LoginSignup
19
11

More than 5 years have passed since last update.

Ionicにユニットテスト(Jest)の環境を作る

Last updated at Posted at 2018-03-04

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の設定ファイルを作る

プロジェクトのルートディレクトリに作ります。おまじないみたいなものです。

jest.config.js
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ディレクトリの直下に作ります。おまじないみたいなものです。

src/setupJest.ts
import 'jest-preset-angular';
import './jestGlobalMocks'; // browser mocks globally available for every test
src/jestGlobalMocks.ts
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']
});
src/tsconfig.spec.json
{
  "extends": "../tsconfig.json",
  "include": [
    "**/*.spec.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}

package.jsonを編集する

テストを実行するためのコマンドを用意します。

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のテストを書いてみた

simple.service.spec.ts より

simple.service.spec.ts
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)のテストを書いてみた

welcome.spec.ts より

welcome.spec.ts
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
> (←入力を受け付ける状態になる)

ここでコードを貼り付けるとスクリプトが実行されてファイルが生成されます。楽ちんですね。

19
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
11