使用useContext解构导致Jest单元测试失败
解决Jest单元测试中useContext导入函数导致的失败问题
问题现象
使用Jest进行单元测试时,通过useContext导入的loginUser函数导致测试失败,报错信息如下:
TypeError: Cannot destructure property 'loginUser' of '(0 , _react.useContext)(...)' as it is undefined.
测试代码
test('Login page renders with no errors', () => { render(<Router><Login/></Router>) });
Jest配置
module.exports = { preset: "ts-jest/presets/js-with-ts", transform: { '^.+\\.(js|jsx|ts|tsx)$': '<rootDir>/node_modules/react-scripts/config/jest/babelTransform.js', '^.+\\.css$': '<rootDir>/node_modules/react-scripts/config/jest/cssTransform.js', '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '<rootDir>/node_modules/react-scripts/config/jest/fileTransform.js', "^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest-amcharts", "\\.[jt]sx?$": "babel-jest", "^.+\\.css$": "jest-transform-css", "node_modules/variables/.+\\.(j|t)sx?$": "ts-jest", }, transformIgnorePatterns: [ // '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$', '^.+\\.module\\.(css|sass|scss)$', "[/\\\\]node_modules[/\\\\](?!(@amcharts)\\/).+\\.(js|jsx|ts|tsx)$", "/node_modules/(?!react-file-drop)", "node_modules/(?!variables/.*)" ], moduleNameMapper: { '^react-native$': 'react-native-web', '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy', "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/mocks/fileMock.js", "\\.(css|less)$": "<rootDir>/mocks/fileMock.js", "^.+\\.(css|less|scss)$": "babel-jest", }, moduleDirectories: ["node_modules", "src"], }
loginUser实现代码
const loginUser = async (tokens) => { let response = await axios.post('http://127.0.0.1:8000/api/token/',tokens) try { setAuthTokens(authTokens => ({ ...response.data })) const decoded = jwt_decode(response.data.access) setUser(user => ({ ...decoded })) localStorage.setItem('authTokens',JSON.stringify(response.data)) history.push('/') } catch(err) { alert(response.data.user); } }
解决方案
核心原因
测试时Login组件依赖的Context没有被提供,useContext返回undefined,导致解构loginUser失败。
具体解决步骤
- 在测试中手动提供Context Provider
假设你的Context是AuthContext,修改测试代码,模拟Context中的loginUser函数:import { render } from '@testing-library/react'; import { AuthContext } from './path-to-your-auth-context'; import { Router } from 'react-router-dom'; import Login from './Login'; test('Login page renders with no errors', () => { // 模拟loginUser函数 const mockLoginUser = jest.fn(); render( <AuthContext.Provider value={{ loginUser: mockLoginUser }}> <Router> <Login /> </Router> </AuthContext.Provider> ); }); - 处理多Context依赖
如果组件依赖多个Context,需要嵌套所有必要的Provider,确保每个Context都有模拟值。 - 验证配置合理性
当前jest.config无直接影响Context解析的问题,可检查moduleDirectories是否包含Context所在目录,确保测试能正确导入Context文件。
额外优化建议
- 将Context模拟封装成工具函数,减少重复代码;
- 对
loginUser中的异步操作和副作用做mock处理:- 用
jest.mock('axios')模拟接口请求; - 用
jest.spyOn(localStorage, 'setItem')监听localStorage操作; - 用
MemoryRouter替代Router,更方便测试路由跳转逻辑。
- 用
内容的提问来源于stack exchange,提问作者Emm
相关产品推荐
相关产品推荐

