Riot.jsについて
Riot.js 2.0 情報まとめを見るととてもよく分かると思う。
ブラウザ以外でもtagを動かしたい
ガイド見る限りブラウザ上でriot.mount
を実行することが前提のように書かれていて、tag単位のユニットテストが辛い。ユニットテストやるとして、Node.jsの上で動かしたい。
しかし、ブラウザ上で動いているもの相当のrequire('riot/riot')
を単純にNode.js上で実行しても、DOMが存在しない環境なのでブロックされriot.mount
やriot.tag
が生えない。
ということはつまり、Node.js上でもDOM実装さえ適切に与えれば、riot.mount
が実行可能になる。Node.jsでDOM操作といえば、jsdomである。jsdomは外部からJavaScript片を注入できるので、以下のような記述が動く。
jsdom = require('jsdom')
fs = require('fs')
riot = fs.readFileSync(require.resolve('riot/riot'), 'utf-8')
jsdom.env
html: '<div><foo /></div>'
src: [riot]
done: (errors, window) ->
console.log(window.riot.mount) # => Function
tagファイルはコンパイルするとriot.tag
を実行するjsファイルに化けるので、このまま続けて注入できる。
tagをテストする
例えばこんなtagがあるとして、
<foo>
<h3>{ opts.bar }</h3>
<p>{ baz }</p>
</foo>
jsdomを使えばこんな感じでテストもできる。今回はtapeを使ったがmochaでも何でも問題ないはず。
jsdom = require('jsdom')
fs = require('fs')
riot = fs.readFileSync(require.resolve('riot/riot'), 'utf-8')
compiler = require('riot')
tag = compiler.compile(fs.readFileSync('./foo.tag', 'utf-8'))
test = require('tape')
test (t) ->
t.plan(3)
jsdom.env
html: '<div><foo /></div>'
src: [riot, tag]
done: (errors, window) ->
[foo] = window.riot.mount('foo', bar: 'baz')
document = window.document
t.equal(document.querySelector('h3').innerHTML, 'baz')
t.equal(document.querySelector('p').innerHTML, '')
foo.update(baz: 'qux')
t.equal(document.querySelector('p').innerHTML, 'qux')
これで表示と変更はテストできた。
$ coffee test/foo.tag.test.coffee
TAP version 13
# (anonymous)
ok 1 should be equal
ok 2 should be equal
ok 3 should be equal
1..3
# tests 3
# pass 3
# ok