升级Angular至12后jest.spyOn().and.returnValue()报错替换方案
.and属性类型报错解决方案 问题场景
基于Nx/NRWL框架将Angular项目从11版本升级至12版本后,单元测试执行时抛出类型错误:Property 'and' does not exist on type 'SpyInstance<{ afterClosed: () => Observable<{ snoozeDate: Moment; snoozeNote: string; }>; }, []>'.
项目内共有30余处测试用例使用.and.returnValue()语法模拟方法返回值,典型写法如下:
jest.spyOn(mockMatDialog, 'open').and.returnValue({ afterClosed: () => of(true)});jest.spyOn(component.randomHelperService, 'myHelper').and.returnValue('12354');
当前已在Jest配置中设置testRunner: 'jest-jasmine2'以兼容其他存量测试语法,需要找到适配该返回值模拟逻辑的最优实现方案。
问题根因
Nx升级到Angular12配套版本后,内置Jest的TypeScript类型定义默认使用Jest原生SpyInstance类型,不再默认挂载Jasmine风格的.and链式调用属性——即便配置了jest-jasmine2保证运行时兼容Jasmine语法,TS静态校验阶段仍然会识别不到and属性,进而抛出类型错误。
可选落地方案
方案1:原生语法替换(推荐,零额外配置成本)
Jest原生提供的mock方法和Jasmine的.and系列方法功能完全一一对应,直接做全局文本替换即可覆盖所有30余处问题点,改动量极小,无后续版本兼容风险。
对应替换规则:
.and.returnValue(value)替换为.mockReturnValue(value).and.callThrough()替换为.mockCallThrough().and.callFake(fn)替换为.mockImplementation(fn).and.returnValues(...values)替换为.mockReturnValue(...values)
替换后的代码示例:
// 模拟MatDialog弹窗open方法返回值 jest.spyOn(mockMatDialog, 'open').mockReturnValue({ afterClosed: () => of(true)}); // 模拟公共服务方法返回值 jest.spyOn(component.randomHelperService, 'myHelper').mockReturnValue('12354');
替换后不需要调整任何Jest配置,运行时行为和原写法完全一致,和当前使用的jest-jasmine2运行器无冲突。
方案2:类型补丁兼容(无需改动现有测试代码)
如果不想修改存量测试代码,可以通过TS接口合并的方式给Jest的SpyInstance类型补充.and属性定义:
- 在测试专用目录(通常与
test-setup.ts同级)新建类型声明文件jest-spy-extend.d.ts,写入以下内容:
declare namespace jest { interface SpyInstance<T = any, Y extends any[] = any> { and: { returnValue: (val: T) => this; callThrough: () => this; callFake: (impl: (...args: Y) => T) => this; returnValues: (...vals: T[]) => this; }; } }
- 确认
tsconfig.spec.json的include配置覆盖了该声明文件路径,重启IDE的TS服务后类型报错即可消除。
注意:该方案属于类型层面临时兼容补丁,不会改动测试运行时逻辑,但后续Jest大版本升级时需要重新校验类型定义的兼容性,长期维护成本高于方案1。
内容的提问来源于stack exchange,提问作者mrshickadance

