2013-02-23

SpookyJS & mochaでnode.jsのクライアントサイドテスト

SpookyJS + Mocha


MochaはNode.jsでも動くJavaScriptテストフレームワーク。
SpookyJSとは、PhantomJSというHeadless Webkit(GUIのないWebkit的なもの)を、クライアントサイドのテストUtilityとして使えるCasperJSをNode.jsで使えるようにしたモノです。

やりたいことと構成

Node.jsのプロジェクト(express)上でMocha使ってやってるBackendのテストと一緒に、FrontendのテストもSpookyJS経由で行う。


経緯

この前試したZombie.jsがうまくいかないみたいなので別の方法を探したというわけです。。


やってみよう!!

Mocha

Mochaのインストールとか簡単なhello world

// install mocha
// $ npm install -g mocha
// hello mocha
describe('test describe', function() {
it('test contents', function() {
assert.ok(true);
});
});
// run mocha
// $ mocha -R spec testfile.js
view raw hellomocha.js hosted with ❤ by GitHub


導入としてこのサイトも参考にしました。
http://d.hatena.ne.jp/hokaccha/20111202/1322840375
今回はassertionをshouldでやってるけど、元々使ってるのもあってexpectを採用してます。

PhantomJS

インストールはmacなのでHomebrew。
$ brew install phantomjs

実行とかは公式なQuickStartが良かった。
https://github.com/ariya/phantomjs/wiki/Quick-Start

CasperJS

こちらもHomebrewで。

$ brew install casperjs

APIなどはSpookyJSで使えるものと大体同じ、というかこちらが本家なのでAPIリファレンスをちゃんと見ておくと良いです。むしろSpookyの方にドキュメントが殆ど無い。。

http://casperjs.org/api.html#casper

SpookyJS 

インストールはnpmでできます。
$ npm install spooky

入れた時にnode_module/spooky/template?だったかにsampleがあったのでnodeコマンドで実行して試せます。

その他環境

SpookyJSでunderscoreなど必要みたいなので、package.jsのdependenciesをこんな感じで書く。

"dependencies": {
 "express": "3.0.6",
 "jade": "*",
 "mocha": "*",
 "expect": "*",
 "spooky": "*",
 "underscore": "*"
}


spookyHelper.js

ヘルパーを作っておいて、テストスクリプトから呼べるようにしておきます。

var Spooky = require('spooky'),
_ = require('underscore');
function setup(context, done) {
var spooky = context.spooky = new Spooky(context.config, function(err) {
if(err) {
var e = new Error('Failed to initialize Spooky.js');
e.details = err || error;
throw e;
}
spooky.debug = true;
spooky.fails = [];
spooky.on('error', function(e) { console.error(e);});
spooky.on('console', function(line) {
console.log(line);
if(line.match(/FAIL/)){
spooky.fails.push(line);
return;
}
});
spooky.on('log', function(log) {
if(log.space === 'remote') {
console.log(log.message.replace(/ \- .*/, ''));
}
});
done();
});
}
module.exports.before = function(context) {
context.config = _.defaults(context.config || {}, {
casper: {
verbose: true,
logLevel: 'debug'
}
});
return function(done) {
setup(context, done);
}
}
module.exports.after = function(context) {
return function(done) {
context.spooky.removeAllListeners();
context.spooky.destroy();
done();
};
}
view raw spookyHelper.js hosted with ❤ by GitHub


spookyMochaTest.js

spookyHelper.jsを使って、spooky + mochaを実現してるコード。

var express = require('express');
var app = express();
// setup server
app.get('/', function(req, res){
res.send('hello spooky');
});
module.exports = app;
// start spooky test
describe('Frontend tests', function() {
describe('homepage', function() {
var context = {};
var hooks = require('./spooky_helper');
var fails = [];
var server = app.listen(4000, function() {});
before(hooks.before(context));
afterEach(function() {
if(!this.ok) this.test.error(new Error(fails));
});
it('should return a 200 OK status', function(done) {
var self = this;
self.ok = true;
// spooky flow start.
context.spooky.start();
context.spooky.open('http://localhost:4000/');
context.spooky.then(function() {
// casper API
this.test.assertHttpStatus(200, 'successfully received 200 OK');
});
// spooky flow end.
function onComplete() {
if ( context.spooky.fails.length > 0 ) {
fails.push(context.spooky.fails);
self.ok = false;
}
done();
}
context.spooky.on('run.complete', onComplete);
context.spooky.run(function() {
this.test.done(1);
});
});
});
});


こっからは、SpookyJS(CasperJS)のAPIゴリゴリ使って、テストを書いてく感じ。
CasperJSの使い方については、また書けたら書きます。







2013-02-20

Zombie.jsでクライアントサイドのテストしてみる




Zombie.js is headless browser.


Zombie.jsはnode.jsで動くクライアントサイトテストフレームワーク。またはユーザーインターフェースを持たないブラウザです。
コレを使ってクライアントサイドのテストが書けます。

Hello Zombie.js


すっごく簡単に使ってみる。(神戸蘭子のアメブロ見てtitleタグ確認するだけ。)


var Browser = require("zombie");
var assert = require("assert");
browser = new Browser();
browser.on('error', function(error) {
console.log(error);
});
// Load the page from AmebaBlog.
browser.visit("http://ameblo.jp/ran-ran-k/", function (err, browser, statusCode) {
// Return true if the status code is 2xx.
assert.ok(browser.success);
// Return the text contents of the selected elements.
assert.equal(browser.text('title'), '神戸蘭子オフィシャルブログ「神戸蘭子の☆diary☆」by Ameba');
});
view raw hello-zombie.js hosted with ❤ by GitHub

こんな感じ。

browser.successでstatusCodeが200かどうかをnodeのAPI、assert.okを使ってチェック。
browser.textでCSSセレクタ使って見つけたエレメントを取得して、assert.equalでチェック。


その他


form入力とかもできる。


browser.
fill("email", "zombie@underworld.dead").
fill("password", "eat-the-living").
pressButton("Sign Me Up!", function() {
// Form submitted, new page loaded.
assert.ok(browser.success);
assert.equal(browser.text("title"), "Welcome To Brains Depot");
})
view raw zombie-form.js hosted with ❤ by GitHub
pressButtonとか、clickLinkとか、色んなAPIがあるみたい。

調べてる途中なのだけど、JavaScript使ってDOM生成したエレメントが見れないぽい。。

どうやったらええんや…。

2013-02-18

SublimeText2でEmmet入れたらコケた件


久々にブログを書いた動機


SublimeText2でZenCoding使ってたら機能不全に陥ってしまっていたのでremove packageして、Emmetを入れてみた時のメモ。

現象


 ctrl + shift + pでEmmetをインストールして再起動したら下記のエラーが出た。
Error while loading PyV8 binary: exit code 4
from https://github.com/emmetio/pyv8-binaries
PyV8ってのが足らんらしい。


対処

  1. githubのリンクを辿って行くと下部のREADMEにPyV8のOS別ダウンロードリンクがあったのでそこから自分のOS用のファイルをDLし解凍。
  2. SublimeText2でctrl+shift+p -> "Browse Packages..." を開いて、解凍したフォルダを移動。
  3. SublimeText2を再起動。

その他設定など


Emmetを入れただけだと日本語使えないらしいので、下記サイトを参考に設定変更。

勉強会があったらしい。使い方など。

スニペットの変更はココ
/Users/username/Library/Application Support/Sublime Text 2/Packages/Emmet/emmet/snippets.json

ZenCodingの時と一緒で、langの設定変えたい時等はココで変更できる。