使用Jest/Enzyme测试React useContext组件时如何给state赋值并解决报错
报错原因
直接渲染Timer组件时,组件外层没有提供GameContext的上下文实例,useContext(GameContext)返回值为undefined,尝试解构timer属性就会触发该报错。
解决方案
你可以通过以下两种方式给组件注入需要的context状态:
方案1:使用GameContext.Provider包裹待测组件
该方案更贴近组件实际运行场景,无需修改组件依赖,测试代码示例如下:
import { shallow } from 'enzyme'; import React from 'react'; import Timer from './timer'; import { GameContext } from './global/contexts'; // 自定义模拟的context值,包含timer和mock的setTimer方法 const mockContext = { timer: 2000, setTimer: jest.fn() }; test('Timer组件正常渲染计时数值', () => { const wrapper = shallow( <GameContext.Provider value={mockContext}> <Timer /> </GameContext.Provider> ); // 调用dive()获取Timer组件本身的渲染内容(shallow默认只渲染第一层Provider) const timerDom = wrapper.dive().find('[data-testid="timer"]'); // 2000 / 100 = 20,所以显示Timer : 20 expect(timerDom.text()).toBe('Timer : 20'); });
方案2:直接mockuseContext返回值
该方案无需包裹Provider,适合单组件独立测试场景,代码示例如下:
import { shallow } from 'enzyme'; import React from 'react'; import Timer from './timer'; const mockSetTimer = jest.fn(); // 全局mock React的useContext方法,返回自定义的状态 jest.spyOn(React, 'useContext').mockReturnValue({ timer: 3000, setTimer: mockSetTimer }); test('Timer组件倒计时逻辑正常', () => { // 启用假定时器,不需要等待真实计时 jest.useFakeTimers(); const wrapper = shallow(<Timer />); // 快进1000ms,对应100次10ms的定时器触发 jest.advanceTimersByTime(1000); // 验证setTimer被调用了100次 expect(mockSetTimer).toHaveBeenCalledTimes(100); // 测试结束后恢复真实定时器 jest.useRealTimers(); }); // 每次测试结束后清除mock,避免影响其他用例 afterEach(() => { jest.clearAllMocks(); });
内容的提问来源于stack exchange,提问作者Pedram
相关产品推荐
相关产品推荐

