jestでimport文を使うには


環境

・jest ^26.5.3
・babel-jest ^26.6.0
・@babel/core ^7.7.5
・@babel/preset-env ^7.7.6

babelrc
{
  "presets": [
    "@babel/preset-react",
    ["@babel/preset-env", {
      "targets": {
        "node": "current",
        "ie":11,
        "safari":9
      },
      "useBuiltIns": "usage",
      "corejs": 3,
      "modules": false
    }],
  ],

babelrcの初期設定がこんな感じになっています。

なぜimport/exportが使えないのか

上記設定のままだと、jestでimport/export(es6)文を実行することはできません。
jestでは require系のcommonjsしか使えないためです。
なので、 babelの処理で es6 -> commonjsへの変換を行う必要があります。

es6 -> commonjsに変換するには?

鍵を握るのは、 @babel/preset-envのoptionの modulesの項目です。
現在falseで設定しています。
falseだと、moduleの読み込み系の文を変換しない、つまりimport/export文はそのままなので
jestでエラーが出ているというわけです。

これを、 NODE_ENVでの切り替えを行い、 jestでテストしている時だけes6->commonjsに変換する
という風に設定します。

jest用のNODE_ENV

実はjestはデフォルトでtest用のNODE_ENV testが設定されています。

jestの中身
if (process.env.NODE_ENV == null) {
process.env.NODE_ENV = 'test'
}

なので、こちらで jest NODE_ENV=test と設定する必要はなく、
jest コマンドだけでbabelrcの処理を分岐させることが可能です。

babelrc
{
  "presets": [
    "@babel/preset-react",
    ["@babel/preset-env", {
      "targets": {
        "node": "current",
        "ie":11,
        "safari":9
      },
      "useBuiltIns": "usage",
      "corejs": 3,
      "modules": false
    }],
  ],
  "env": {
+   /* ここから下がjest用の処理 */
+    "test": {
+      "presets": [
+        "@babel/preset-react",
+        ["@babel/preset-env", {
+          "targets": {
+            "node": "current",
+            "ie":11,
+            "safari":9
+          },
+          "useBuiltIns": "usage",
+          "corejs": 3,
+          "modules": "cjs"
+        }]
+      ]
+    }
  }
}

NODE_ENVtestの場合は、 "modules": "cjs" に設定しています。
(cjsはcommonjsの略です)

jestがbabelでコンパイルされるようにする

上記作業だけではまだes6->commonjs変換を行うことはできません。
jest実行時にbabelでコンパイルするよう指示する必要があります。
jest実行時のconfigファイルはデフォルトではjest.config.jsですので、
jest.config.jsを作成します。

jest.con
module.exports = {
  verbose: true,
  transform: {
    '^.+\\.js$': 'babel-jest',
  },
  moduleFileExtensions: ['js'],
};

babel-jestパッケージをインストールします。
このパッケージがbabelでのコンパイルを行ってくれます。
https://www.npmjs.com/package/babel-jest

$ npm i -D babel-jest

以上でOK! 動作チェック

exporter.js
export async function addCalcFun(baseValue, addValue) {
  return baseValue + addValue;
}
importer.spec.js
import { callErrorFun } from './exporter'

describe('エラー', () => {
  it('通常のエラー', () => {
    expect(callErrorFun(2+2)).toBe(5)
  })
})

$ npx jest importer.spec.js

問題なく設定できていれば、上記の処理がうまく走ります🎉

参考資料

https://qiita.com/riversun/items/6c30a0d0897194677a37
https://tech.bitbank.cc/lets-test-by-jest/
https://qiita.com/hogesuke_1/items/8da7b63ff1d420b4253f#importexport%E6%A7%8B%E6%96%87%E3%82%92%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84%E5%95%8F%E9%A1%8C%E3%81%AE%E5%AF%BE%E5%87%A6