使用 PNPM 的情况下,Jest 解决 ESM 依赖库的报错问题

环境

  • NX
  • PNPM
  • lodash-es
  • Jest

从 karma 转移到 Jest 遇到了如下报错

主要原因是 "node_modules" 文件夹中 ESM(ECMAScript Modules) 库不被 Jest 支持。

鉴于 Jest ESM 支持还在几乎不可用的试验阶段,而目前我主要是在公司项目上迁移到 Jest。所以本文主要采用 transformIgnorePatternsmoduleNameMapper 两种配置来解决这个问题。

shell 复制代码
Test suite failed to run

Jest encountered an unexpected token

Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

By default "node_modules" folder is ignored by transformers.

Here's what you can do:
    • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
    • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
    • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
    • If you need a custom transformation specify a "transform" option in your config.
    • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation

以下配置主要以 lodash-es 作为参考。

transformIgnorePatterns

官方文档的解释是:正则表达式模式字符串的数组,在转换之前与所有源文件路径匹配。如果文件路径与任何模式匹配,则不会对其进行转换。 即 transformIgnorePatterns 用于指定在进行代码转换时应该忽略的文件或文件夹。

而在 NX 默认的 Jest 配置中,配置为 node_modules/(?!.*\\.mjs$)。 这个正则表达式的含义是,匹配以 node_modules/ 开头的文件夹路径,但排除那些以 .mjs 为扩展名的文件夹路径。?! 是一个否定预查,表示不匹配这样的文件夹路径。

javascript 复制代码
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],

以上配置意思就是将会把以 .mjs 为扩展名的文件从 ESM 转换为 CommonJS,以支持 Jest。

添加转换 lodash-es

顺便支持一下 PNPM

javascript 复制代码
const esModules = ['.*\\.mjs$', 'lodash-es'].join('|');

export default {
    ...
    transformIgnorePatterns: [`node_modules/(?!.pnpm|${esModules})`],
    ...
}

转换后 failed 数量从 15 减少到 11,但是这么做会有一个转换的过程会有额外的支出,需要 51s。不过第一次转换完后貌似就会缓存然后就不用转换了。

支出更少的方法 moduleNameMapper

这种方法需要库本身有对应的 CommonJS,就不需要转换了。可以跑到 12s

javascript 复制代码
export default {
    ...
    moduleNameMapper: {
        '^lodash-es$': 'lodash',
    },
  ...
}

最终配置参考如下

javascript 复制代码
/* eslint-disable */
const esModules = ['.*\\.mjs$'].join('|');

export default {
  displayName: 'pc',
  preset: '../../jest.preset.js',
  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
  coverageDirectory: '../../coverage/apps/pc',
  moduleNameMapper: {
    '^lodash-es$': 'lodash',
  },
  transform: {
    '^.+\\.(ts|mjs|js|html)$': [
      'jest-preset-angular',
      {
        tsconfig: '<rootDir>/tsconfig.spec.json',
        stringifyContentPathRegex: '\\.(html|svg)$',
      },
    ],
  },
  transformIgnorePatterns: [`node_modules/(?!.pnpm|${esModules})`],
  snapshotSerializers: [
    'jest-preset-angular/build/serializers/no-ng-attributes',
    'jest-preset-angular/build/serializers/ng-snapshot',
    'jest-preset-angular/build/serializers/html-comment',
  ],
};

参考

  1. Jest setup "SyntaxError: Unexpected token export"
  2. Configuring Jest · Jest
  3. ECMAScript Modules · Jest
  4. Configuring Jest · Jest
相关推荐
蜗牛快跑2134 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy5 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss
龙猫蓝图2 小时前
vue el-date-picker 日期选择器禁用失效问题
前端·javascript·vue.js