Jest の使い方
近年の Web 開発では、サーバーサイド(PHP など)ではなく、クライアントサイド(JavaScript)で処理することが多くなりました。 JavaScript の重要性が増えるに伴って、そのテストもまた重要になってきます。
Jest とは?

Jest は、Meta 社(旧:Facebook 社)製の JavaScript 用のテストフレームワークです。 シンプルさを重視して作成されており、簡単にテストを書くことができます。 シンプルながらも機能は豊富で、JavaScript でよく使われる非同期コードのテストや、コードカバレッジ解析なども簡単に行うことができます。
Jest のインストール
さっそくですがインストールしていきましょう。
npm でインストールする
npm を使ってインストールするには、下記のコマンドを実行するだけです。
基本的には開発環境で使うツールだと思いますので、--save-dev
オプションを付けておきましょう。
npm の使い方がわからないという方は、まずは「Node.js と npm の使い方(その1:概要)」を参考にしてください。
npm install --save-dev jest
インストールできたか確認する
Jest をインストールすると、jest
コマンドが使えるようになっています。
下記のコマンドを実行してバージョン番号が表示されれば、ちゃんとインストールできています。
なお、コマンドは "./node_modules/.bin" にインストールされます。
コマンドが見つからない場合は、"./node_modules/.bin" に PATH を通しておくか、
相対パスで "./node_modules/.bin/jest" と指定するか、
もしくは npx
コマンドを使用するなどの対応を行ってください。
この記事では、説明の簡略化のために "./node_modules/.bin" に PATH を通してあることを前提として説明していきます。
jest --version
ヘルプを表示する
jest
コマンドの詳しい使い方が知りたい場合は、ヘルプを表示してみましょう。
jest --help
テストの書き方
テストを書くにはいくつかルールがあります。
-
テストコードとして認識されるファイルは下記です(設定で変更可能です)。
- "__tests__" ディレクトリの中のファイル
- 拡張子に ".spec" もしくは ".test" が含まれているファイル(例:sum.test.js)
-
テストの内容は、
test()
を使用して記述します。
※it()
は、test()
のエイリアス(別名)として使用できます。 -
expect()
と Matcher を使用して、期待される値と実際の値が等しいことを確かめます。
const sum = require('./sum.js'); test('sum 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
expect() と Matcher
expect()
expect()
は値をテストしたい時に毎回使用する関数です。
引数には、判定したい実際の値を設定します。
expect()
は、Matcher と組み合わせて使用します。
Matcher
Matcher(マッチャー)は、テストしたいことが正しいかどうかを判定するための関数です。
上記の例では、.toBe()
の部分が Matcher になります。
引数には、期待する値を設定します。
Matcher にどんな関数があるかは、ここでは記載しません。 大量にありますので、公式のドキュメントを見てもらった方が良いと思います。
テストのグループ化
describe()
を使用すると、いくつかの関連するテストをまとめたブロックを作成できます。
テストをグループにまとめたい場合に便利です。
describe()
はネストすることができます。
const sum = require('./sum.js'); describe('sum', () => { test('sum 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); test('sum 2 + 3 to equal 5', () => { expect(sum(2, 3)).toBe(5); }); });
リピーティングセットアップ
各テストが実行される際、その前処理と後処理を共通化したい場合、Jest では beforeEach()
と afterEach()
という関数が用意されています。
この関数で前処理と後処理を定義すると、各テストが呼ばれる際に自動的に呼んでくれます。
beforeEach()
が前処理、afterEach()
が後処理です。
const sum = require('./sum.js'); beforeEach(() => { // テストごとの前処理 }); afterEach(() => { // テストごとの後処理 }); test('sum 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
ワンタイムセットアップ
各ファイルで1回だけ前処理と後処理を行いたい場合、Jest では beforeAll()
と afterAll()
という関数が用意されています。
この関数で前処理と後処理を定義すると、各ファイルで1回だけ自動的に呼んでくれます。
beforeAll()
が前処理、afterAll()
が後処理です。
const sum = require('./sum.js'); beforeAll(() => { // ファイルで1回だけの前処理 }); afterAll(() => { // ファイルで1回だけの後処理 }); test('sum 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
基本的な使い方
さっそく使ってみましょう。
全てのテストを実行する
jest
コマンドを実行すると全てのテストが実行されます。
オプションなどを指定する必要はありません。
jest
特定のテストのみを実行する
特定のテストのみを実行する場合は、jest
コマンドの後にファイル名の正規表現を指定します。
正規表現に一致するファイルだけが選択され、テストが実行されます。
jest tests/js/model/
特定のテスト名に一致するテストのみを実行する
テスト名というのは、テストを記述する際に describe()
、test()
、it()
の第一引数で指定した文字列のことです。
特定のテスト名に一致するテストのみを実行する場合は、jest
コマンドに、--testNamePattern
オプション指定します。
--testNamePattern
オプション には、エイリアス(別名) -t
オプションがあります。
テスト名は正規表現で指定します。
jest -t ^str
変更があったテストのみを実行する
Git もしくは Mercurial と連携し、変更があったテストのみを実行します。 Git もしくは Mercurial が使用できない場合は実行できません。
変更があったテストのみを実行する場合は、jest
コマンドに、--onlyChanged
オプション指定します。
--onlyChanged
オプション には、エイリアス(別名) -o
オプションがあります。
jest -o
ファイルの変更を監視し、自動的にテストを実行する
ファイルを変更するたびにテストを実行するのはとても面倒です。
そこで、ファイルの変更を Jest が監視し、ファイルに変更があった場合に自動でテストを実行してくれるようになるオプション --watch
と --watchAll
があります。
このオプションを付けて Jest を実行すると、ファイルに何か変更があった場合に、自動でテストが実行されるようになります。
--watch
オプションは、Git もしくは Mercurial と連携し、変更があったテストのみを実行します。
Git もしくは Mercurial が使用できない場合は実行できません。
--watchAll
オプションは、全てのテストを実行します。
監視をやめる場合は、Ctrl + C を押せば終了できます。
jest --watch
jest --watchAll
設定ファイル
Jest は、デフォルトでうまく動作すること(ゼロコンフィグ)を目指して作られていますが、 環境によっては細かい設定が必要になることもあると思います。 コマンドのパラメーターだけでも細かな設定ができるのですが、さすがに全てを指定するのは大変です。 設定ファイルを使用した方が良いでしょう。
設定ファイルのフォーマットとして JavaScript(CommonJS もしくは ES Modules)、TypeScript、JSON が使用できます。 そのため、これらの中からお好きなフォーマットを選んで作成することができます。
設定ファイルを使用する
設定ファイルを使用する方法は3つあります。
デフォルトの設定ファイルを使用する
1つ目の方法は Jest のデフォルトの設定ファイルを使用する方法です。 オプションを指定する必要はありません。
Jest は、デフォルトで現在のディレクトリから設定ファイルを探します。 この時に探されるファイルの名前は、「jest.config.js」「jest.config.ts」「jest.config.mjs」「jest.config.cjs」「jest.config.json」です。 このファイル名のどれかと一致するファイルが見つかった場合に、そのファイルが自動的に読み込まれます。
jest
--config
オプションで指定する
2つ目の方法は、--config
オプションで使用したい設定ファイルを指定することです。
複数の設定ファイルを使用して、設定を切り替えたい場合などには便利かもしれません。
--config
オプション には、エイリアス(別名) -c
オプションがあります。
jest --config=config.json
package.json に Jest の設定を記述する
3つ目の方法は、package.json に Jest の設定を記述する方法です。 package.json に "jest" の項目を作成すると、その内容が Jest の設定になります。
{ "name": "demo-app", "version": "1.0.0", "devDependencies": { "jest": "^29.3.1" }, "jest": { "collectCoverage": true } }
設定ファイルを自動で作成する
Jest の設定ファイルは、手動で作成することもできますが、自動で作成してくれる機能もあります。
自動で作成するには、jest
コマンドに --init
オプションを付けて実行します。
この際に、作成されるファイル名は「jest.config.js」になり、フォーマットは JavaScript(CommonJS)になります。
jest --init
設定ファイルの設定項目
どんな設定項目があるかは、ここでは記載しません。 大量にありますので、公式のドキュメントを見てもらった方が良いと思います。
ここでは簡単な例だけ記載しておきます。
module.exports = { collectCoverage: true, coverageDirectory: "coverage" };
コードカバレッジ解析
Jest でテストを実行したときに、テスト対象のコードのうちどれくらいの割合がテストされたかというのが分かります。 追加で何かをインストールする必要はなく、Jest をインストールするだけで使えるようになるのはスゴイです。

コマンドラインにも解析結果の概要が表示されますが、さらにもっと詳細な内容が HTML ファイルとしても出力されます。 どのファイルの、どの行が実行されていないのか、一目でわかるようになっていて便利です。


コードカバレッジ解析を有効にする
コードカバレッジ解析を有効にする方法は2つあります。
--coverage
オプションで指定する
1つ目の方法は、jest
コマンドで --coverage
オプションを指定する方法です。
jest --coverage
設定ファイルで指定する
2つ目の方法は、設定ファイルで collectCoverage
項目を指定する方法です。
true
を設定すると有効になります。
module.exports = { collectCoverage: true };
コードカバレッジレポートの出力先を変更する
コードカバレッジレポートの出力先のディレクトリは、設定ファイルの coverageDirectory
項目で指定できます。
デフォルトは "coverage" です。
その場合の HTML ファイルの出力先は "./coverage/lcov-report/index.html" になります。
module.exports = { collectCoverage: true, coverageDirectory: "coverage" };
モジュールの読み込みパスを変換する
モジュールを読み込む際に、そのモジュールの場所をパス指定する必要があります。 そのパスに相対パスを使用してしまうと、階層が深くなった場合に "../" だらけになったり、各ファイルで指定するパスの階層が異なったりしてメンテナンスが大変になります。
// 階層が深いとパスが "../" だらけになる const sum = require('../../../../../src/sum.js');
Jest では、モジュールを読み込む際のパスを正規表現で変換することができます。
モジュールを読み込む際のパスを正規表現で変換するには、設定ファイルの moduleNameMapper
項目を使用します。
<rootDir>
というキーワードを使用すると、その部分はアプリケーションのルートディレクトリに変換されます。
module.exports = { moduleNameMapper: { "^/(.*)$": "<rootDir>/$1" } };
// 変換後はどの階層からでもこう書ける const sum = require('/src/sum.js');
ES Modules を使用する
Jest の公式のサンプルや、ここまでの説明を見てもわかるように、実は Jest は CommonJS が前提になっています。 JavaScript モジュールを、CommonJS で記述している場合はそれでも問題ないかもしれませんが、 ES Modules で記述している場合は、エラーが発生してしまいます。 これは困るということで、Jest で ES Modules が動作するようにしてみたいと思います。 そもそもなぜ Jest が CommonJS 前提なのかと言えば、Node.js がそうなっているからのようです。
詳しい対応方法は 公式のドキュメント に書かれていますが、 必要なことは大きく2つです。
- Node.js に
--experimental-vm-modules
オプションを付けた状態で Jest を実行すること - Node.js に JavaScript ファイルを ES Modules として認識させること
CommonJS と ES Modules の見分け方
まずは、CommonJS と ES Modules の簡単な見分け方から。
この2つは JavaScript モジュールの記述の仕方が異なります。
module.exports
/ require
を使用するのが CommonJS で、
export
/ import
を使用するのが ES Modules です。
CommonJS (拡張子は ".js" もしくは ".cjs") |
ES Modules (拡張子は ".js" もしくは ".mjs") |
---|---|
読み込まれる側(sum.js)
function sum(a, b) {
return a + b;
}
module.exports = sum;
|
読み込まれる側(sum.js)
export function sum(a, b) {
return a + b;
}
|
読み込む側
const sum = require('./sum.js');
console.log(sum(1, 2));
|
読み込む側
import { sum } from './sum.js';
console.log(sum(1, 2));
|
Node.js に --experimental-vm-modules オプションを付けた状態で Jest を実行する
Node.js に --experimental-vm-modules
オプションを付けた状態で Jest を実行するには、下記のコマンドを実行します。
このオプションは、名前からもわかる通り実験的な機能ということで、今後変更される可能性があります。
しかしながら、いまはこのオプションを使わないといけないようです。
node --experimental-vm-modules node_modules/jest/bin/jest.js
かなり長いので、npm-scripts に登録しておくと楽だと思います(詳しくは後述)。
npm-scripts に登録
{ "name": "demo-app", "version": "1.0.0", "scripts": { "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" }, "devDependencies": { "jest": "^29.3.1" } }
Node.js に JavaScript ファイルを ES Modules として認識させる
Node.js の動作は下記のようになっています。
- ファイルの拡張子が ".cjs" なら CommonJS として扱う。
- ファイルの拡張子が ".mjs" なら ES Modules として扱う。
- ファイルの拡張子が ".js" なら package.json の "type" の値に従う(デフォルトは CommonJS)。
なので、この動作の条件を元に Node.js が ES Modules として認識できるように変更します。
方法は2つです。 環境に合わせてお選びください。
方法1:ファイルの拡張子は ".js" のまま ES Modules として認識させる
Node.js は、ファイルの拡張子が ".js" なら package.json の "type" の値に従います。
"type" の値は、CommonJS の場合は commonjs
、ES Modules の場合は module
です。
なので、"type" の値に module
を指定します。
{
"name": "demo-app",
"version": "1.0.0",
"type": "module",
"scripts": {
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
},
"devDependencies": {
"jest": "^29.3.1"
}
}
この値を変更するということは、この package.json が有効な範囲全体に影響するので注意が必要です。 つまり、モジュールとテストコード以外のファイルにも影響が及びます。 拡張子が ".js" のファイルは要注意です。ファイルの中身が CommonJS になっていた場合はエラーになります。
わかりやすい例は設定ファイルです。 例えば、Jest とは別に webpack を使用していて、その設定ファイルが "webpack.config.js" というファイル名だった場合、 そのファイルも ES Modules として扱われてしまいます。 引き続き CommonJS として扱わせたい場合は、そのファイルの拡張子を ".cjs" に変更するなどの対応が必要です。
Jest の設定ファイルが "jest.config.js" というファイル名になっていた場合も同様です。 中身を ES Modules に変更するか、ファイルの拡張子を ".cjs" に変更するか、いっそのこと JSON に変更してしまうかなど、対応が必要になります。
方法2:ファイルの拡張子を全て ".mjs" に変更する
こちらの方法は、全体に影響がない代わりに、モジュールとテストコードのファイルの数に比例して修正箇所が増えます。
Node.js は、ファイルの拡張子が ".mjs" なら ES Modules として扱います。
なので、モジュールとテストコードのファイルの拡張子を全て ".mjs" に変更します。
import
文でファイルパスに拡張子を付けて指定している場合は、そちらも修正が必要です。
次に、Jest が拡張子 ".mjs" をテストコードとして認識できるように、Jest の設定ファイルを変更します。
デフォルトの状態では、".mjs" を認識してくれません。
どのファイルがテストコードとして認識されるかは、testMatch
項目で指定できます。
module.exports = { testMatch: [ "**/__tests__/**/*.mjs", "**/?(*.)+(spec|test).mjs" ], };
裏技:webpack でバンドルする
Jest で ES Modules を動かすための裏技として、モジュールとテストコードを webpack でバンドルしてしまうという方法があります。 webpack でバンドルしてしまえば、CommonJS か ES Modules かなんて関係がなくなりますから、Jest で動作させることができます。
しかし、この方法は簡単ではありますが Jest のコードカバレッジ解析ができなくなるというデメリットがあります。 また、いちいちバンドルしなければならないという手間も発生します。
コードカバレッジ解析なんていらないぜ!って方は、解決策の1つになるかもしれません。
webpack の使い方がわからないという方は、「webpack の使い方」を参考にしてください。
npm-scripts に登録する
jest
コマンドですが、各種オプションなどを毎回入力するのは面倒に感じてくると思います。
そこで、よく使うコマンドを npm-scripts に登録しておくと、入力の手間が少なくなって便利です。
npm-scripts では、"./node_modules/.bin" に PATH が通っているので、"./node_modules/.bin" を入力したり、npx
コマンドを使用したりする必要はありません。
npm-scripts の使い方がわからないという方は、「Node.js と npm の使い方(その3:npm-scripts)」を参考にしてください。
npm-scripts に登録
{ "name": "demo-app", "version": "1.0.0", "scripts": { "test": "jest" }, "devDependencies": { "jest": "^29.3.1" } }
npm-scripts を実行する
npm run test
オプションを追加したい場合は、--
で繋ぐと追加できます。
npm run test -- --watch