nx: How to set transformIgnorePatterns to fix "Jest encountered an unexpected token"

First of all, thanks for bringing Jest to Angular!

I previously had configured Jest in my Angular project by myself. In order to use lodash-es, I had to set transformIgnorePatterns to inlude the path to lodash-es:

  "jest": {
    "preset": "jest-preset-angular",
...
    "transformIgnorePatterns": [
      "<rootDir>/node_modules/(?!lodash-es/.*)"
    ],

Now, after migrating to the Jest config provided by Nx, I don’t know where I can set this option. My tests currently fail with this error:

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • 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/en/configuration.html

    Details:

    C:\Users\Marvin\Projekte\hypershop-ng\node_modules\lodash-es\lodash.js:10
    export { default as add } from './add.js';
    ^^^^^^

    SyntaxError: Unexpected token export

      1 | import { ComponentFixture } from "@angular/core/testing";
    > 2 | import { isUndefined } from "lodash-es";
        | ^
      3 |
      4 | export function expectElementFromFixture<T>(fixture: ComponentFixture<T>, domQuery?: string): jasmine.Matchers<{} | null> {
      5 |     return expect(elementFromFixture(fixture, domQuery));

      at ScriptTransformer._transformAndBuildScript (../../node_modules/jest-runtime/build/script_transformer.js:403:17)
      at Object.<anonymous> (../../libs/common/src/test/expect.ts:2:1)
      at Object.<anonymous> (../../libs/common/src/test/index.ts:1:1)

Thanks for your help

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 42
  • Comments: 31 (10 by maintainers)

Most upvoted comments

I had to remove the <rootDir> from ours:

const esModules = ['@agm', 'ngx-bootstrap'].join('|');
// ...
module.exports = {
  //...
    transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
  // ...
};

One other option is to pull in babel-jest and tell it to transpile those js files.

From the jest-preset-angular docs:

Transpile js files through babel-jest

Some vendors publish their sources without transpiling. You need to say jest to transpile such files manually since typescript (and thus ts-jest used by this preset) do not transpile them.

  1. Install babel-preset-env and add .babelrc (or modify existing if needed) with that contents:
{
  "presets": ["env"]
}
  1. Update Jest configuration (by default TypeScript process untranspiled JS files which is source of the problem):
{
  "jest": {
    "transform": {
      "^.+\\.(ts|html)$": "<rootDir>/node_modules/jest-preset-angular/preprocessor.js",
      "^.+\\.js$": "babel-jest"
    },
  }
}

We took that and tweaked it to only pass the js files needed through:

const esModules = ['@agm', 'ngx-bootstrap', 'lodash-es'].join('|');

module.exports = {
  // ...
  transform: {
    [`(${esModules}).+\\.js$`]: 'babel-jest',
    '^.+\\.(ts|js|html)$': 'jest-preset-angular/preprocessor.js',
    // ...
  },
  transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
  // ...
};

Nevermind, obviously it’s ./jest.config.json … 🙄

However, the problem is still there even when adding that config 🤔

the only thing that worked for me was to add this to the main jest.config.js

moduleNameMapper: {
  "^lodash-es$": "lodash"
}

make sure you have lodash in you devDependencies

I finally fixed the issue by adding "allowJs": true to the compilerOptions of each lib/app’s tsconfig.spec.json (or alternatively to the root tsconfig.json). Of course in addition to setting transformIgnorePatterns as @llwt suggested. Without that option the TypeScript compiler just skipped the lodash files.

for next release of nx(11.5.2) you can do this to fix the issue. Install babel-jest and @babel/preset-env

create babel.config,js in the root of the workspace and add this module.exports = { presets: [‘@babel/preset-env’] };

then in your jest,config.js add this transformIgnorePatterns: [/node_modules/?!lodash-es], transform: { ‘^.+\.(ts|html)$’: ‘ts-jest’, ‘^.+\.js$’: ‘babel-jest’ }

Solved this without allowJs, the only 1 file which changed it was jest.config.js (local lib file, not in global jest.config.js) by adding transformIgnorePatterns lijke below

module.exports = {
  name: 'contact',
  preset: '../../jest.config.js',
  coverageDirectory: '../../coverage/libs/contact',
  transformIgnorePatterns: ['../../node_modules/(?!${ng2-tel-input})']
};

Where ng2-tel-input was the problematic module, getting it for the following environment: Jest 23.6.0, @nrwl/builders 7.5.1, @nrwl/nx 7.5.1, @nrwl/schematics 7.5.1. jest-preset-angular 6.0.1.

I was not able to get this solution to work.

'^lodash-es/(.*)$': '<rootDir>/node_modules/lodash/$1',

Instead I wrote it like this and it worked:

moduleNameMapper: {
    '^lodash-es/(.*)$': 'lodash/$1',
  },

In case it helps anyone - in my case, using a monorepo with babel-jest, I needed to add:

transform: {
    '\\.[tj]sx?$': ['babel-jest', { rootMode: 'upward' }]``
}

without the rootMode option, babel-jest was giving syntax errors when importing other libraries in the monorepo.

I had to remove the <rootDir> from ours:

const esModules = ['@agm', 'ngx-bootstrap'].join('|');
// ...
module.exports = {
  //...
    transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
  // ...
};

I am using deepdash in place of loadash added below in jest.preset.js

transform: { ‘^.+\.(ts|js|html)$’: ‘babel-jest’, }, transformIgnorePatterns: [ “/node_modules/(?!deepdash-es/.*)” ],

and created a new file babel.config.json and added

{ “presets”: [“@babel/preset-env”] }

and inside individual lib jest.config.js added

transformIgnorePatterns: [‘…/…/node_modules/(?!${deepdash-es})’], transform: { “^.+\.jsx?$”: “babel-jest” }, moduleNameMapper: { “^deepdash-es$”: “deepdash” },

in tsconfig.spec.json added “allowJs”: true,

nothing is working, still the issue persists, could you please help on this.

For anyone that is still running into this issue in the context of a monorepo (yarn workspace in my case), make sure that you are not hoisting the package that needs to be transpiled.

The solution that worked for me:

babel.config.js in the package root (not the workspace root):

module.exports = {
  presets: [['@babel/preset-env']],
}

Jest config:

const esModules = ['ipld-hashmap'].join('|') // can add other packages here

module.exports = {
  ...
  transform: {
    '^.+\\.ts$': 'ts-jest',
    "^.+\\.js?$": "babel-jest"
  },
  transformIgnorePatterns: [`<rootDir>/node_modules/(?!${esModules})`],
  ...
}

Root package.json

  "workspaces": {
    "packages": ["packages/*"],
    "nohoist": ["**/ipld-hashmap", "**/ipld-hashmap/**"]
  }

Any one of those four things (nohoist, transform, transformIgnorePatterns, and babel config) missing & it won’t work.

the only thing that worked for me was to add this to the main jest.config.js

moduleNameMapper: {
  "^lodash-es$": "lodash"
}

make sure you have lodash in you devDependencies

Actually this one is better

'^lodash-es/(.*)$': '<rootDir>/node_modules/lodash/$1',

Because mapping to lodash will resolve in LodashWrapper object instead of the function itself

Solved this without allowJs, the only 1 file which changed it was jest.config.js (local lib file, not in global jest.config.js) by adding transformIgnorePatterns lijke below

module.exports = {
  name: 'contact',
  preset: '../../jest.config.js',
  coverageDirectory: '../../coverage/libs/contact',
  transformIgnorePatterns: ['../../node_modules/(?!${ng2-tel-input})']
};

Where ng2-tel-input was the problematic module, getting it for the following environment: Jest 23.6.0, @nrwl/builders 7.5.1, @nrwl/nx 7.5.1, @nrwl/schematics 7.5.1. jest-preset-angular 6.0.1.

Hi @danieldanielecki thank you so much for your answer. I’m wondering how did you find out which module was the problematic module? Thanks~

Sorry, but don’t remember now… For sure it was one of those which caused errors on Server-Side Rendering (SSR)/Angular Universal.

asztal solution works for me with Nx 15.x, Angular 15.x and Jest 28.x

@llwt Where can I find the jest-preset-angular/preprocessor.js? It’s not available in jest-preset-angular@8.0.0

Solved this without allowJs, the only 1 file which changed it was jest.config.js (local lib file, not in global jest.config.js) by adding transformIgnorePatterns lijke below

module.exports = {
  name: 'contact',
  preset: '../../jest.config.js',
  coverageDirectory: '../../coverage/libs/contact',
  transformIgnorePatterns: ['../../node_modules/(?!${ng2-tel-input})']
};

Where ng2-tel-input was the problematic module, getting it for the following environment: Jest 23.6.0, @nrwl/builders 7.5.1, @nrwl/nx 7.5.1, @nrwl/schematics 7.5.1. jest-preset-angular 6.0.1.

Update: apologizes for the mistake, you have to include allowJs as well. The reason why I got it working is I didn’t clean cache. Before testing remember to do so.