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.
Since Jest's ESM support is still in an experimental stage and I am mainly migrating to Jest in my company's projects, this article mainly uses the transformIgnorePatterns
and moduleNameMapper
configurations to solve this problem.
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 official documentation explains that it is an array of regular expression pattern strings that match all source file paths before transformation. If a file path matches any pattern, it will not be transformed.
In other words, transformIgnorePatterns
is used to specify files or folders that should be ignored during code transformation.
In the default Jest configuration of NX, it is configured as node_modules/(?!.*\\.mjs$)
.
This regular expression means that it matches folder paths starting with node_modules/
, but excludes 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, taking 51s. However, it seems that the transformation is cached after the first transformation and no further transformation is needed.
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',
},
...
}
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',
],
};