Phantom.js+QUnitでjavascriptの自動テスト環境を作りたい
Phantom.jsって何?
PhantomJS is a headless WebKit with JavaScript API.
- [PhantomJS: Headless WebKit with JavaScript API ](http://phantomjs.org/)
他に特徴は?
色んなテストフレームワークに対応
jasmine, capybara, QUnit, mocha, webdriver, yui test, busterjs, funcunit, robot framework
他のCUIブラウザと比べて軽い
ブラウザの動作をエミュレートしている訳ではない為
導入
自分の環境は、MacPortsなので、手動でインストール
$ wget http://phantomjs.googlecode.com/files/phantomjs-1.7.0-macosx.zip $ unzip phantomjs-1.7.0-macosx.zip $ cd phantomjs-1.7.0-macosx $ bin/phantomjs -v 1.7.0
簡単。
jsを使って動かす
まずは、hello world
console.log('hello, world!'); // メインスレッドが終わっても終了しないので、 // 明示的に終わらせる必要がある phantom.exit();
$ bin/phantomjs test.js Hello, world!
ページを読み込む
var page = require('webpage').create(); page.open('http://google.com', function () { // ページのキャプチャ page.render('google.png'); phantom.exit(); });
標準だと、594x442px でレンダリングされてる
page.viewportSizeでサイズの変更が可能
page.viewportSize = { width: 480, height: 800 };
内部でjavascriptも動くの?
onloadで、div id="test" に、文字列を表示する、htmlを用意して実験
<html> <head> <meta charset="utf-8"> <title>title</title> <script> window.onload = function(){ document.getelementbyid("test").innerhtml='test'; } </script> </head> <body> <div id="test1"></div> </body> </html>
test.js にて、htmlを読み込んで、onloadで表示されるdiv id="test"の中の文字列を取得して表示する
var page = require('webpage').create(); page.open('01.html', function () { // ページアクセス setTimeout(function(){ console.log( // ページ内でJSを動かすメソッド page.evaluate(function () { return document.getElementById("test").innerHTML; }) ); phantom.exit(); }, 1000); });
$ bin/phantomjs test.js test
うごいた!
イベント送受信
今度はこんなHTMLを用意
div id="test" をクリックすると、confirmが出て分岐
// 〜 中略 〜 window.onload = function(){ document.getElementById("test").addEventListener("click", function(){ if(confirm("click?")){ alert("yes"); }else{ alert("no"); } }); } </script> </head> <body> <div id="test">click me!</div> </body> </html>
var page = require('webpage').create(); page.open('01.html', function () { // ページアクセス page.onConfirm = function(msg){ // confirm発生時にトリガ console.log("confirm : "+msg); return true; // 真偽値でOK、キャンセルを決める } page.onAlert = function(msg){ // アラート発生時にトリガ console.log("alert : "+msg); } page.includeJs("jquery.min.js", function(){ // jQueryをinclude var offset = page.evaluate(function(){ // リンクのoffsetを取得 return $("* test").offset(); }); page.sendEvent('click', offset.left+1, offset.top+1); // クリック }); });
$ bin/phantomjs test.js alert : jquery.min.js * includeJs完了時に、alertイベントが飛んでるっぽい confirm : click? alert : yes
イベントを受け取って、confirmでyesを選択している
ちなみに、confirmを受け取らない場合、デフォルトでは「いいえ」を選択している様子
QUnit連携
- javascriptのunitテストフレームワーク
- Qunitを、Phantom.js で実行させることが可能
- 全てCUIで実行できるので、CI環境に持ち込むのが簡単
連携には、examples/run-QUnit.js を使う
試しに、QUnitのテストをPhantom.jsで実行してみる
$ examples/run-QUnit.js ../jquery-QUnit-4e03a4b/test/index.html; echo $1 'waitfor()' finished in 1901ms. tests completed in 1771 milliseconds. 596 tests of 596 passed, 0 failed.bin/phantomjs 0
- 成功の場合、戻り値は0
- 失敗の場合は、1を返す
まとめ
- 内部的には、QUnitをopenして、結果を出力するDOMをウォッチしているだけなので、ちょっといじれば、エラーが発生したテストを出力するとかできそう
- 戻り値を返すので、Jenkinsへの組み込みも簡単にできそう
- 全ブラウザのテストは無理だけど、CIに組み込めるのが良いと思った
- デザイナさんがjavascript書いて、テストもQUnitで書くという状況ならば、Phantom.js と組み合わせて、CIに組み込むのがベター?