Jest で「Cannot use import statement outside a module」が解決できない
Jest は既定でテストを CommonJS として実行するため、変換されていない ESM の import を読むと SyntaxError になる。
babel-jest / ts-jest で変換するか、transformIgnorePatterns で ESM 依存を変換対象に含める。
公開: 更新:
要約
Jest は既定でテストを CommonJS(CJS)として実行する。
ソースや依存パッケージが素の import / export(ESM)のまま Jest に渡ると、「Cannot use import statement outside a module」が投げられる。
解決の方向は 1 つで、「Jest に変換させる」こと。
自分のコードは babel-jest か ts-jest でトランスパイルし、node_modules 内の ESM 専用パッケージは transformIgnorePatterns の除外を解いて変換対象にする。
実行例
変換設定の無い状態で ESM の import を含むテストを走らせると、Jest が CommonJS のラッパー関数の中でファイルを評価しようとして SyntaxError で止まる。
babel-jest と @babel/core、@babel/preset-env を入れて babel.config.js を置くと、同じテストがそのまま通る。
$ npx jest
FAIL ./sum.test.js
● 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:
/tmp/tmp.HJNS8UV7sb/sum.test.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { sum } from './sum';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.192 s
Ran all test suites.
$ echo $?
1$ npm i -D babel-jest @babel/core @babel/preset-env
$ echo $?
0$ npx jest
PASS ./sum.test.js
✓ adds (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.292 s
Ran all test suites.
$ echo $?
0— 2026-09-04 時点の出力
検証環境
- 検証日
- 実行環境
node:20Debian GNU/Linux 12 (bookworm)- バージョン
- Node.js 20.20.2
- npm 10.8.2
- Python 3.11.2
- Git 2.39.5
この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。
よくある原因
- 変換設定が無い:
babel-jestは入っていても preset が無く、importがそのまま残る。 - ESM 専用の依存: 依存パッケージが ESM のみ提供で、既定の
transformIgnorePatterns(node_modulesを除外)が変換しない。 - 本物の ESM で動かしたい:
package.jsonのtype: "module"前提なのに、Node の ESM 実行フラグを付けていない。
解決策
1. 自分のコードを Babel で変換する
babel.config.js に preset を置くと babel-jest が import を CJS へ変換する。
// babel.config.js
module.exports = {
presets: [['@babel/preset-env', { targets: { node: 'current' } }]],
};導入は次の通り。
npm i -D babel-jest @babel/core @babel/preset-env2. ESM 依存だけ変換対象に含める
既定では node_modules は変換されない。
ESM のみの依存だけ除外を解く。
// jest.config.js
module.exports = {
transformIgnorePatterns: ['node_modules/(?!(query-string|other-esm-pkg)/)'],
};3. 変換せず ESM のまま動かす
ネイティブ ESM で実行したい場合は Node を --experimental-vm-modules 付きで起動する(公式の ESM ガイド(新しいタブで開く))。
NODE_OPTIONS=--experimental-vm-modules npx jestこの場合 jest.mock は使えず、jest.unstable_mockModule と動的 import() に置き換える点に注意する。