かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その44 )( Jest で setTimeout の処理のテストを書く )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その43 )( Jest で jQuery.ajax の処理のテストを書く ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Jest で setTimeout の処理のテストを書きます。

参照したサイト・書籍

  1. Jest - Timer Mocks
    https://facebook.github.io/jest/docs/en/timer-mocks.html

目次

  1. Jest を 21.2.1 → 22.0.4 へバージョンアップする。。。は IntelliJ IDEA 2017.3.3 待ちでした
  2. setTimeout の処理のテストを書く
    1. テストで使用するモジュールを作成する
    2. テストを書いて実行する
  3. 次回は。。。

手順

Jest を 21.2.1 → 22.0.4 へバージョンアップする。。。は IntelliJ IDEA 2017.3.3 待ちでした

IntelliJ IDEA を 2017.3.2 へバージョンアップしたので、改めて npm install --save-dev jest@22.0.4 コマンドを実行して Jest を 22.0.4 へバージョンアップします。

f:id:ksby:20171229160345p:plain

Form.test.js のテストを実行してみます。。。が、失敗しました。前と同じ No tests found というメッセージが出ますね?

f:id:ksby:20171229175716p:plain

もしかしてまだ修正されていないのかと思い、IntelliJ IDEA の次の EAP のページを IDEA 2017.3 EAPIntelliJ IDEA 2017.3 173.4301.1 Release Notes と見てみると、Bug WEB-30377 wrong test pattern when running single Jest test, 'no tests found' が見つかりました。どうも修正されるのは次の 2017.3.3 のようです。

npm install --save-dev jest@21.2.1 コマンドを実行して元に戻すことにします。

また今回試している時に気づきましたが、Java のテストと同様に Ctrl+Shift+T を押すとテスト対象のモジュールのファイルとテストのファイルの間を行ったり来たりできました。

setTimeout の処理のテストを書く

テストで使用するモジュールを作成する

src/main/assets/js/lib/util の下に delayExecutor.js というファイルを新規作成し、以下の内容を記述します。

"use strict";

let id = undefined;

module.exports = {

    /**
     * 指定された時間経過後に実行する関数を登録する
     * @param {Function} fn - 遅延実行する関数
     * @param {number} milliSeconds - 関数 fn を遅延実行する時間(ミリ秒)
     */
    register: function (fn, milliSeconds) {
        if (id !== undefined) {
            this.cancel();
        }
        id = setTimeout(fn, milliSeconds);
    },

    /**
     * 登録されている遅延実行関数をキャンセルする
     */
    cancel: function () {
        if (id !== undefined) {
            clearTimeout(id);
            id = undefined;
        }
    }

};

テストを書いて実行する

src/test/assets/tests/lib/util の下に delayExecutor.test.js というファイルを新規作成し、以下の内容を記述します。

"use strict";

global.$ = require("jquery");
const delayExecutor = require("lib/util/delayExecutor.js");

jest.useFakeTimers();

describe("delayExecutor.js のテスト", () => {

    function setSampleValue() {
        $("#sample").val("サンプル");
    }

    function setTestValue() {
        $("#sample").val("テスト");
    }

    beforeEach(() => {
        document.body.innerHTML = `
            <input type="text" name="sample" id="sample" value="">
        `;
    });

    test("delayExecutor.register で関数を登録すると指定した時間経過後に実行される", () => {
        delayExecutor.register(setSampleValue, 2000);
        expect($("#sample").val()).toBe("");
        jest.runAllTimers();
        expect($("#sample").val()).toBe("サンプル");
    });

    test("delayExecutor.cancel を呼び出せば指定した時間を経過しても実行されない", () => {
        delayExecutor.register(setSampleValue, 2000);

        // ここで jest.advanceTimersByTime(...) を呼び出して、
        // 少しだけ時間を経過させたかった。。。

        delayExecutor.cancel();
        expect($("#sample").val()).toBe("");
        jest.runAllTimers();
        expect($("#sample").val()).toBe("");
    });

    test("delayExecutor.register は最後に登録した関数だけが実行される", () => {
        delayExecutor.register(setSampleValue, 2000);
        delayExecutor.register(setTestValue, 1000);

        expect($("#sample").val()).toBe("");
        jest.runAllTimers();
        expect($("#sample").val()).toBe("テスト");
    });

});

テストを実行すると成功しました。

f:id:ksby:20171230020511p:plain

やっぱり setTimeout のテストを書くなら jest.advanceTimersByTime が使いたいかな。。。

次回は。。。

番外編で以下の3つを書いてみる予定です。

  • axiosNock でテストを書いてみる
  • MobX を使ってみる(このモジュールを使えば jQuery でも状態管理ができるらしいのでちょっと興味が湧きました)
  • Flow を使ってみる(Javascript を書いていると型が欲しいと切実に思いますが、これか Typescript を使えば型がある書き方ができるらしいので試してみます)

その後に Gradle の build タスクで Javascript の build +テストを一緒に実行する方法を調べてから、入力画面3以降の作成に移る予定です。

履歴

2017/12/30
初版発行。