Ionic CLIでプロジェクトを作るとなぜかユニットテスト環境が用意されません。実はこれ昔からそうで、いつか用意されるだろうと思って2年ぐらい経ちましたが全くそういう気配がありません。
じゃあAngular CLIで用意されるKarmaの環境を持ち込もうと思ってもボイラープレートがやたら多くて勘弁してくれよとなります。(個人の感想)
なので色々調べたらJestの環境がさくっと作れるっぽいのでやってみました。
今回のリポジトリは https://github.com/ovrmrw/ionic-super-template-pwa-jest-prettier です。(余談ですがPrettierの設定も組み込んでいます)
多分早ければ1分くらいで環境作れます。
Ionic CLIでプロジェクトを作る
ionic start
コマンドでプロジェクトを作ります。
$ ionic start myApp super
これでSuper Starterというてんこ盛りのテンプレートからプロジェクトが作成されます。
Jestをインストールする
$ cd myApp
$ npm install -D jest-preset-angular jest @types/jest
このjest-preset-angular
というやつがいい感じに色々やってくれます。
Jestの設定ファイルを作る
プロジェクトのルートディレクトリに作ります。おまじないみたいなものです。
module.exports = {
preset: 'jest-preset-angular',
roots: ['src'],
testRegex: '\\.spec\\.ts$',
setupTestFrameworkScriptFile: '<rootDir>/src/setupJest.ts',
transformIgnorePatterns: ['node_modules/(?!@ngrx|@ionic-native|@ionic)']
};
Jestの実行時に読み込むファイルを作る
これらのファイルはsrcディレクトリの直下に作ります。おまじないみたいなものです。
import 'jest-preset-angular';
import './jestGlobalMocks'; // browser mocks globally available for every test
const mock = () => {
let storage = {};
return {
getItem: key => (key in storage ? storage[key] : null),
setItem: (key, value) => (storage[key] = value || ''),
removeItem: key => delete storage[key],
clear: () => (storage = {})
};
};
Object.defineProperty(window, 'localStorage', { value: mock() });
Object.defineProperty(window, 'sessionStorage', { value: mock() });
Object.defineProperty(window, 'getComputedStyle', {
value: () => ['-webkit-appearance']
});
{
"extends": "../tsconfig.json",
"include": [
"**/*.spec.ts"
],
"exclude": [
"node_modules"
]
}
package.jsonを編集する
テストを実行するためのコマンドを用意します。
(省略)
"scripts": {
(省略)
"test": "jest",
"test:w": "jest --watch",
"test:ci": "jest --runInBand"
},
(省略)
環境構築終わり
Jestによるユニットテストの環境構築はこれで全てです。
コードは全てコピペでOKなので手間と言えるほどの作業は一切ありません。
※おまじないファイルを一括生成するスクリプトも用意しました。
https://qiita.com/ovrmrw/items/a25a229da02a6dbe2603#%E8%BF%BD%E8%A8%98
Serviceのテストを書いてみた
import { TestBed } from '@angular/core/testing';
import { SimpleService } from './simple.service';
describe('SimpleService', () => {
beforeEach(() =>
TestBed.configureTestingModule({
providers: [SimpleService]
})
);
describe('with injection', () => {
let simpleService: SimpleService;
beforeEach(() => {
simpleService = TestBed.get(SimpleService);
});
it('add', () => {
const expected = 3;
const actual = simpleService.add(1, 2);
expect(actual).toBe(expected);
});
it('subtract', () => {
const expected = -1;
const actual = simpleService.subtract(1, 2);
expect(actual).toBe(expected);
});
});
});
add()
とsubtract()
という関数を持つServiceの簡単なテストです。
Component(Page)のテストを書いてみた
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { IonicModule, NavController } from 'ionic-angular';
import { WelcomePage } from './welcome';
const mockNavController = {
push: jest.fn()
};
describe('WelcomePage', () => {
beforeEach(() =>
TestBed.configureTestingModule({
declarations: [WelcomePage],
imports: [IonicModule.forRoot(WelcomePage), TranslateModule.forRoot()],
providers: [{ provide: NavController, useValue: mockNavController }],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents()
);
describe('with injection', () => {
let fixture: ComponentFixture<WelcomePage>;
let welcomePage: WelcomePage;
beforeEach(() => {
fixture = TestBed.createComponent(WelcomePage);
welcomePage = fixture.componentInstance;
});
afterEach(() => {
jest.resetAllMocks();
});
it('should be created.', () => {
expect(welcomePage).toBeTruthy();
});
it('when login function is called.', () => {
welcomePage.login();
expect(mockNavController.push.mock.calls.length).toBe(1);
expect(mockNavController.push.mock.calls[0]).toEqual(['LoginPage']);
});
it('when signup function is called.', () => {
welcomePage.signup();
expect(mockNavController.push.mock.calls.length).toBe(1);
expect(mockNavController.push.mock.calls[0]).toEqual(['SignupPage']);
});
});
});
ComponentのテストはServiceより記述量が多くなりますが、やっていることは
- インジェクトしているService(NavController)をモックする。
- DIコンテナからComponentのインスタンスを取得してテストする。
- インスタンスが生成されていることの確認。
- NavContollerの
push()
が指定した引数を伴って呼ばれていることの確認。
これだけです。
まとめ
JestでComponentのテストもできることがわかりました。
環境構築はあっという間にできるのでIonic CLIがやってくれるとありがたいのですが。
※全体的に参考にしたのは https://github.com/datencia/ionic2-jest-example です。
追記
おまじないファイルを一括生成するスクリプトを用意しました。
上記のJSファイルのコードをコピーして、プロジェクトのルートディレクトリで
$ node
> (←入力を受け付ける状態になる)
ここでコードを貼り付けるとスクリプトが実行されてファイルが生成されます。楽ちんですね。