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の設定を行っているため、目を通しておくと良い。