让 Jest 支持测试 ESM 业务代码

3,832 阅读1分钟

Jest 运行 TypeScript 单测并增加覆盖率后续篇

如果是 node_modules 单测报错 Cannot use import statement outside a module,请参考 Jest 单测支持 node_modules ESM 完全解决方案

Cannot use import statement outside a module

jest 本身支持 ESM,即单测可以如此写

// src/lib/lite-lodash.js

export isPromise(...) { ... }
// test/lib/lite-lodash.test.js

import { isPromise } from '../../src/lib/lite-lodash'

describe(...)

但是当 lite-lodash.js 出现 import xx from yy 则会报错。其实是不识别被测试文件内的 import,需要 babel 援手。

Cannot use import statement outside a module

解法

  1. 安装 babel-jest
  2. touch babel.config.js 注意不是 .babelrc
// babel.config.js 注意不是 `.babelrc`。
// only used by jest 不应该影响业务代码构建!
module.exports = { presets: ['@babel/preset-env'] };
  1. jest.config.js
module.exports = {
  transform: {
    "^.+\\.(js|jsx)$": "babel-jest",
  }
};
  1. DONE 🎉

alias

配置文件别名 alis 可以解决 import 需要脑力计算路径问题,在 webpack 或 TS 中我们常用的开发体验优化措施,比如

// jsconfig.json

{
  "compilerOptions": {
    "checkJs": true,
    "target": "es2015",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "exclude": ["dist", "node_modules", "**/node_modules/*"]
}

但是麻烦来了如果你测试的文件含有

import '@/common/lib/xxx'

则 jest 会抱怨找不到文件

Cannot find module '@/common/tools/format' from 'test/common/tools/url.test.js'

解法

jest.config.js

+ 'moduleNameMapper': {
+   '^@/(.*)': '<rootDir>/src/$1',
+ },

Cannot read property 'cwd' of undefined

运行 jest 报错:

Test suite failed to run

TypeError: Cannot read property 'cwd' of undefined

at Object.process (node_modules/babel-jest/build/index.js:325:33)

解法

     "babel-jest": "^27.0.6",
-    "jest": "^26.6.3",
+    "jest": "^27.0.6",

总结

Jest 默认支持 ESM 固然很好,但是支持不全面官方也说了,故需要 babel 援助。mocha 支持 ESM 只需以下修改,更方便。

安装 esm,然后修改 test:

"scripts": {
+  "test": "node -r esm ./node_modules/.bin/mocha"

参考

How to resolve “Cannot use import statement outside a module” in jest