yaakaito.org

Buster-html-docとあとcoffee

BusterJS, CoffeeScript, JavaScript, Testing

こんにちは!うきょーです。 前回BusterJSのtestbedの話を書いたのですが、

@yaakaito HTMLを用意するまでもない場合は buster-html-doc とかも良いと思いますがどうでしょう!

という意見をもらったので、こっちのことも書いておこうと思いました。

そもそもbuster-html-docって何

BusterJSはJSTestDriver形式で書かれたテストケースの実行をサポートしているのですが、JSTestDriverにHTML Docという昨日があります。 この部分だけをBusterJS用に切り出したのがbuster-html-docで、前回のようにHTMLを用意するまでもない場合に

1
2
/*:DOC hoge = <p>aaaa</p>*/
assert.equals(this.hoge.innerHTML, 'aaaa');

という風にテスト毎にエレメントを生成することができます。

使い方

buster-html-docをnpmからインストールします。

1
$ npm install buster-html-doc

buster.jsでbuster-html-docを読み込むようにします。

1
2
3
4
5
6
7
8
9
var config = module.exports;

config["browser test"] = {
  env : "browser",
  tests : [
    "test.js"
  ],
  extensions: [require("buster-html-doc")] // これ
}

こういう感じにテストを書きます。

1
2
3
4
5
6
buster.testCase('hoge', {
  'test html doc' : function() {
      /*:DOC hoge = <p>aaaa</p>*/
      assert.equals(this.hoge.innerHTML, 'aaaa');
  }
})

これでテストを実行すると、テスト時に/*:DOC hoge = <p>aaaa</p>*/の部分が、

1
2
3
4
5
6
7
this.hoge = (function () {
  var element = document.createElement("div");
  element.innerHTML = "<p>aaaa</p>";if (element.childNodes.length > 1) {
      throw new Error("HTML doc expected to only contain one root node, found " + element.childNodes.length);
  }
  return element.firstChild;
}());

という感じに変換されます。 あとはこのエレメントを使ってアサーションするなりできます。

上の例ではthis.hogeに対してエレメントを生成していますが、 そうではなくbodyとかに突っ込んでほしい場合は、+=を使って書く事もできます。

1
2
/*:DOC += <p id="hoge">aaaa</p>*/
assert.equals(document.getElementById('hoge').innerHTML, 'aaaa');

という感じなのがbuster-html-docプラグインです。

buster-coffee

続いてbuster-coffeeなのですが、名前の通りテスト実行時にCoffeeScriptをコンパイルしてくれるので、コードをCoffeeScriptで書けるよ、というものです。 これ自体は特にめんどくさくなくて、npmでインストールして、

1
$ npm install buster-coffee
1
2
3
4
5
6
7
8
9
var runner = module.exports;

runner["browser test"] = {
  env : "browser",
  tests : [
    "test.coffee" // coffee
  ],
  extensions: [require("buster-coffee")]
}

という風に使えばよいのですが、buster-html-docと少し相性の問題があるみたいで、

1
extensions: [require("buster-coffee"), require("buster-html-doc")]

こういう感じにして、

1
2
3
4
buster.testCase 'hoge',
  'test html doc' : ->
      ###:DOC hoge = <p>aaaa</p>###
      assert.equals(this.hoge.innerHTML, 'aaaa');

こう書いても、

TypeError: Cannot read property ‘innerHTML’ of undefined

となります。

コンパイルされるとHTML Docの部分は

1
2
/*:DOC hoge = <p>aaaa</p>
*/

こうなるはずなので、一見大丈夫そうに思えるんですが、うまくいきません。 というか自分でコンパイルするとちゃんと動くので、プラグインの実行順か、それぞれの実行タイミングが悪いのかみたいな話だと思います。

ハマりやすいので気をつけましょう。

回避策としてはプラグインのところ見直してプルリクエストが一番早そうなんですが、 僕は他の理由もあって先にcoffeeを別にコンパイルするようにしてしまいました。

おまけ

HTML Doc形式の書式が結構便利で、最近関わっているプロダクトだと

1
2
3
4
5
6
###:XHR /hoge = {
 fuga : 'fuga',
 piyo : 'piyo'
} 
###
# /hoge にアクセスしたらこのレスポンスが返ってくる (XHR部分のラッパー有)

みたいにして通信部分をモックできるようしてみた、便利。