测试React+Redux的Header组件时找不到react-redux上下文报错如何解决
问题原因
你的Header组件使用了react-redux的useSelector Hook,该Hook依赖Redux上下文环境,测试时直接渲染Header没有在外层包裹Redux的Provider组件,因此触发上下文找不到的报错。
解决方案
方案1:直接修改当前测试用例
步骤1:安装测试依赖(未安装时执行)
npm install redux-mock-store --save-dev
步骤2:修改Header.test.js代码
import { render, screen } from "@testing-library/react"; import { Provider } from "react-redux"; import configureMockStore from "redux-mock-store"; import Header from "../Header"; // 初始化mock store const mockStore = configureMockStore([]); const mockedSetOpenForm = jest.fn(); test("should render number of invoices", () => { // 构造测试需要的state,这里设置invoices长度为5匹配你测试的文本 const store = mockStore({ invoices: new Array(5).fill({}) }); // 渲染时用Provider包裹Header,传入模拟的store render( <Provider store={store}> <Header openForm={false} setOpenForm={mockedSetOpenForm} /> </Provider> ); const paragraphElement = screen.getByText(/There are 5 total invoices./i); expect(paragraphElement).toBeInTheDocument(); });
如果你的项目用的是Redux Toolkit,也可以直接用configureStore生成测试用的真实store:
import { configureStore } from "@reduxjs/toolkit"; import invoiceReducer from "你的reducer实际存储路径"; const store = configureStore({ reducer: { invoices: invoiceReducer }, preloadedState: { invoices: new Array(5).fill({}) } })
方案2:封装通用测试渲染工具(推荐)
如果项目里很多组件都用到Redux,可以封装一个自定义的render函数,避免每次测试都手动包Provider:
- 在测试目录新建
test-utils.js:
import { render } from '@testing-library/react' import { Provider } from 'react-redux' import configureMockStore from 'redux-mock-store' const mockStore = configureMockStore([]) const customRender = (ui, { preloadedState = {}, ...renderOptions } = {}) => { const store = mockStore(preloadedState) const Wrapper = ({ children }) => <Provider store={store}>{children}</Provider> return render(ui, { wrapper: Wrapper, ...renderOptions }) } // 重新导出testing-library的所有方法,替换原来的render export * from '@testing-library/react' export { customRender as render }
- 之后测试Redux组件时直接引入这个自定义的render,传入需要的预加载state即可:
import { render, screen } from './test-utils' import Header from "../Header"; const mockedSetOpenForm = jest.fn(); test("should render number of invoices", () => { render(<Header openForm={false} setOpenForm={mockedSetOpenForm} />, { preloadedState: { invoices: new Array(5).fill({}) } }); const paragraphElement = screen.getByText(/There are 5 total invoices./i); expect(paragraphElement).toBeInTheDocument(); });
额外注意点
Header组件中读取了localStorage的profile字段,如果后续测试涉及点击按钮等交互逻辑,需要提前模拟localStorage的值:
beforeEach(() => { Storage.prototype.getItem = jest.fn(() => JSON.stringify({ result: { name: '测试用户' } })) })
内容的提问来源于stack exchange,提问作者r121
相关产品推荐
相关产品推荐

