JestをES6化してimport/exportを使う方法
NODE_OPTIONS: experimental-vm-modulesを使う
関連記事:
Jestのサンプルコードを見ると
(。´・ω・)ん?
と思うことがある。
function sum(a, b) {
return a + b;
}
module.exports = sum;
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
(・・? なんでCommonJS方式なの?
exports/requireがCommonJS、
一方import/exportがES6だ
世の中ES6で動いてるのに、
Jestだけ置いてけぼりになっている状態なの?
ちょっと調べてみたが、
NodeJSの仕様に合わせてそうしているようだ。
それはちょっとなぁ~と思ったら、
どうやら最近サポートされたようだ。
NodeJS側で (^_^;)
正確にはNodeJSのexperimental-modulesオプションにて対応していたが、
v13.2.0でそれが外れpackage.jsonのtype定義、あるいは--input-typeオプション、
拡張子をmjsにするなどでES Moduleが使えるようになるそうだ。
ただ、これとJestでのサポートは別のようで、
experimental-vm-modulesオプションは必須。
ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪
------------------- ↓ 本題はここから ↓-------------------
ESモジュール化
こちらを参照
NODE_OPTIONSを設定
NODE_OPTIONSにexperimental-vm-modulesというオプションを追加する。
Windowsユーザーはcross-envを使うと良いらしい
特定のコマンドに追加するほうがいいので以下のように設定
export NODE_OPTIONS=--experimental-vm-modules
反映
source ~/.bashrc
確認
env | grep -i 'node'
NODE_OPTIONS=--experimental-vm-modules
package.jsonの調整
package.json上のtypeディレクティブにモジュールを追記する。
拡張子をmjsとしてる場合でも必要っぽい
{
・・・
"type": "module"
}
コード調整
サンプルをimport/exportに書き換える
defaultに名前つける意味はちょっとわからん。
const sum = (a, b) => {
return a + b
}
export default sum
import sum from './sum.js'
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3)
})
テスト実行
npx jest sum.test.js
(node:9379) ExperimentalWarning: VM Modules is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
PASS ./sum.test.js
✓ adds 1 + 2 to equal 3 (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.479 s
Ran all test suites matching /sum.test.js/i.
問題なさそう
------------------- ↓ 後書はここから ↓-------------------
package.jsonの調整
上記は.bashrcで調整したが、
CIなどに加えることを考えるとコマンド自体を弄るほうがいい。
"scripts": {
"test": "NODE_OPTIONS=--experimental-vm-modules npx jest",
"test.watch": "NODE_OPTIONS=--experimental-vm-modules npx jest --watchAll"
},
npm test sum.test.js
moduleが定義されてないと怒られる場合
既存のテストをmoduleに変更すると以下のようなエラーが出る。
NODE_OPTIONS=--experimental-vm-modules npx jest sum.test.js
ReferenceError: module is not defined
at file:///home/dozo/tmp/tests2/jest.config.js:6:1
at ModuleJob.run (node:internal/modules/esm/module_job:154:23)
at async Loader.import (node:internal/modules/esm/loader:166:24)
at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15)
at async readConfigFileAndSetRootDir (/home/dozo/tmp/tests2/node_modules/jest-config/build/readConfigFileAndSetRootDir.js:126:32)
at async readConfig (/home/dozo/tmp/tests2/node_modules/jest-config/build/index.js:217:18)
at async readConfigs (/home/dozo/tmp/tests2/node_modules/jest-config/build/index.js:406:26)
at async runCLI (/home/dozo/tmp/tests2/node_modules/@jest/core/build/cli/index.js:230:59)
at async Object.run (/home/dozo/tmp/tests2/node_modules/jest-cli/build/cli/index.js:163:37)
これはjest.config.jsがCommonJS形式で書かれているのが原因
これを
module.exports = {
・・・・
}
こう書き換えよう
export default {
・・・・
}
jest.config.jsを削除してjest --initを打ち直してもいい
その際ファイル名はjest.config.mjsとなっている
ExperimentalWarningが気になる
Jest実行すると以下のワーニングが常に出てくる
(node:5995) ExperimentalWarning: VM Modules is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
まぁ、一行だけならいいのだが、
テストの数だけ出てくるので結構うっとうしい。
方法としてはwarningを消すことだろう。
NODE_OPTIONS='--experimental-vm-modules --no-warnings' npx jest
開発でワーニング消すなど以ての外だが、
テストランナーだけだから問題はないだろう。
Discussion
不要な情報かもしれませんが、
私は、テストコードの方も、プロダクトコードと同じように
WebPack(やBabel)でビルドしてからJestに流すというようにしています。
そうすると、node は CommonJS 前提ですが、自分で CommonJS 書く必要がなくなり
テストコード側が ESModules 使っても問題なく
プロダクトと同じ仕組みで同じ構文が使えたりします。
プロダクトと揃えるのならばそれでいいと思います。