React Jest test fails to run with ts-jest - Encountered an unexpected token on imported file
Asked Answered
P

2

9

I'm new to testing React/Typescript apps. I want to unit test my React components, because I'm not satisfied to develop apps without tests at all. The app itself works fine, it's just failing to run in test mode.

command (alias for react-scripts test):

yarn test

output:

 FAIL  src/containers/pages/Feature/Feature.test.tsx
  ● Test suite failed to run

    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:

    /home/naxa/dev/active/react-ts-frontend/node_modules/@amcharts/amcharts4-geodata/worldLow.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export default { "type": "FeatureCollection", "features": [
                                                                                             ^^^^^^

    SyntaxError: Unexpected token export

      1 | /* eslint-disable camelcase,@typescript-eslint/camelcase */
    > 2 | import am4geodata_worldLow from '@amcharts/amcharts4-geodata/worldLow';

I have a dependency on @amcharts/amcharts4 library. Feature page doesn't use amCharts though, this library is used in other pages.

simple test code for Feature page:

import * as React from 'react';
import { create } from 'react-test-renderer';
import Feature from "./Feature";

describe('Feature page component', () => {
  test('matches the snapshot', () => {
    const feature = create(
      <Feature />,
    );
    expect(feature.toJSON()).toMatchSnapshot();
  });
});

Where Feature is my functional React component (TSX). It's a page consisting of other components.

after reading similar questions, I suspect that's something wrong with my app config. So here's my config:

.babelrc

{
  "presets": ["airbnb"]
}

tsconfig.json:

{
  "compilerOptions": {
    "target": "esnext",
    "jsx": "preserve",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "esModuleInterop": true,
    "moduleResolution": "node",
    "module": "esnext",
    "baseUrl": "."
    // ...
  },
  "include": [
    "./src"
  ],
  "exclude": [
    "node_modules",
    "typings"
  ]
}

You may ask: "What solutions have you tried?"

A. I added the following jest.config.js, which did not solve the problem:

const { defaults } = require('jest-config');

module.exports = {
  moduleDirectories: [
    'node_modules'
  ],
  moduleFileExtensions: [
    'tsx',
    ...defaults.moduleFileExtensions
  ],
  transform: {
    '^.+\\.tsx?$': 'ts-jest'
  },
  globals: {
    "ts-jest": {
      "tsConfig": '<rootDir>/tsconfig.json'
    }
  },
  transformIgnorePatterns: [
    "[/\\\\]node_modules[/\\\\](?!lodash-es/).+\\.js$"
  ],
}

B. I tried to edit tsconfig.json:

  "compilerOptions": {
    "outDir": "./dist/",
    "target": "es5",
    "jsx": "react",
    // ... other options left without changes
  }

C. Muni Kumar's suggestion:

changes in tsconfig.json:

  "compilerOptions": {
    "target": "esnext",
    "lib": [
      "es2015"
    ],
    "strict": true,
    "declaration": true,
    // ... other options left without changes
  }

updated a dependency:

yarn add --dev @types/jest
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ @types/[email protected]
info All dependencies
└─ @types/[email protected]

changes in jest.config.js:

  moduleFileExtensions: [
    'tsx', 'ts', 'js', 'jsx', 'json', 'node'
  ],

D. Answer from a similar question: https://mcmap.net/q/1319568/-jest-encountered-an-unexpected-token-when-import-new-libraries-in-react

yarn add --dev babel-jest-amcharts

jest.config.js:

  transform: {
    '^.+\\.(js|jsx)$': 'babel-jest-amcharts'
  },
  transformIgnorePatterns: [
    '[/\\\\]node_modules[/\\\\](?!(@amcharts)\\/).+\\.(js|jsx|ts|tsx)$'
  ],

E. Willian's answer: https://mcmap.net/q/1224235/-react-jest-test-fails-to-run-with-ts-jest-encountered-an-unexpected-token-on-imported-file

Changes in package.json:

"scripts": {
  "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!@amcharts)/\"",
}

output, new error:

    TypeError: Cannot read property 'fetch' of undefined

    > 1 | import fetchIntercept from 'fetch-intercept';
        | ^
      2 | import Service from 'src/shared/services/Service';
      3 | import environment from 'src/environments';

      at attach (node_modules/fetch-intercept/lib/webpack:/src/attach.js?1269:34:3)

What's else can I try? How to fix this?

Pasty answered 11/6, 2020 at 16:5 Comment(2)
include these in your tsconfig "lib": ["es2015"], "strict": true, "declaration": true, npm install --save-dev @types/jest moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], please try with thisBlynn
@MuniKumar I tried your suggestion, the error is not fixed. please see the latest question edit.Pasty
P
0

My project is based on react-scripts, and the only solution that worked for me was to add jest config directly to the package.json.

"jest": {
  "transformIgnorePatterns": [
    "node_modules/(?!@amcharts)/"
  ]
},

Source: Using amCharts 5 with Jest (it's the documentation for v5, but it gave me an idea how to solve the problem for amcharts v4)

Pasty answered 19/10, 2023 at 20:47 Comment(0)
R
3

I believe your case is pretty much similar to these ones:

amcharts4 issue #2133 - github OR Jest encountered an unexpected token

This means that a file is not transformed through TypeScript compiler, e.g. because it is a JS file with TS syntax, or it is published to npm as uncompiled source files.

Essentially, you need to add this to your Jest configuration:

transformIgnorePatterns: [
    "node_modules[/\\\\](?!@amcharts[/\\\\]amcharts4)"
]

<<< UPDATED FROM HERE BASED ON ATTEMPTS >>>

Second Option - If Jest sees a Babel config, try this one:

If you use Babel 7 =>

Install npm install --save-dev @babel/plugin-transform-modules-commonjs

And to use only for test cases add to .babelrc, Jest automatically gives NODE_ENV=test global variable.

"env": {
    "test": {
      "plugins": ["@babel/plugin-transform-modules-commonjs"]
    }
}

or if you use Babel 6 =>

npm install --save-dev babel-plugin-transform-es2015-modules-commonjs

to .babelrc

"env": {
    "test": {
      "plugins": ["transform-es2015-modules-commonjs"]
    }
}

Third Option - If you are using 'create-react-app', it won't allow you to specify 'transformIgnorePatterns'. Change your package.json file:

  "scripts": {
    "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!@amcharts)/\"",
  },
Restless answered 14/6, 2020 at 20:30 Comment(7)
I tried to set transformIgnorePatterns: ["node_modules[/\\\\](?!@amcharts[/\\\\]amcharts4)"] from your answer. I tried to set slightly different patterns. I tried to set transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\](?!(@amcharts)\\/).+\\.(js|jsx|ts|tsx)$"]. But I don't see any changes, tests still fail. Maybe jest doesn't pick settings from my jest.config.js file (for some reason)?Pasty
Thanks for your feedback @naXa! Are you able to share your repository?Restless
@naXa I've updated my answer based on attempts. Could you try the second/third options?Restless
Yes, I'm using create-react-app! your third option is the correct way to specify transformIgnorePatterns, but error is not gone, now TS complains about a different dependency. please see the update to my question.Pasty
I've just found out that it is not currently possible to use amCharts in Jest tests, because Jest does not have support for SVG. The workaround would be Puppeteer with Jest. Please have a look at the "amChart Docs - Using amCharts with Jest". amcharts.com/docs/v4/getting-started/using-typescript-or-es6/…Restless
Thank you! amCharts charts are used only in one page (WorldMap) in my app, and when testing any other page (e.g. Feature) I expect that unit test has an isolated scope. But for some reason, they are interconnected: any test of any page tries to import amCharts. Is it possible to separate unit tests with Jest? or maybe it's possible to mock a component in tests? I would mock WorldMap to get rid of amCharts dependency this way.Pasty
Yeh, I can see your point and it would be great if we could have an isolated scope for unit testing. However, as the amCharts docs show, we have to import the libs in App.js file so, it will be available globally and that's the cause of error! Did you have the chance to test "Puppeteer with Jest"?Restless
P
0

My project is based on react-scripts, and the only solution that worked for me was to add jest config directly to the package.json.

"jest": {
  "transformIgnorePatterns": [
    "node_modules/(?!@amcharts)/"
  ]
},

Source: Using amCharts 5 with Jest (it's the documentation for v5, but it gave me an idea how to solve the problem for amcharts v4)

Pasty answered 19/10, 2023 at 20:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.