升级 jest 28 后的单元测试执行异常问题及解决办法记录

1,256次阅读
没有评论

共计 2423 个字符,预计需要花费 7 分钟才能阅读完成。

提醒:本文最后更新于2025-07-07 14:38,文中所关联的信息可能已发生改变,请知悉!

1. 升级至 jest 28

升级后 package.json 中 jest 相关的主要依赖及版本参考如下:

[code lang=js]
{
"devDependencies": {
"@jest/types": "^28.1.1",
"@types/jest": "^28.1.1",
"jest": "^28.1.1",
"jest-environment-jsdom": "^28.1.1",
"jest-extended": "^2.0.0",
"ts-jest": "^28.0.5",
}
}
[/code]

相比 jest@27 的相关依赖,除了更新版本外,如需 jsdom 执行环境,需单独添加 jest-environment-jsdom 库依赖。

2. jest 28 报错问题及解决参考

2.1 SyntaxError: Unexpected token ‘export’

主要报错信息参考如下:

[code lang=text]
node_modules/uuid/dist/esm-browser/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { default as v1 } from './v1.js';

SyntaxError: Unexpected token 'export'

> 1 | import { v4 } from "uuid";
[/code]

chalk、uuid 这一类适配了最新 esm 方案的库,基本都会报此类错误。主要原因是 jest 使用 jsdom 执行时使用的默认导出为 browser-esm 版本,而 jest 28 默认的 transform 过滤了 node_modules 目录下的内容。

当前的解决方法可有以下几种:

方法一: 在 moduleNameMapper 配置中指定对应包的 commonjs 版本的入口。示例:

[code lang=js]
/** @type {import('@jest/types').Config.InitialOptions } */
module.exports = {
testEnvironment: 'jsdom',
moduleNameMapper: {
'^uuid$': require.resolve('uuid'),
// 或直接指定入口 js 路径
// '^uuid$': '<rootDir>/node_modules/uuid/dist/index.js',
}
}
[/code]

方法二: 修改 jest transform 过滤规则,允许针对这些异常的依赖执行 transform。示例:

[code lang=js]
module.exports = {
testEnvironment: 'jsdom',
transformIgnorePatterns: ['/node_modules/(?!(uuid|xxx)/)'],
}
[/code]

提示:方法二由于使用 browser 方案,uuid 库还会因为当前版本的 jsdom 不支持 crypto.getRandomValues 而报错。

方案三:mock 不重要的依赖库。如果不是重度使用、对测试逻辑无影响的依赖,可以直接 mock 它。如针对 uuid 的 mock:

[code lang=js]
jest.mock('uuid', () => ({
v1: () => '110ec58a-a0f2-4ac4-8393-c866d813b8d1',
v4: () => '110ec58a-a0f2-4ac4-8393-c866d813b8d1',
v5: () => '110ec58a-a0f2-4ac4-8393-c866d813b8d1',
});
[/code]

2.2 setTimeout: Matcher error: received value must be a mock or spy function

许多涉及 setTimeout 调用的用例都报错如下:

[code lang=text]
Received has value: [Function setTimeout]

expect(received).toHaveBeenCalledTimes(expected)

Matcher error: received value must be a mock or spy function
Received has type: function
Received has value: [Function setTimeout]
111 | jest.runAllTimers();
112 | // 定时器执行的次数
&gt; 113 | expect(setTimeout).toHaveBeenCalledTimes(1);

[/code]

查看测试代码发现存在 ts 类型异常。原写法为:

[code lang=ts]
jest.useFakeTimers('legacy');
[/code]

修正入参为如下即可:

[code lang=js]
jest.useFakeTimers({ legacyFakeTimers: true });
[/code]

3 相关参考

  • https://jestjs.io/zh-Hans/docs/upgrading-to-jest28
  • https://jestjs.io/zh-Hans/docs/webpack
  • https://jestjs.io/docs/ecmascript-modules
  • https://hub.fastgit.xyz/facebook/jest/issues/12770
  • https://hub.fastgit.xyz/jsdom/jsdom/pull/3352

正文完
 0
任侠
版权声明:本站原创文章,由 任侠 于2022-06-17发表,共计2423字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码