一人もくもく会 α verでサービス開始しました。
請求書作成システム α verでサービス開始しました。

mochaとPhantomJSでjavascriptのテスト

開発中のWEBサイトのjavascriptのテストをコンソールで自動化するシンプルなプロジェクトを作成した。

使い方だが

  1. dala00/test_by_phantomjsをクローン
  2. npm install
  3. npm test

でspecフォルダの全てのテストが走る。

ライブラリ

PhantomJS

画面表示のないブラウザ。これでコンソールでの自動化を実現。 ただし、PhantomJSを起動してテストを実行しなければならないため その他のライブラリはrequireで読み込める事が条件。 色々調べた結果下記のライブラリに落ち着いた。

mocha

テストパッケージ。本当は使えないのだが、

feb0223/mocha-phantom

の偉業により使用可能に。

chai

アサーションライブラリ。多分他のでも大丈夫だと思う。

テストプログラム解説

specフォルダにサンプルでSampleSpec.jsを入れてあるので解説。

var webpage = require('webpage');
var page = webpage.create();

PhantomJSのオブジェクトを作成。これはPhantomJS起動でないとrequireできないので今回の構成に決まった。 起動方法はtest.jsを見れば書いてある。test.js内で全部のプログラムを起動しているだけ。

before(function(done) {
    // 指定したページをオープン
    page.open('http://url.for.test/', function(status) {
        if (status !== 'success') {
            console.log('error!');
            phantom.exit();
            return;
        }
        done();
    });
});

URLを開く。失敗したらphantom.exit()する。 とにかく終わるときはexitしないとプロセスが残ってプログラムが終了しないので注意。

it('Fade out', function(done) {
    var oldDisplay = page.evaluate(function() {
        var ret = $('#closePanel').css('display');
        $('#closeButton').trigger('click');
        return ret;
    });
    var display;
    wait.for(function() {
        display = page.evaluate(function() {
            return $('#closePanel').css('display');
        });
        return display != oldDisplay;
    }, function() {
        expect(display).to.not.equal(oldDisplay);
        done();
    });
});

実際のテスト部分。page.evaluate内は完全に別世界となる。 そこではブラウザ上のjavascriptを操作できる。 (むしろそれしかできない。スコープも関係ない) return することでこっち側の世界に値を持ってこれる。

つまり上記は

  1. まず初期のdisplayの状態をoldDisplayに取得しつつ閉じるボタンもクリックしておく
  2. wait.forはひとつ目の関数がtrueになるまで待つ。displayの状態が変わるまで待つ。 上手く動かない場合はタイムアウト(3つ目の引数指定可能)でもウェイト終了。
  3. wait.forのふたつ目の関数が実行されて終了。

wait.forはPhantomJSに入っていたサンプルのwaitforを改造しただけのもの。 setTimeoutだと動作が遅い場合テスト失敗になってしまうのでこの方法を採用。 他の類似ライブラリでもいいと思う。

specフォルダにファイルはいくらでも追加できるのでちょっとしたテストには充分。 ブラウザ側のjavascriptがそのまま使えるのでSelenium WebDriverより記述も簡単だと思う。 execしてstdoutを取得しているだけなのでtest.jsを改造すればテスト結果の集計なども可能なはず。