Tech Sketch Bucket of Technical Chips by TIS Inc.

Jasmine/QUnitのテスト中にスクリーンキャプチャするプラグイン

Pocket

JavaScriptに対する自動テストツールも充実し、Jenkinsなどを用いてCIをまわす人も増えてきました。
しかし、レスポンシブレイアウトや、Floatのレイアウト崩れなど、人間が見ればすぐに分かる「見た目」に関する問題は、自動テストによる判定がし辛いのが実情です。
この記事では、この問題を解決するために作成した、テスト中にスクリーンキャプチャを取るためのプラグイン「phantom-capture」を紹介します。


現状の問題点

JasmineQUnit といったテストフレームワークや、 PhantomJS , sinon.js といったツールの助けを借りることで、JavaScriptの自動テストが行えるようになり、サーバ側だけではなく、クライアント側にも自動テストを適用する人が増えてきています。

ビジネスロジックやバリデーション、DOMの構築結果などは問題なくテストすることができますが、人間には容易に判別できるレスポンシブレイアウトや、Floatのレイアウト崩れなどの場合、DOM自体にはなんら問題が無いため、自動テストでチェックするのは難しいところです。

「見た目は単体テストじゃなくて、後で見るから......」というのもありですが、せっかくなら「見た目」もテストしてみませんか?
この記事ではJasmine/QUnitのテスト中から関数呼び出し一つでスクリーンキャプチャが取得できる phantom-capture について紹介していきます。

想定する環境

この記事で示す手順は以下の環境で動作確認を行いました。既にPhantomJS上でJavaScriptのテスト環境を整えている方であれば、特に新しいものは無いかと思います。

サーバ AWS ec2 m1.small
OS Amazon Linux AMI 64bit
テスト実施用仮想ブラウザ PhantomJS 1.9.1
テストフレームワーク Jasmine 1.3.1 / QUnit v1.13.0pre
キャプチャ用プラグイン phantom-capture

phantom-captureの機能

phantom-captureで追加される機能はスクリーンキャプチャの取得に特化しており、phantom.capture関数を呼び出すだけでキャプチャを取得することができます。

phantom.capture

書式

phantom.capture(filename, [options])

パラメータ

  • filename: 取得したキャプチャ画像を保存するパス
  • options: キャプチャ時のオプション
    • width: ウィンドウの幅(デフォルトは320px)
    • height: ウィンドウの高さ(デフォルトは480px)
    • verbose: キャプチャ内容を標準出力に出力する(デフォルトはfalse)

phantom-captureの使用例

Runnerスクリプトへの組み込み

Jasmineのテストコードからキャプチャする場合の例

QUnitのテストコードからキャプチャする場合の例

環境構築

それでは、実際にサンプルのテストを動かしてphantom-captureを使ったスクリーンショットを取得してみようと思います。
既にPhantomJS上でJasmine/QUnitによる自動テストを行っている人は、インストール部分を飛ばして3番から進めてください。

1. gitのインストール

phantom-captureを含む幾つかのライブラリはgithubで公開されているため、まずはgitをインストールします。

2. PhantomJSのインストール

PhantomJSは 公式ページ で64bit用のバイナリが公開されているため、ダウンロードして解凍するだけで使用できます。

3. phantom-capture(とサンプルソース)の配置

4. 単純なサンプルを用いてテストの実行

ボタンを押すとdiv要素のサイズが大きくなるだけの単純なサンプルを用いてテストを実行し、スクリーンキャプチャが取得できることを確認してみたいと思います。
このサンプルではJasmine/QUnitのテストコードによって、拡大メソッドを呼び出しながらスクリーンキャプチャを撮影しています。

実行時に、Jasmineの場合は jasmine-reporters 、QUnitの場合は QUnit本体 のRunnerスクリプトを使用しています。

横幅320pxで撮影した場合の例

base.png

5. jQuery Mobileと連携させたサンプルを用いてテストの実行

続いてjQuery Mobileとの連携を行いながらスクリーンキャプチャを撮影するサンプルです。
テスト対象のページがレスポンシブレイアウトを実装しているため、同じページをキャプチャしても撮影時のウィンドウサイズによって文言や背景色が変わることがわかります。

横幅320pxで撮影した場合の例

second320.png

横幅640pxで撮影した場合の例

second640.png

phantom-captureの仕組み

実際に撮影することができたので、中身の仕組みを軽く見ていきたいと思います。
まず、PhantomJSを用いてJavaScriptの自動テストを行う場合、基本的な流れは以下の図のようになります。
phantomjs-test.png

phantom-captureを使ってスクリーンキャプチャを取得する場合は、上記の流れに加えて、runnerスクリプトからプラグインを読み込みます。
Jasmine/QUnitのテストはPhantomJSの中に構築されたwebpageの中で実行されますが、これは単なる仮想ブラウザのため、webpageの中からスクリーンキャプチャを取得することはできません。スクリーンキャプチャを取得する機能はPhantomJSの機能となっているため、初期化時にwebpageとPhantomJSの橋渡しを行う関数を自動的に追加します。 (下図a)
これによってwebpageの世界から、PhantomJSの世界にあるキャプチャ用メソッドを呼ぶことができるようになり、JasmineやQUnitのテストケースからphantom.capture関数を呼ぶことができるようになっています。 (下図b)

phantomjs-test2.png

既知の問題点

日本語への対応、及びフォントが違うことによるズレ

Amazon AMIにはデフォルトでは日本語対応フォントが含まれて居ませんが、yumリポジトリからIPAフォントをインストールすることで日本語を表示してスクリーンキャプチャを行うことが可能です。

しかし、Windowsで使われているMS ゴシックなど、規約によってインストールできないフォントもあるため、テキストのサイズによって要素の幅、高さが決まるようなレイアウトの場合、使用されるフォントが異なることによって細かいズレが生じることがあります。

ブラウザエンジンによるズレ

だいぶマシになったとは言え、Webシステムの鬼門であるブラウザ依存を避けることはできません。
PhantomJSはQtWebkitエンジンによるレンダリングを行うため、IE向けシステムを作る場合などはキャプチャに頼り切るのは危険です。開発中はphantom-captureによるスクリーンキャプチャを使用し、最終的にはSeleniumや目視による確認をした方が安全でしょう。

まとめ

PhantomJSのキャプチャ機能は手軽に使えてなかなか面白い機能です。
今回のようにテスト結果のズレ確認に使うこともできますし、SVGやCanvasに対応しているため、JavaScriptで描画されたグラフを画像としてダウンロードするような用途にも使用できます。特定サイトを定期的に画像化して時系列に見てみるなんてのも面白いかもしれませんね。

エンジニア採用中!私たちと一緒に働いてみませんか?