你写测试吗? jest.spyOn 做完的时候不就是这样写的吗?
import * as f from './functions'
jest.spyOn(f, "x").mockImplementation(() => 'x')
test('should be x', () => expect(f.x()).toBe('x'))
写js的时候,经常会创建一个函数的模块,而不是类基,写mock()比较麻烦,所以偷工减料,这样写,但是对于esm→cjs文件的玩笑,依赖于测试和组合转译器,就会出现标题错误。
TL;博士
- 如果你使用 babel-jest、tsc-jest,你应该没问题。如果 babel/tsc 发出符合 esm 的 cjs,应该会发生错误。
- 使用 swc-jest、esbuild-jest 时出错。
- 对于 swc-jest,使用 jest_workaround 插件(使导出的内容可配置的插件)。
- 使用另一个测试框架(vitest 很好)。
- 乖乖使用mock()。
背景
当nextjs产品从babel中移除迁移到swc,jest测试也改为swc-jest
TypeError:无法重新定义属性
我遇到了一个错误并尝试了各种方法。
是什么原因
只看 jest 的实现和每个转译器的结果。
你在 esm 中写的
export const a = () => {}当转换为 cjs
babel/tsc(大致相同)
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.a = void 0; const a = () => { }; exports.a = a;swc/esbuild(大致相同)
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "a", { enumerable: true, get: function() { return a; } }); var a = function() {};笑话实现
let descriptor = Object.getOwnPropertyDescriptor(object, methodKey); ... if (descriptor && descriptor.get) { const originalGet = descriptor.get; mock = this._makeComponent({type: 'function'}, () => { descriptor!.get = originalGet; Object.defineProperty(object, methodKey, descriptor!); }); descriptor.get = () => mock; Object.defineProperty(object, methodKey, descriptor); } else { mock = this._makeComponent({type: 'function'}, () => { if (isMethodOwner) { object[methodKey] = original; } else { delete object[methodKey]; } }); // @ts-expect-error overriding original method with a Mock object[methodKey] = mock; }就是带有descriptor.get的那个,也就是swc/esbuild做成cjs的那个。转译器的结果是符合 esm 的,并且可配置为默认值 false,因此在第 7 行会出现无法重新定义属性错误。
另一方面,babel/tsc 没有定义 Object.defineProperty 并按原样导出,所以没有错误,因为 jest 实现的 else 端没有 Object.defineProperty。
然后怎么办
在 swc/esbuild 中有很多这样的问题,因为更改编译器会导致错误。不过双方的说法是,esm本来就是不可变的,所以babel/tsc就奇怪了,他们也不知道。在下面的评论中,一个 swc 提交者创建了一个使 esm 可变的插件,但它已被弃用。
乖乖地用mock来写,好像也不错。或者另外一个测试框架,部分团队使用vitest,转译器是esbuild,但是这似乎不会导致这个错误,因为spyOn实现不同。
甚至 vitest 的 spyOn 实现也与 jest 不同,所以有一种现象是它在 jest 中有效,而在 vitest 中无效,但我将把这个留到另一篇文章中。
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308628299.html