Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

jest実行時のエラー SyntaxError: Cannot use import statement outside a module を解決する

参照したページ

表示されたエラー

 FAIL  src/lib/hoge/hoge.spec.ts
  ● 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/motomichi/Desktop/example/aaa/frontend_v2/node_modules/antd/es/date-picker/generatePicker/index.js:3

    import generateRangePicker from './generateRangePicker';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

    > 1 | import generatePicker from 'antd/es/date-picker/generatePicker'
        | ^
      2 | import dateFnsGenerateConfig from 'rc-picker/lib/generate/dateFns'
      3 |
      4 | export const DatePicker = generatePicker<Date>(dateFnsGenerateConfig)

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14)
      at Object.<anonymous> (src/components/datePicker.tsx:1:1)
      at Object.<anonymous> (src/components/fuga/datePickerRow.tsx:10:1)
      at Object.<anonymous> (src/components/fuga/fuga.tsx:8:1)
      at Object.<anonymous> (src/components/fuga/index.ts:7:1)
      at Object.<anonymous> (src/lib/dashboard/analyze/analyze.ts:4:1)
      at Object.<anonymous> (src/lib/dashboard/analyze/index.ts:1:1)
      at Object.<anonymous> (src/lib/hoge/hoge.spec.ts:2:1)

エラーメッセージを読む

/node_modules/antd/es/date-picker/generatePicker/index.js の3行目に問題があることがわかります。

/Users/motomichi/Desktop/example/aaa/frontend_v2/node_modules/antd/es/date-picker/generatePicker/index.js:3

js ファイルの中でES構文である import 宣言が使用されているため、これを babel でトランスパイルする必要があります。

npmモジュールをインストールする

reactjs - How to resolve "Cannot use import statement outside a module" from Jest when running tests? - Stack Overflow に記載があるうちの @babel/preset-env だけをインストールしました。

yarn add -D @babel/preset-env

私はこの問題が起こる前から jest ts-jest をインストール済みであることと、 コードの変換 · Jest に以下のように記載があることから babel-jest はインストールしていません。

Jest は、1つの transformer – babel-jest を初めから同梱しています。

babel.config.js の作成とその記述内容

babel.config.js を作成して、以下の通り記述しました。

module.exports = {presets: ['@babel/preset-env']}

jest.config.js の編集

最終的に以下の記述で上手くいきました。

/** @type {import('ts-jest').JestConfigWithTsJest} */

module.exports = {
  preset: 'ts-jest',
  transformIgnorePatterns: [
    '/node_modules/(?!(.*)/(es|esm)/)',
  ],
  transform: {
    '^.+\\.(js|jsx)$': 'babel-jest',
  },
};

Options | ts-jest には以下のように記載がありますが、私は preset の記述は残したままでも正常に実行できています。

If you are using custom transform config, please remove preset from your Jest config to avoid issues that Jest doesn't transform files correctly.

実行してみる

以下のコマンドでテストを実行して、エラーが解消されたことが確認できました。

yarn jest

transformIgnorePatterns プロパティについての補足

無視する対象を正規表現で指定します。

?! は否定先読みアサーションという正規表現です。「条件に当てはまる場合はマッチしない」という否定表現です。

参考: とほほの正規表現入門 - とほほのWWW入門

/node_modules/ ディレクトリ配下は無視する対象だが、その中の es または esm ディレクトリ配下は無視せずトランスパイルする。ということになります。

つまり es または esm ディレクトリ配下はトランスパイルされます。

transform プロパティについての補足

どのファイルをどのツールでトランスパイルするかを設定します。

.js または .jsx 拡張子のファイルを babel-jest でトランスパイルするように設定しています。