AngularのテスティングフレームワークはJasmine + Karmaがデフォルトで用意されている。便利な半面実行が遅く、効率よくフィードバックを得ながらテストを書くにはリズムが悪い。
解決策として、世界で今最も支持されているであろうJestを使用すれば、Angularのユニットテストの実行は格段に早くなる。
この記事ではAngularアプリケーションにJestを適用する方法を紹介したいと思う。
Jestとは?
JestはFacebookが開発しているJavaScriptのテスティングフレームワーク。
ユニットテストの実行速度が早いことに加えて、スナップショットテストや強力なモック機能など使い勝手が良く、最近では一番使われているテスティングフレームワークです。
Jasmineと同じく expect(a).toBe(true)
といったBDDスタイルのアサーションなので、導入ハードルは比較的低い。
Jestへの変更
Angular CLIでテスティングフレームワークをJestに置き換えるnpmパッケージ(Angular Schematics)が公開されているので、これを使う。
https://github.com/briebug/jest-schematic
はじめにnpmパッケージをグローバルにインストールする。
$ npm install -g @briebug/jest-schematic
次にAngularプロジェクトにターミナルで移動して以下のコマンドを実行。
$ ng g @briebug/jest-schematic:add
実行すると不要なファイルは削除され、Jestなどの必要なパッケージのインストールと以下のファイルが生成される。
- jest.config.js
- src/setup-jest.ts
- src/test-config.helper.ts
次に関連ファイルの修正を行う。
src/tsconfig.spec.json
types
を "jasmine"
から "jest"
に変更する
{ "compilerOptions": { "outDir": "../out-tsc/spec", "types": [ "jest", // jasmine -> jest に変更 "node" ], "module": "commonjs" }, }
src/setup-jest.ts
2行目以降を削除して以下に書き換える。
import 'jest-preset-angular'; import './jest-global-mocks';
src/jest-global-mocks.ts
を新規作成して以下の内容を記述する。
/* global mocks for jsdom */ const mock = () => { let storage: { [key: string]: string } = {}; return { getItem: (key: string) => (key in storage ? storage[key] : null), setItem: (key: string, value: string) => (storage[key] = value || ''), removeItem: (key: string) => delete storage[key], clear: () => (storage = {}) }; }; Object.defineProperty(window, 'localStorage', { value: mock() }); Object.defineProperty(window, 'sessionStorage', { value: mock() }); Object.defineProperty(window, 'getComputedStyle', { value: () => ['-webkit-appearance'], }); Object.defineProperty(window, 'CSS', {value: null}); Object.defineProperty(document, 'doctype', { value: '<!DOCTYPE html>' }); Object.defineProperty(window, 'getComputedStyle', { value: () => { return { display: 'none', appearance: ['-webkit-appearance'] }; } }); /** * ISSUE: https://github.com/angular/material2/issues/7101 * Workaround for JSDOM missing transform property */ Object.defineProperty(document.body.style, 'transform', { value: () => { return { enumerable: true, configurable: true, }; }, }); /* output shorter and more meaningful Zone error stack traces */ // Error.stackTraceLimit = 2;
ここではMock用の設定をまとめている。
合わせて @types/jest
もインストールしておく。
$ npm i -D @types/jest
基本はこれで完了。
テストの実行
テストの実行はコマンドが書き換えられているので、 npm test
を実行すればいい。
$ npm test
また上記は単発の実行で、 npm run test:watch
でwatchモードで実行できる。自分は package.json を書き換えて npm test
でwatchするようにしている。
{ "scripts": { ... "test": "jest --watch", ... }, }
テストを走らせる場合は大体watchしながら走らせるので、test:watch
のほうは消してしまっていいと思う。
Jestの設定
jest-schematicの中では以下のJest presetを利用してJestの設定を行っているため、目を通しておくと良い。