共计 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 | // 定时器执行的次数 | |
> 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