如何在组件外调用mock createStore?Zustand测试场景答疑
问题描述
我已经按照文档配置了Vite mock文件,但在测试场景中无法正确使用。具体场景如下:
带中间件的Zustand Store
export const useStore = create<Store>()( devtools( subscribeWithSelector((set) => ({ currentPage: 1, error: null, isLoading: false, photos: [], searchTerm: '', setIsLoading: (isLoading) => set({ isLoading }), setPhotos: (photos) => set({ photos }), setSearchTerm: (searchTerm) => set({ searchTerm }), setError: (error) => set({ error }), })) ) );
当前测试代码(使用真实Store)
test('renders when loading', () => { useStore.setState({ isLoading: true }); // 想用mock store替代此处 const component = render(<ImageGrid />); expect(component.asFragment()).toMatchInlineSnapshot(`...`); }); // 状态未重置会污染后续测试
当前核心问题:上述方式无法使用mock中定义的storeResetFns,如何用create函数创建mock store以在测试中轻松设置状态?
解决方案
1. 抽离Store创建逻辑,实现可替换
先把Store的核心创建逻辑单独封装,避免直接导出固定实例:
// store.ts export const createStore = () => create<Store>()( devtools( subscribeWithSelector((set) => ({ currentPage: 1, error: null, isLoading: false, photos: [], searchTerm: '', setIsLoading: (isLoading) => set({ isLoading }), setPhotos: (photos) => set({ photos }), setSearchTerm: (searchTerm) => set({ searchTerm }), setError: (error) => set({ error }), })) ) ); // 默认导出供业务代码使用 export const useStore = createStore();
2. 测试中创建独立Mock Store实例
每次测试前生成全新的Store实例,彻底避免状态污染,同时通过Provider让组件使用mock实例:
// ImageGrid.test.tsx import { createStore } from './store'; import { render } from '@testing-library/react'; import ImageGrid from './ImageGrid'; let mockStore: ReturnType<typeof createStore>; beforeEach(() => { // 每次测试初始化新的store mockStore = createStore(); // 可在这里设置默认初始状态 mockStore.setState({ isLoading: false, photos: [] }); }); test('renders when loading', () => { // 设置当前测试所需的状态 mockStore.setState({ isLoading: true }); // 用mock store的Provider包裹组件 render( <mockStore.Provider> <ImageGrid /> </mockStore.Provider> ); expect(component.asFragment()).toMatchInlineSnapshot(`...`); });
3. 集成storeResetFns实现一键重置
如果需要使用Zustand的storeResetFns,可以在创建Store时内置重置逻辑并注册:
// store.ts import { storeResetFns } from 'zustand/middleware'; export const createStore = () => { const store = create<Store>()( devtools( subscribeWithSelector((set) => ({ currentPage: 1, error: null, isLoading: false, photos: [], searchTerm: '', setIsLoading: (isLoading) => set({ isLoading }), setPhotos: (photos) => set({ photos }), setSearchTerm: (searchTerm) => set({ searchTerm }), setError: (error) => set({ error }), // 自定义重置方法 reset: () => set({ currentPage: 1, error: null, isLoading: false, photos: [], searchTerm: '', }), })) ) ); // 将重置方法注册到storeResetFns storeResetFns.add(() => store.getState().reset()); return store; };
在测试中可以直接调用重置:
beforeEach(() => { mockStore = createStore(); // 一键重置到初始状态 mockStore.getState().reset(); });
4. 封装辅助函数简化测试流程
可以写一个通用渲染函数,自动注入mock store并支持初始状态配置:
const renderWithMockStore = (ui: React.ReactElement, initialState?: Partial<Store>) => { const store = createStore(); if (initialState) { store.setState(initialState); } return { ...render(<store.Provider>{ui}</store.Provider>), store, }; }; // 使用示例 test('renders when loading', () => { const { container } = renderWithMockStore(<ImageGrid />, { isLoading: true }); expect(container).toMatchInlineSnapshot(`...`); });
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

