JSDOMはnode環境でDOMをシミュレートするやつ。React.addons.TestUtilsはReactに同梱されているテストツール。この2つがあわさり最強に見える。
今作ってるライブラリのために、しばらくブラウザ使わずにテストしてたけど、ブラウザ立ち上げる必要なくて非常に快適。これ https://github.com/mizchi/arda/tree/master/test
JSDOM、昔はとにかく不安定な印象だったけど、最近はよくできてる印象。見なおした。
コード
# globalにdocumentとwindowを定義することで、DOM環境を参照できるようにする
# 必ずReactの前に読み込むこと
jsdom = require('jsdom').jsdom
global.document = jsdom('<html><body></body></html>')
# global.window = document.parentWindow # 追記 jsdom v4.0で parentWindow -> defaultView
global.window = document.defaultView
global.navigator = window.navigator
# TestUtilsを使うためにreact/addonsを読み込む
React = require 'react/addons'
# 0.13.0-beta.1 以降で使える ES6 Class記法
# ※ 別にReact.createClassでも良いがgetInitialStateになる
class HelloComponent extends React.Component
constructor: ->
super
@state = cnt: 0
render: ->
React.createElement 'button',
className: 'counter'
ref: 'counter'
onClick: @onClick.bind(@)
, 'cnt:'+@state.cnt
onClick: ->
@setState cnt: @state.cnt+1
# アサーション
assert = require 'assert'
# renderIntoDocumentはDOMにマウントせずcomponentを生成する
# ただしDOM環境は必要
component = React.addons.TestUtils.renderIntoDocument React.createFactory(HelloComponent)()
assert.equal component.refs.counter.getDOMNode().innerHTML, 'cnt:0'
# クリックをシミュレート
React.addons.TestUtils.Simulate.click component.refs.counter.getDOMNode()
# 再レンダーされているか確認
assert.equal component.refs.counter.getDOMNode().innerHTML, 'cnt:1'
# もう二回ぐらい叩いてみる
React.addons.TestUtils.Simulate.click component.refs.counter.getDOMNode()
React.addons.TestUtils.Simulate.click component.refs.counter.getDOMNode()
# 確認
assert.equal component.refs.counter.getDOMNode().innerHTML, 'cnt:3'
実はちょっと前まで動かなったけど、最近動くようになった。
ReactTestUtils.Simulate.click does not work with jsdom · Issue #1185 · facebook/react https://github.com/facebook/react/issues/1185
懸念点
jsdom v3.3.1 がまだ io.js v1.1.0でビルドできないので node v0.10を使った。jsdomの初期化、ちょっとだけ時間かかって、テストの実行のたびに0.6秒ぐらい必要。まあPhantomよりは遥かにマシ。