Nexmoe

Nexmoe

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

When using PNPM, Jest resolves the error of ESM dependency libraries.

Environment#

  • NX
  • PNPM
  • lodash-es
  • Jest

Encountered the following error when migrating from karma to Jest#

The main reason is that ESM (ECMAScript Modules) libraries in the "node_modules" folder are not supported by Jest.

Considering that Jest's ESM support is still in an almost unusable experimental stage, and currently I am mainly migrating to Jest in the company's project. So this article mainly uses transformIgnorePatterns and moduleNameMapper configurations to solve this problem.

11c629a593c4c8484b6cb8ca44d6aa5f.png

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

The following configuration mainly uses lodash-es as a reference.

transformIgnorePatterns#

The explanation in the official documentation is: an array of regular expression pattern strings that are matched against all source file paths before transformation. If a file path matches any pattern, it will not be transformed.
That is, transformIgnorePatterns is used to specify the files or folders that should be ignored during code transformation.

In the default Jest configuration of NX, it is configured as node_modules/(?!.*\\.mjs$).
The meaning of this regular expression is to match folder paths starting with node_modules/, but exclude those folder paths with .mjs as the extension. ?! is a negative lookahead, indicating that it does not match such folder paths.

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

The above configuration means that files with the extension .mjs will be transformed from ESM to CommonJS to support Jest.

Adding transformation for lodash-es#

Also, support PNPM

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

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

After the transformation, the number of failed tests decreased from 15 to 11, but this approach incurs additional overhead during the transformation process, taking 51s. However, it seems that the transformation is cached after the first transformation and no further transformation is needed.

ef4e6aeef369b021b707664f9c03549a.png

A method with less overhead: moduleNameMapper#

This method requires the library itself to have a corresponding CommonJS version, so no transformation is needed. It can be done in 12s.

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

e87d8ad99b64c8f836a8c1777ec217bf.png

Final configuration reference#

/* 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',
  ],
};

References#

  1. Jest setup "SyntaxError: Unexpected token export"
  2. Configuring Jest · Jest
  3. ECMAScript Modules · Jest
  4. Configuring Jest · Jest
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.