Nexmoe

Nexmoe

一个开发者。关于勇敢与热爱,互联网/创造/赛博朋克
twitter
github

使用 PNPM 的情況下,Jest 解決 ESM 依賴庫的報錯問題

環境#

  • NX
  • PNPM
  • lodash-es
  • Jest

從 karma 轉移到 Jest 遇到了如下報錯#

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

鑑於 Jest ESM 支持還在幾乎不可用的試驗階段,而目前我主要是在公司項目上遷移到 Jest。所以本文主要採用 transformIgnorePatternsmoduleNameMapper 兩種配置來解決這個問題。

11c629a593c4c8484b6cb8ca44d6aa5f.png

測試套件運行失敗

Jest 遇到了意外的標記

Jest 無法解析一個文件。這種情況發生在例如當你的代碼或其依賴使用非標準的 JavaScript 語法,或者當 Jest 沒有配置以支持這種語法時。

開箱即用的 Jest 支持 Babel,這將用於根據你的 Babel 配置將你的文件轉換為有效的 JS。

默認情況下 "node_modules" 文件夾被轉換器忽略。

你可以做以下幾點:
 如果你嘗試使用 ECMAScript Modules,請參見 https://jestjs.io/docs/ecmascript-modules 以了解如何啟用它。
 如果你嘗試使用 TypeScript,請參見 https://jestjs.io/docs/getting-started#using-typescript
 要對某些 "node_modules" 文件進行轉換,你可以在配置中指定自定義的 "transformIgnorePatterns"。
 如果你需要自定義轉換,請在配置中指定 "transform" 選項。
 如果你只是想模擬你的非 JS 模塊(例如二進制資產),你可以使用 "moduleNameMapper" 配置選項將它們存根。

你可以在文檔中找到這些配置選項的更多詳細信息和示例:
https://jestjs.io/docs/configuration
有關自定義轉換的信息,請參見:
https://jestjs.io/docs/code-transformation

以下配置主要以 lodash-es 作為參考。

transformIgnorePatterns#

官方文檔的解釋是:正則表達式模式字符串的數組,在轉換之前與所有源文件路徑匹配。如果文件路徑與任何模式匹配,則不會對其進行轉換。
transformIgnorePatterns 用於指定在進行代碼轉換時應該忽略的文件或文件夾。

而在 NX 默認的 Jest 配置中,配置為 node_modules/(?!.*\\.mjs$)
這個正則表達式的含義是,匹配以 node_modules/ 開頭的文件夾路徑,但排除那些以 .mjs 為擴展名的文件夾路徑。?! 是一個否定預查,表示不匹配這樣的文件夾路徑。

transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],

以上配置意思就是將會把以 .mjs 為擴展名的文件從 ESM 轉換為 CommonJS,以支持 Jest。

添加轉換 lodash-es#

順便支持一下 PNPM

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

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

轉換後 failed 數量從 15 減少到 11,但是這麼做會有一個轉換的過程會有額外的支出,需要 51s。不過第一次轉換完後貌似就會緩存然後就不用轉換了。

ef4e6aeef369b021b707664f9c03549a.png

支出更少的方法 moduleNameMapper#

這種方法需要庫本身有對應的 CommonJS,就不需要轉換了。可以跑到 12s

export default {
    ...
    moduleNameMapper: {
        '^lodash-es$': 'lodash',
    },
  ...
}

e87d8ad99b64c8f836a8c1777ec217bf.png

最終配置參考如下#

/* 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
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。