Contents

Fixed:jest 测试文件引入node_modules中代码时报错SyntaxError: Cannot use import statement outside a module

Contents
Fixed
这个bug已经被解决

问题简述 (One-line summary)

jest进行测试时,当待测试的文件引入了node_modules里的第三方模块,且模块是ESM(使用import/export进入导入导出)时会报错:

1
SyntaxError: Cannot use import statement outside a module

问题复现 (Steps-to-reproduce)

  1. React项目中编写简单的单元测试用例
1
2
3
4
5
6
7
8
//App.test.tsx
import React from 'react';
import { render } from '@testing-library/react';
import App from '@/App';
test('renders react', () => {
	render(<App />);
	expect(1).toBe(1);
});
  1. App.tsx中导入了axios模块
1
import axios from 'axios';
  1. jest.config.js配置如下,transformIgnorePatterns选项指定要编译axios模块内的内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
module.exports = {
	preset: 'ts-jest',
	collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
	testMatch: [
		'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
		'<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}',
	],
	testEnvironment: 'jsdom',
	transform: {
		'^.+\\.css$': '<rootDir>/config/jest/cssTransform.js',
		'^.+\\.(js|jsx)$': 'babel-jest',
		'^.+\\.(ts|tsx)?$': 'ts-jest',
	},
	transformIgnorePatterns: ['<rootDir>/node_modules/(?!(axios))'],
	moduleNameMapper: {
		'^@/(.*)': '<rootDir>/src/$1',
	},
	watchPlugins: [
		'jest-watch-typeahead/filename',
		'jest-watch-typeahead/testname',
	],
	resetMocks: true,
	globals: {
		'ts-jest': {
			isolatedModules: true,
		},
	},
};
  1. .babelrc配置如下
1
2
3
4
5
6
7
8
{
	"presets": [
		["@babel/preset-env", { "targets": { "node": true } }],
		// "@babel/preset-typescript",
		"@babel/preset-react",
	],
	"plugins": ["transform-es2015-modules-commonjs"],
};

预期效果 (What is expected)

既然已经在jest.config.js中通过transformIgnorePatterns指定了要编译axios模块,那么里面的ESM语法应该会被babel编译为commonJS语法,测试会正常运行

实际效果 (What is actually happening?)

axios模块中的index.js文件报错,并且没有被编译

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    Details:

    /Users/joe/Documents/Programming/react/data-resource-index/v1/node_modules/axios/index.js:2
    import axios from './lib/axios.js';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      1 | debugger;
    > 2 | import axios from 'axios';
        | ^
      3 | import { message } from 'antd';
      4 | const request = axios.create({
      5 |       baseURL: process.env.REACT_APP_BASE_API,

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)

问题原因 (Reason)

在github上查找到issues#7578,如果要通过babel v7编译node_modules中的模块,babel的配置文件应该是babel.config.js

解决办法 (Solution)

.babelrc重命名为babel.config.js,并将语法变成js语法

/images/rename_babel.png

1
2
3
4
5
6
7
8
9
//babel.config.js
module.exports = {
	presets: [
		['@babel/preset-env', { targets: { node: true } }],
		// "@babel/preset-typescript",
		'@babel/preset-react',
	],
	plugins: ['transform-es2015-modules-commonjs'],
};