如何使用Jest Mock ES模块默认导出对象的指定属性
问题原因
你的两个方案分别存在以下问题:
jest.mock不能放在it用例内部:jest会自动将所有jest.mock调用提升到测试文件最顶部执行,写在用例内部的mock规则不会生效;同时你写的mock返回值既没有标记__esModule: true让jest识别这是ES模块导出,也没有保留原模块的具名导出内容,导致默认导出识别异常。jest.spyOn加了不必要的'get'参数:你的模块默认导出是普通静态值,不是访问器属性,指定get访问类型会抛出匹配不到属性的错误;同时如果模块已经被业务代码提前导入缓存,直接修改默认导出对象的属性会比全量mock更简单。
可行方案
方案1:直接修改属性(最简单,推荐)
因为默认导出是引用类型的对象,直接修改其内部属性即可,所有导入该对象的文件都会自动读取到最新值:
import test from '../test' import {toTestModuleFunc} from '../toTestModule' describe('test', () => { // 保存原始值,每个用例执行后恢复,避免影响其他用例 let originalTestVal; beforeEach(() => { originalTestVal = test.blabla.test; }); afterEach(() => { test.blabla.test = originalTestVal; }); it('test modify property', async () => { const newValue = 'newValue'; test.blabla.test = newValue; const value = await toTestModuleFunc(); expect(value).toEqual(newValue); }); });
方案2:全局jest.mock(适合所有用例都要mock该值的场景)
jest.mock要写在测试文件所有import语句之前:
// 写在测试文件最顶部,所有导入语句之前 jest.mock('../test', () => ({ __esModule: true, // 标记为ES模块,默认导出规则才会生效 ...jest.requireActual('../test'), // 保留原模块不需要mock的其他导出内容 default: { blabla: { test: 'newValue' } } })); import * as test from '../test' import {toTestModuleFunc} from '../toTestModule' describe('test', () => { it('with jest.mock', async () => { const value = await toTestModuleFunc(); expect(value).toEqual('newValue'); }); });
方案3:jest.spyOn动态mock(适合不同用例需要设置不同mock值的场景)
import * as test from '../test' import {toTestModuleFunc} from '../toTestModule' describe('test', () => { afterEach(() => { jest.restoreAllMocks(); // 每个用例执行后恢复原始导出值 }); it('with jest.spyOn', async () => { const newValue = 'newValue'; // 不需要加get参数,直接mock default导出的返回值 jest.spyOn(test, 'default').mockReturnValue({ blabla: { test: newValue } }); const value = await toTestModuleFunc(); expect(value).toEqual(newValue); }); });
内容的提问来源于stack exchange,提问作者Jair
相关产品推荐
相关产品推荐

