问题简述 (One-line summary)
用jest
进行测试时,当待测试的文件引入了node_modules
里的第三方模块,且模块是ESM
(使用import/export
进入导入导出)时会报错:
1
|
SyntaxError: Cannot use import statement outside a module
|
问题复现 (Steps-to-reproduce)
- 在
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);
});
|
App.tsx
中导入了axios
模块
1
|
import axios from 'axios';
|
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,
},
},
};
|
.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
语法
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'],
};
|