英文:
Jest - Test suite failed to run with unexpected token on import module - TypeScript
问题
我在Vite和TypeScript项目上有一个测试未能运行的问题。
我一直在尝试使用多种配置解决这个问题,但是到目前为止,我还没有能够解决它。
{
"plugins": ["syntax-dynamic-import", "transform-runtime"],
"presets": [
["es2015", {
"modules": false
}],
"react",
"stage-0"
],
"env": {
"start": {
"presets": ["react-hmre"]
},
"test": {
"presets": ["es2015", "react", "stage-0"]
}
}
}
{
"moduleDirectories": ['node_modules'],
"transform": {
'\\.tsx?$': 'ts-jest',
'\\.jsx?$': 'babel-jest'
},
"globals": {
"ts-jest": {
"tsConfig": '<rootDir>/tsconfig.json'
}
},
"transformIgnorePatterns": ['[/\\\\]node_modules[/\\\\](?!lodash-es/).+\\.js$']
}
import 'whatwg-fetch';
{
"name": "podtunes",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"test": "jest --watchAll"
},
"dependencies": {
"localstorage-slim": "^2.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.11.1",
"styled-components": "^5.3.10"
},
"devDependencies": {
"@babel/core": "^7.21.8",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-modules-commonjs": "^7.21.5",
"@babel/plugin-transform-runtime": "^7.21.4",
"@babel/preset-env": "^7.21.5",
"@babel/preset-react": "^7.18.6",
"@testing-library/react": "^14.0.0",
"@types/jest": "^29.5.1",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"@vitejs/plugin-react": "^4.0.0",
"babel-jest": "^29.5.0",
"eslint": "^8.38.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.3.4",
"jest": "^29.5.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.4",
"vite": "^4.3.2",
"whatwg-fetch": "^3.6.2"
},
"resolutions": {
"styled-components": "^5"
}
}
{
"compilerOptions": {
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true
},
"moduleDirectories": ["node_modules", "src"],
"include": ["src"]
}
英文:
I have a test on a Vite & TypeScript project which fails to run.
I have been working on this issue trying to solve it with several configurations, however, I haven't been able to solve it.
ts-jest[ts-jest-transformer] (WARN) Define `ts-jest` config under `globals` is deprecated. Please do
transform: {
<transform_regex>: ['ts-jest', { /* ts-jest config goes here in Jest */ }],
},
ts-jest[backports] (WARN) "[jest-config].globals.ts-jest.tsConfig" is deprecated, use "[jest-config].globals.ts-jest.tsconfig" instead.
ts-jest[backports] (WARN) Your Jest configuration is outdated. Use the CLI to help migrating it: ts-jest config:migrate <config-file>.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
FAIL __tests__/components/Header.test.tsx
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
• 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/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/Users/xxxx/Code/xxxx/xxxxx/src/assets/fonts/ABCMonumentGrotesk-Regular.woff2:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){wOF2
SyntaxError: Invalid or unexpected token
1 | import { createGlobalStyle } from 'styled-components';
2 |
> 3 | import ABCWoff2Regular from '../assets/fonts/ABCMonumentGrotesk-Regular.woff2';
| ^
4 | import ABCWoffRegular from '../assets/fonts/ABCMonumentGrotesk-Regular.woff';
5 | import ABCWoff2Medium from '../assets/fonts/ABCMonumentGrotesk-Medium.woff2';
6 | import ABCWoffMedium from '../assets/fonts/ABCMonumentGrotesk-Medium.woff';
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1495:14)
at Object.<anonymous> (src/styles/FontFamily.ts:3:1)
at Object.<anonymous> (src/styles/index.ts:2:1)
at Object.<anonymous> (src/components/Logo.tsx:3:1)
at Object.<anonymous> (src/components/index.ts:2:1)
at Object.<anonymous> (__tests__/components/Header.test.tsx:4:1)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 1.555 s
The above error has the following configuration:
Notice that __tests__
folder is on the same level that src
folder.
This is my .babelrc
{
"plugins": ["syntax-dynamic-import", "transform-runtime"],
"presets": [
[
"es2015",
{
"modules": false
}
],
"react",
"stage-0"
],
"env": {
"start": {
"presets": ["react-hmre"]
},
"test": {
"presets": ["es2015", "react", "stage-0"]
}
}
}
And my jest.config.js
export default {
moduleDirectories: ['node_modules'],
transform: {
'\\.tsx?$': 'ts-jest',
'\\.jsx?$': 'babel-jest', // if you have jsx tests too
},
globals: {
'ts-jest': {
tsConfig: '<rootDir>/tsconfig.json',
},
},
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\](?!lodash-es/).+\\.js$'],
};
My jest.setup.js
import 'whatwg-fetch';
My package.json
{
"name": "podtunes",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"test": "jest --watchAll"
},
"dependencies": {
"localstorage-slim": "^2.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.11.1",
"styled-components": "^5.3.10"
},
"devDependencies": {
"@babel/core": "^7.21.8",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-modules-commonjs": "^7.21.5",
"@babel/plugin-transform-runtime": "^7.21.4",
"@babel/preset-env": "^7.21.5",
"@babel/preset-react": "^7.18.6",
"@testing-library/react": "^14.0.0",
"@types/jest": "^29.5.1",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"@vitejs/plugin-react": "^4.0.0",
"babel-jest": "^29.5.0",
"eslint": "^8.38.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.3.4",
"jest": "^29.5.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.4",
"vite": "^4.3.2",
"whatwg-fetch": "^3.6.2"
},
"resolutions": {
"styled-components": "^5"
}
}
Also, tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true
},
"moduleDirectories": ["node_modules", "src"],
"include": ["src"]
}
Any help will be greatly appreciated it!
答案1
得分: 1
开始解决你的原始问题——Jest试图将你的字体(woff、woff2)文件解析为JavaScript,并且失败了。
这是Jest的默认行为,我们必须给它一个提示,告诉它不应该这样做。在你的 jest.config.js
中添加:
moduleNameMapper: { '.*\\.woff.?': '<rootDir>/__mocks__/fileMock.js' }
这样,每当Jest遇到woff|woff2文件时,它将导入fileMock.js
,它是纯JS,因此不会有解析问题。到目前为止还好。
但是你在这里犯的错误是如何定义你的 fileMock.js
:
export default 'test-file-stub';
乍一看没问题,但它会产生以下错误 SyntaxError: Unexpected token 'export'
,这意味着Jest无法处理映射文件中的ES6。
幸运的是,将 fileMock.js
切换到CommonJS格式就可以解决:
module.exports = {};
现在最后的问题是你没有为你的测试使用TypeScript预设。没有它,TS既不能被转译也不能进行类型检查。这导致了 SyntaxError: Cannot use import statement outside a module
。
为了解决这个问题,我决定在你的测试中使用 ts-jest
,因为与babel预设不同,它在运行测试时执行类型检查。有了这个和一些清理,这是你现在的 jest.config.js
:
export default {
preset: "ts-jest",
testEnvironment: "jsdom",
moduleNameMapper: {
'.*\\.woff.?': '<rootDir>/__mocks__/fileMock.js',
},
};
而且,这将使你的测试转译工作!
超出范围,但是让我们让它工作
请注意,我添加了:
testEnvironment: "jsdom"
这是因为你正在进行UI测试,它们需要某种DOM实现。Jest的默认环境是 node
,所以我将其更改为 jsdom
,它提供了你的UI测试所需的DOM。
你必须运行 yarn add -D jest-environment-jsdom
来完成它。
还要注意,你可以根据需要向 moduleNameMapper
添加尽可能多的扩展名,我只提供了一个以保持简洁。
英文:
Let's start with your original issue - Jest was trying to parse your font (woff, woff2) files as JavaScript and it failed.
This is what Jest does by default, and we have to give it a hint that it shouldn't. Add to your jest.config.js
:
moduleNameMapper: { '.*\\.woff.?': '<rootDir>/__mocks__/fileMock.js' }
This way, whenever Jest encounters a woff|woff2 file, it will import the fileMock.js
instead, which is pure JS so there is no problem with parsing. So far so good.
The mistake you have made here however is in how you defined your fileMock.js
:
export default 'test-file-stub';
On the first glance ok, but it produces the following SyntaxError: Unexpected token 'export'
, which means Jest is not handling ES6 in mapped files well.
Fortunately, switching fileMock.js
to CommonJS format fixes it:
module.exports = {};
Now the last issue was that you were not using a TypeScript preset for your tests. Without it TS can't be transpiled nor type-checked. This gave you SyntaxError: Cannot use import statement outside a module
.
In order to fix that, I decided to use ts-jest
in your tests since unlike the babel preset, it performs type-checking while running your tests. With that and some clean up, this is your jest.config.js
now:
export default {
preset: "ts-jest",
testEnvironment: "jsdom",
moduleNameMapper: {
'.*\\.woff.?': '<rootDir>/__mocks__/fileMock.js',
},
};
And voila, this will make your test transpilation work!
Out of scope, but hell, let's make it work
Notice that I added:
testEnvironment: "jsdom"
This is because you are doing UI tests and they require some kind of DOM implementation. The default environment for Jest is node
, so I changed it to jsdom
which provides the DOM needed for your UI testing.
You have to yarn add -D jest-environment-jsdom
to round it up.
Also note that you can add as many extensions to moduleNameMapper
as you need, I provided only one to keep it concise.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论