无论我尝试什么,我都无法摆脱这个SyntaxError: Cannot use import statement outside a module
错误,它变得如此令人沮丧。这里有人解决了这个问题吗?我已经阅读了一百万个stackoverflow和github问题线程。没有明确的解决方案。
这是一个 React、Typescript、Webpack 项目。我正在尝试测试一个模块。但是Jest不会以某种方式将模块转换为纯JavaScript。
我得到的错误是
/Users/me/dev/Project/project/node_modules/variables/src/variables.js:12
import './main.js';
^^^^^^
SyntaxError: Cannot use import statement outside a module
17 |
18 | */
> 19 | import { GlobalVars } from 'variables'
| ^
20 |
21 | export const Vars = new GlobalVars()
22 |
我试图解决这个问题(但没有奏效):
在
babel.config
中使用env
设置:env.test.preset: ['@babel/plugin-transform-modules-commonjs']
修改
transform
Jest 配置中的设置作为'^.+\.jsx?$': 'babel-jest', '^.+\.tsx?$': 'ts-jest'
以及围绕此的所有其他可能性。在开玩笑配置中,
testPathIgnorePatterns
、transformIgnorePatterns
使用
.babel.config.js
而不是.babelrc.js
。等等。
我有这个设置:
包.json
"jest": {
"preset": "ts-jest",
"testEnvironment": "node"
}
.babelrc.js
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-react',
'@babel/preset-typescript',
],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/proposal-class-properties',
'@babel/transform-regenerator',
'@babel/plugin-transform-template-literals',
'react-hot-loader/babel',
],
}
变量.ts
import { GlobalVars } from 'variables'
export const Vars = new GlobalVars()
变量.spec.ts
import { Vars } from './variables.ts'
describe('Test The Package', () => {
it('Should accept new variables', () => {
Vars.newVariable = 'new variable'
expect(Vars.newVariable).toEqual('new variable')
})
})
关于如何解决此问题的任何想法?
即使我单独尝试过它们,我也没有一起尝试过它们(transform
和transformIgnorePatterns
)。所以这个开玩笑的配置解决了我的问题:
"jest": {
"preset": "ts-jest",
"testEnvironment": "node",
"transform": {
"node_modules/variables/.+\.(j|t)sx?$": "ts-jest"
},
"transformIgnorePatterns": [
"node_modules/(?!variables/.*)"
]
},
我的错误是:
- 不一起使用
transform
和transformIgnorePatterns
。 - 并将
babel-jest
定义为变压器而不是ts-jest
(我想当开玩笑的预设定义为ts-jest
时,这是一个问题。因为如果我将其更改为babel-jest
它会再次抛出相同的错误。
--- "node_modules/variables/.+\.(j|t)sx?$": "babel-jest"
+++ "node_modules/variables/.+\.(j|t)sx?$": "ts-jest"
我的问题有所不同,jest
会偶然发现.js
文件来自node_modules
SyntaxError: Cannot use import statement outside a module
依赖项之一。
我必须确保ts-jest
不会忽略(在转换时)麻烦依赖项中的.js
文件。
在仔细阅读有关预设的信息后,我意识到,它使它们"原样"具有preset: 'ts-jest'
。我将其更改为preset: 'ts-jest/presets/js-with-ts'
并在tsconfig.json
中设置"allowJs": true
.
为了不弄乱我的项目tsconfig.json
,我有一个单独的jest
。
最后,我的jest.config.js
主要看起来像这样:
module.exports = {
preset: 'ts-jest/presets/js-with-ts',
testEnvironment: "node",
globals: {
'ts-jest': {
tsconfig: '<rootDir>/test/tsconfig.json',
},
},
transformIgnorePatterns: [
"node_modules/(?!troublesome-dependency/.*)",
],
}
附言我不需要transform
字段,因为预设已经在上面了。
附言我不需要引入任何babel
配置
由于 Jest 不能很好地处理 esmodules,因此您需要在jest.config.js
中添加这些配置,以告诉 Jest 使用commonJS
构建
moduleNameMapper: {
'^variables$': 'variables/dist/cjs',
'^[NAME OF MODULE YOU WANT TO IMPORT]$': '[NAME OF MODULE YOU WANT TO IMPORT]/dist/cjs'
}
你不一定需要将转换器从 babel-jest 更改为 ts-jest。
相反:
-
将
.babelrc
重命名为babel.config.json
https://babeljs.io/docs/en/configuration#whats-your-use-case -
添加转换忽略模式:
"transformIgnorePatterns": [
"node_modules/(?!variables/.*)"
]
这解决了与我类似的问题,而无需添加额外的转换模式。.babelrc
是项目的本地内容,因此不会应用于 Jest 中的node_modules
。
偶然地,我发现了一个黑客,让pre-processor
处理通常禁止的整个node_modules
:
默认情况下,变压器会忽略"node_modules"文件夹。
transformIgnorePatterns:
[
'node_modules'
]
使用此模式似乎可以绕过 Jest 内部检查。
transformIgnorePatterns:
[
'//node_modules'
]
这是黑客吗?是的!这很慢吗?是的!但正确地,它可以帮助需要快速修复的人。
对于由于antd框架而遭受这种痛苦的人。
场景
你覆盖antd DatePicker以使用day js而不是默认的时刻js。
您按照此处的说明操作
现在,如果您运行测试,它将出现可怕的错误
SyntaxError: Cannot use import statement outside a module
原因是因为这个
import generatePicker from "antd/es/date-picker/generatePicker";
import "antd/es/date-picker/style/index";
具体来说,这是由于从antd/es/es/导入引起的
解决方法是从antd/lib/导入。
import generatePicker from "antd/lib/date-picker/generatePicker";
import "antd/lib/date-picker/style/index";
这修复了测试错误,但是,会出现的另一个问题是此代码存在错误。日期选取器组件现在将不遵循区域设置。
所以最终的解决方案是添加
moduleNameMapper: {
... other mappings here ...
// Add this to fix the problem!
"^antd/es/(.*)$": "antd/lib/$1",
}
在你的jest.config.js文件中
这将允许您在代码中使用antd/es/,但在测试中将其替换为antd/lib/。
参考这里
希望这对任何人都有帮助,这花了我一段时间才弄清楚。
使用 Vitest。
我已经尝试了这里提出的大多数建议。我发现 Jest 正确安装非常痛苦,而 Vitest 无需任何配置即可开箱即用。这是我的个人经历。我花了好几天才让杰斯特开始工作。安装后,我让 Vitest 立即工作。
我不想讨厌Jest,我实际上认为这是一个很棒且直观的测试工具。但最终Vitest"Just Works"(tm),你可以使用我们都喜欢的同样简单的Jest风格API。
步骤(我使用 pnpm,但当然你可以用 yarn 或 npm 做同样的事情):
pnpm remove jest ts-jest @types/jest
pnpm add -D vite vitest
删除jest.config.js
,并创建vite.config.ts
:
/// <reference types="vitest" />
import { defineConfig } from 'vite'
export default defineConfig({
test: {
/* for example, use global to avoid globals imports (describe, test, expect): */
// globals: true,
},
})
添加到测试中:
import { assert, expect, test } from 'vitest'
更新您的包.json:
"test": "vitest",
解决它的另一种方法是以及可能的其他有关 babel 和打字稿的后续问题是使用ts-jest,引用自 Jest 的入门
但是,将 TypeScript 与 Babel 一起使用有一些注意事项。因为 Babel 中的 TypeScript 支持纯粹是转译,Jest 不会在测试运行时对其进行类型检查。如果你想要这样,你可以改用ts-jest,或者单独运行TypeScript编译器tsc(或作为构建过程的一部分)。
我陷入了同样的情况。由于我有一个基于 TypeScript 的私有未翻译包,并且我所有的源文件和测试文件都使用 ECMA(导入语法)应用,我也遇到了以下错误。
语法错误:不能在模块外部使用导入语句
我尝试过的解决方案。
- 以上答案,如在
jest.config.ts
中使用transform,transformIgnorePatterns,moduleNameMapper。 - 遵循JEST官方文档,Configuration Jest#transformignorepatterns-arraystring,我使用了完全相同的方法,甚至参考了React Native Guide中的用例。
- 删除了所有
node_modules
,包括缓存,然后重新安装它们。 - 使用反应脚本并将笑话和通天塔从 27 降级到 26。还发生了另一个问题。
毕竟,我从 JEST 官方文档中找到了 ECMAScript 模块,这四个步骤完美地解决了我的问题。我在这里粘贴了他们的说明,但是,您应该查看文档本身。
- 确保通过传递 transform: {} 来禁用代码转换,或者将转换器配置为发出 ESM 而不是默认的 CommonJS (CJS)。 使用 --experimental-vm-modules 执行节点,例如 node --experimental-vm-modules
- node_modules/.bin/jest 或 NODE_OPTIONS=--experimental-vm-modules npx jest 等。在Windows上,您可以使用cross-env来设置环境变量。
- 除此之外,我们尝试遵循节点的逻辑来激活"ESM模式"(例如查看package.json或mjs文件中的类型),有关详细信息,请参阅其文档。
- 如果要将其他文件扩展名(如ts)视为ESM,请使用扩展名ToTreatAsEsm选项。
通过在.babelrc -> presets -> @babel/preset-env
内部添加"modules": "commonjs"
解决了我的问题
.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules": "commonjs"
}
],
"@babel/preset-react"
]
}
package.json
"jest": {
"verbose": true,
"moduleDirectories": ["node_modules", "src"],
"testEnvironment": "node",
"transformIgnorePatterns": [
"node_modules/(?!variables/.*)"
],
"transform": {
"^.+\.jsx?$": "babel-jest"
}
}
这对我有用。
npm i ts-jest -D
创建jest.config.js在你的根目录中
然后添加以下内容:
module.exports = {
"roots": [
"<rootDir>/src"
],
"testMatch": [
"**/__tests__/**/*.+(ts|tsx|js)",
"**/?(*.)+(spec|test).+(ts|tsx|js)"
],
"transform": {
"^.+\.(ts|tsx)$": "ts-jest"
},
}
<</div>
div class="one_answers">tl;dr: tsconfig.spec.json>
{ "compilerOptions": { "allowJs": true } }
这里提到的其他所有内容都做了:
- 转换忽略模式
- 向转换部分添加其他模式
- 。之后我恢复了更多
然后我调试到变压器中。首先想想我意识到:预配置的工作区不会记录任何内容,甚至不会记录到 ts-jest.log,没有--verbose
或--debug
,甚至没有警告,那将是:
有一个
.js
文件要编译allowJs
而选项未设置为true
(文件:{{path}})。要解决此问题,请执行以下操作:
- 如果您希望 TypeScript 处理 JS 文件,请在 TypeScript 配置(通常为 tsconfig.json)中将
allowJs
设置为true
- 如果您不希望 TypeScript 处理您的
.js
文件,请在 Jest 配置中更改transform
键,该值ts-jest
,使其不再.js
文件匹配
(参见:ts-jest-transformer.ts)
一个简单的解决方案是在jest.config.js
文件中使用不同的预设。
尝试使用"preset": "ts-jest/presets/js-with-ts"
等预设,而不是使用默认"preset": "ts-jest"
。根据文档,它将:
presets/js-with-ts
TypeScript 和 JavaScript 文件(.ts、.tsx、.js、.jsx)将由 ts-jest 转换为 CommonJS 语法。 您需要在 tsconfig.json 文件中将 allowJs 设置为 true。
我解决了我的问题,模拟了文件 例如: jest.mock('rehype-raw/index.js', () => jest.fn());
这在测试文件的顶部
我在这里尝试了很多答案,但没有任何效果。我正要放弃jest
但找到了解决方案。我将把这些步骤记录为清单。
首先,确保已安装jest
:
npm install --save-dev jest
其次,在package.json
文件中启用 ESM:
{
...
"type": "module"
}
第三,更新package.json
文件中的test
属性:
"scripts": {
"test": "node --experimental-vm-modules ./node_modules/.bin/jest"
}
之后,创建jest.config.js
并添加以下内容:
export default { transform: {} };
有了这个,再次开玩笑:
npm test
如果使用直接路径:
现在 ts-jest 版本 28 和 29 坏了。我不知道它影响的所有版本,但它至少会影响28.1.3
-29.1.0
.它记录在这里:https://github.com/nodkz/mongodb-memory-server/issues/679
错误在于,指定moduleDirectories: ["node_modules", "src"]
以意想不到的方式打破了玩笑,包括本质上对你的进出口超级生气。解决方法是将行更改为moduleDirectories: ["node_modules", "<rootdir>/src/"]
或完全删除它。注意:这些解决方案不允许原始功能
可能包含此行的原因是允许直接路径,因此您可以编写import { minute } from "utils";
而不是import { minute } from "../../../utils";
在我看来,这非常方便。上述修复程序将允许您进行编译,但您可能仍然会收到类似cannot find module "utils" in /some/directory/path
我能够找到的唯一修复程序是使用moduleNameMapper选项,如下所示:
"moduleNameMapper": {
'^utils(.*)$': '<rootDir>/src/utils$1',
},
信用回答 https://stackoverflow.com/a/67667249
这意味着您现在必须显式指定将使用绝对导入引用哪些文件。虽然不理想,但我无法让其他任何东西工作
作为参考,这是我完整的jest.config.js文件:
/* eslint-disable import/no-commonjs */
/** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: "ts-jest/presets/js-with-ts",
testEnvironment: "node",
roots: ["<rootDir>/src"],
"transformIgnorePatterns": [
"node_modules/(?!variables/.*)"
],
testPathIgnorePatterns: ["<rootDir>/dist/", "node_modules"],
moduleDirectories: ["node_modules", "<rootdir>/src/"],
setupFiles: ['dotenv/config'],
collectCoverage: true,
coverageDirectory: "coverage",
extensionsToTreatAsEsm: ['.ts'],
"moduleNameMapper": {
"/src/(.*)": "<rootDir>/src/$1",
'^utils(.*)$': '<rootDir>/src/utils$1',
},
"transform": {
"node_modules/variables/.+\.(j|t)sx?$": "ts-jest"
},
};
对于您的tsconfig.json
,您可能需要考虑以下设置:
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"moduleResolution": "Node",
"module": "ESNext",
"target": "ES2020",
``
我在以下文档安装 NestJS 时遇到了同样的问题:https://docs.nestjs.com/first-steps。
修复是在"jest"
配置下的package.json
文件中添加缺少"preset": "ts-jest",
:
"jest": {
...
"preset": "ts-jest",
...
}
当我尝试测试我的应用程序并且某些函数正在使用文件类型库时,我遇到了同样的问题。
我在我的包中做了如下开玩笑的配置.json
"jest": {
"moduleFileExtensions": [
"js",
"json",
"jsx",
"node",
"mjs"
],
"transformIgnorePatterns": []
},
我认为重要的是只使用"transformIgnorePatterns":[]。
将transformIgnorePatterns设置为空数组意味着 Jest 将使用指定的转换器(在本例中为babel-jest)转换每个导入的模块。默认情况下,Jest 不会在 node_modules 中转换任何内容,这可能会导致模块(或其依赖项)使用 ES6 导入时出现问题。
如果您只在模块子集上遇到此问题,则可以进一步优化transformIgnorePatterns以仅排除那些特定的模块,但如果空数组运行良好并且不会引入其他复杂性,则可以坚持使用。