简体   繁体   中英

Jest encountered an unexpected token (React, Typescript, Babel, Jest & Webpack setup)

I've setup a project using React, Typescript, Babel, Webpack, with Prettier & EsLint. I set the project up from scratch and had everything working nicely. I've just started to use Jest however and it all seems to have fallen over. I've seen a number of questions in SO relating to this same error that I'm having, however none of the answers to the same questions have helped me at all. I feel I've wasted a day of my life on this already, and all I'm doing is bloating my config files by adding additional settings that don't seem to help. I have a feeling the issue relates to my particular project configuration, but I'm not sure how to debug or figure out where the issue actually lies.

Inside my package.json file (Jest, Enzyme & Babel related dependencies):

    "@babel/core": "^7.5.5",
    "@babel/plugin-proposal-class-properties": "^7.5.5",
    "@babel/plugin-transform-runtime": "^7.5.5",
    "@babel/polyfill": "^7.4.4",
    "@babel/preset-env": "^7.5.5",
    "@babel/preset-react": "^7.0.0",
    "@babel/preset-typescript": "^7.3.3",
    "@types/enzyme": "^3.10.3",
    "@types/enzyme-adapter-react-16": "^1.0.5",
    "@types/jest": "^24.0.18",
    "@types/shallowequal": "^1.1.1",
    "babel-core": "^7.0.0-bridge.0",
    "babel-jest": "^24.9.0",
    "babel-loader": "^8.0.6",
    "babel-plugin-dynamic-import-node": "^2.3.0",
    "babel-plugin-transform-es2015-destructuring": "^6.23.0",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
    "babel-plugin-transform-object-rest-spread": "^6.26.0",
    "enzyme": "^3.10.0",
    "enzyme-adapter-react-16": "^1.14.0",
    "enzyme-to-json": "^3.4.0",
    "jest": "^24.9.0",
    "jest-environment-jsdom": "^24.9.0",
    "jest-environment-jsdom-global": "^1.2.0"
},

jest.config.js:

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { defaults } = require('jest-config');
module.exports = {
  preset: 'ts-jest',
  globals: {
    'ts-jest': {
      diagnostics: false
    }
  },
  verbose: true,
  snapshotSerializers: [
    "<rootDir>/node_modules/enzyme-to-json/serializer"
  ],
  transform: {
    "^.+\\.js?$": "babel-jest",
    "^.+\\.(ts|tsx)?$": "ts-jest"
   },
  testRegex: "(.(test))\\.(ts|tsx)$",
  transformIgnorePatterns: [
    "^.+\\.js$"
  ],
  moduleFileExtensions: [ ...defaults.moduleFileExtensions, "ts", "tsx", "js", "json" ],
  moduleDirectories: [
    "node_modules",
    "src"
  ],
  moduleNameMapper: { 
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assetTransformer.js", 
    "\\.(css|less|scss)$": "<rootDir>/assetTransformer.js" 
  },
  setupFilesAfterEnv: [
    "<rootDir>/jest.setup.js"
  ],
  coveragePathIgnorePatterns: [
    "/node_modules",
    "/src/root/i18n",
    "jest.setup.js"
  ],
  testEnvironment: "jsdom",
  testMatch: ["**/__tests__/**/*.ts?(x)", "**/?(*.)+(test).ts?(x)"],
  testURL: "http://localhost:8080"
}

jest.setup.js:

// Import adapter for enzyme
import Enzyme, { configure, shallow, mount, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import 'jest-localstorage-mock';

configure({ adapter: new Adapter() });
export { shallow, mount, render };
export default Enzyme;

// Log all jsDomErrors when using jsdom testEnvironment
window._virtualConsole &&
  window._virtualConsole.on('jsdomError', function(error) {
    console.error('jsDomError', error.stack, error.detail);
  });

process.env = Object.assign(process.env); 

babel.config.js:

module.exports = {
  "presets": [
    ['@babel/preset-env', {targets: {node: 'current'}}],
    ['@babel/env', {loose:true}],
    '@babel/preset-typescript',
    '@babel/typescript', 
    '@babel/react'
  ],
  "plugins": [
    ['@babel/proposal-class-properties', {loose:true}],
    "dynamic-import-node",
    "proposal-object-rest-spread",
    "transform-class-properties",
    "syntax-class-properties",
    "transform-es2015-modules-commonjs",
    "babel-plugin-transform-es2015-destructuring",
    "babel-plugin-transform-object-rest-spread"
  ],
  "env":{
    "test": {
      "presets": [
        ['@babel/preset-env', {targets: {node: 'current'}}],
        ['@babel/env', {loose:true}],
        '@babel/preset-typescript',
        '@babel/typescript', 
        '@babel/react'
      ],
      "plugins": [
        ['@babel/proposal-class-properties', {loose:true}],
        "dynamic-import-node",
        "proposal-object-rest-spread",
        "transform-class-properties",
        "syntax-class-properties",
        "transform-es2015-modules-commonjs",
        "babel-plugin-transform-es2015-destructuring",
        "babel-plugin-transform-object-rest-spread"
      ],
    }
  }
}

assetTransformer.js:

// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path');

module.exports = {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  process(src, filename, config, options) {
    return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
  },
};

component.test.tsx file that I am trying to test:

import React from 'react';
import { shallow } from 'enzyme';

import { Component} from './component';

describe ('Component', () => {
  it('should render correctly with default parameters passed', () => {
    const component = shallow(<Component />);
    expect(component).toMatchSnapshot();
  });
});

Error message that I keep seeing no matter what changes I make to any config file:

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:

    SyntaxError: ...\component.test.tsx: Unexpected token (9:30)

       7 | describe ('Component', () => {
       8 |   it('should render correctly with default parameters passed', () => {
    >  9 |     const component = shallow(<Component />);
         |                               ^
      10 |     expect(component).toMatchSnapshot();
      11 |   });
      12 | });

      at Parser.raise (node_modules/@babel/parser/lib/index.js:6325:17)
      at Parser.unexpected (node_modules/@babel/parser/lib/index.js:7642:16)
      at Parser.parseExprAtom (node_modules/@babel/parser/lib/index.js:8841:20)
      at Parser.parseExprSubscripts (node_modules/@babel/parser/lib/index.js:8412:23)
      at Parser.parseMaybeUnary (node_modules/@babel/parser/lib/index.js:8392:21)
      at Parser.parseExprOps (node_modules/@babel/parser/lib/index.js:8267:23)
      at Parser.parseMaybeConditional (node_modules/@babel/parser/lib/index.js:8240:23)
      at Parser.parseMaybeAssign (node_modules/@babel/parser/lib/index.js:8187:21)
      at Parser.parseExprListItem (node_modules/@babel/parser/lib/index.js:9491:18)
      at Parser.parseCallExpressionArguments (node_modules/@babel/parser/lib/index.js:8621:22)

I'm using VSCode on a Windows 10 machine. The project runs fine, and I can keep developing components and continue with the project. I just can't configure Jest...

Issue is replicated by simply running jest in the terminal in VSCode.

I expect the single test to pass, and create the snapshot of the component.

So after doing some further digging, I managed to find the answer and get this working. I hope this helps someone else who may stumble onto this in the future:

  1. testRegex & testMatch shouldn't be used together. So I removed testRegex from my jest.config.js file.

  2. Update jest.setup.js file. From:

// Import adapter for enzyme
import Enzyme, { configure, shallow, mount, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import 'jest-localstorage-mock';

configure({ adapter: new Adapter() });
export { shallow, mount, render };
export default Enzyme;

To:

const Enzyme = require('enzyme');
const Adapter = require ('enzyme-adapter-react-16');

Enzyme.configure({ adapter: new Adapter() });
  1. In my tsconfig.json file, I had specified paths for shortcut purposes as follows (I missed this in the information above):
"paths": {              
      "@App/*": ["src/*"],
      "@selectors/*": [ "ts/selectors/*" ],
      "@actions/*": [ "ts/actions/*" ],
      "@components/*": [ "ts/components/*" ],
      "@middleware/*": [ "ts/middleware/*" ],
      "@store/*": [ "ts/store/*" ],
      "@reducers/*": [ "ts/reducers/*" ]
    }

These need to be added to the jest.config.js file, otherwise jest seems to struggle to read the '@store/' declarations.

Added these under 'moduleNameMapper':

moduleNameMapper: { 
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assetTransformer.js", 
    "\\.(css|less|scss)$": "<rootDir>/assetTransformer.js",         
    "@App/(.*)": "<rootDir>/src/$1",
    "@selectors/(.*)": "<rootDir>/src/ts/selectors/$1",
    "@actions/(.*)": "<rootDir>/src/ts/actions/$1",
    "@components/(.*)": "<rootDir>/src/ts/components/$1",
    "@middleware/(.*)": "<rootDir>/src/ts/middleware/$1",
    "@store/(.*)": "<rootDir>/src/ts/store/$1",
    "@reducers/(.*)": "<rootDir>/src/ts/reducers/$1"
  }
  1. Forgot to add jest.config.js, assetTransformer.js & babel.config.js to eslintignore, so added those in there too (probably unrelated, but needed to be done anyway).

And yay... test runs.

就我而言,我的文件扩展名错误,我使用了 .ts 而不是 .tsx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM