You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js+Redux Toolkit的Jest测试中获取Store并渲染组件?

问题

在Next.js项目中用Jest做组件集成测试时,必须用Redux的Provider包裹组件才能让组件访问Store,但项目依赖next-redux-wrapper同步客户端与服务端Store,_app.tsx里通过wrapper.useWrappedStore全局提供Store,不清楚如何在测试文件中获取Store并正确渲染组件。

相关代码片段:

测试文件(tests/Calculator.test.tsx)

import { Calculator } from "@/components";
import { cleanup, render } from "@testing-library/react";
import { Provider } from "react-redux";

afterEach(cleanup);

it("Check Calculator", () => {
  const CalculatorTest: React.FunctionComponent = () => {
    return (
      <Provider store={}>
        <Calculator></Calculator>
      </Provider>
    );
  };
  const { queryAllByTestId } = render(<CalculatorTest />);
  expect(queryAllByTestId("calc-test")).toBeTruthy();
}); 

_app.tsx

const MyApp: FC<AppProps> = ({ Component, ...rest }) => {
  const { store, props } = wrapper.useWrappedStore(rest);
  return (
    <Provider store={store}>
      <Head>
        <title>Calculator</title>
      </Head>
      <Component {...props.pageProps} />
    </Provider>
  );
};

export default MyApp;

redux/store.ts

const makeStore = () =>
  configureStore({
    reducer: {
      history: calculatorHistoryReducer,
    },

    devTools: true,
  });

const store = makeStore();

export type RootStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<RootStore["getState"]>;
export type AppDispatch = typeof store.dispatch;
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>;
export const useAppDispatch: () => typeof store.dispatch = useDispatch;

export const wrapper = createWrapper<RootStore>(makeStore);
解决方案

方法1:直接生成测试用Store

利用已定义的makeStore工厂函数,直接创建测试专用Store,再用Provider包裹组件:

import { Calculator } from "@/components";
import { cleanup, render } from "@testing-library/react";
import { Provider } from "react-redux";
import { makeStore } from "@/redux/store";

afterEach(cleanup);

it("Check Calculator", () => {
  // 创建全新的测试用Store
  const testStore = makeStore();
  
  const { queryAllByTestId } = render(
    <Provider store={testStore}>
      <Calculator />
    </Provider>
  );
  
  expect(queryAllByTestId("calc-test")).toBeTruthy();
}); 

方法2:借助next-redux-wrapper的wrapper获取Store

通过wrapper对象创建Store,还能模拟服务端预加载数据的逻辑:

import { Calculator } from "@/components";
import { cleanup, render } from "@testing-library/react";
import { Provider } from "react-redux";
import { wrapper } from "@/redux/store";
import { fetchHistory } from "@/redux/actions"; // 导入需要的action

afterEach(cleanup);

it("Check Calculator", async () => {
  // 通过wrapper生成Store
  const testStore = wrapper.createStore();
  
  // 模拟getServerSideProps中的数据预加载
  await testStore.dispatch(fetchHistory());
  
  const { queryAllByTestId } = render(
    <Provider store={testStore}>
      <Calculator />
    </Provider>
  );
  
  expect(queryAllByTestId("calc-test")).toBeTruthy();
}); 

方法3:封装自定义render工具函数

为了避免重复编写Provider包裹逻辑,封装一个带Store的render工具:
创建test-utils.tsx:

import { render, RenderOptions } from "@testing-library/react";
import { Provider } from "react-redux";
import { makeStore, RootStore } from "@/redux/store";

const customRender = (
  ui: React.ReactElement,
  { store = makeStore(), ...renderOptions }: RenderOptions & { store?: RootStore } = {}
) => {
  const Wrapper = ({ children }: { children: React.ReactNode }) => (
    <Provider store={store}>{children}</Provider>
  );
  
  return render(ui, { wrapper: Wrapper, ...renderOptions });
};

export * from "@testing-library/react";
export { customRender as render };

在测试文件中使用这个工具:

import { Calculator } from "@/components";
import { cleanup, render } from "@/test-utils";
import { makeStore } from "@/redux/store";
import { fetchHistory } from "@/redux/actions";

afterEach(cleanup);

it("Check Calculator", async () => {
  // 可选:创建带初始数据的Store
  const testStore = makeStore();
  await testStore.dispatch(fetchHistory());
  
  const { queryAllByTestId } = render(<Calculator />, { store: testStore });
  
  expect(queryAllByTestId("calc-test")).toBeTruthy();
}); 

关键说明

  • makeStore每次调用都会生成全新Store,保证测试之间的状态隔离。
  • 如果组件依赖服务端预加载的数据,需要在测试中手动dispatch对应的action初始化Store状态。
  • 自定义render工具能统一处理Store包裹逻辑,减少重复代码。

内容的提问来源于stack exchange,提问作者tresor13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 14:40:24