2016年07月25日

Rspec実行時はJSのアニメーションをOFFにする

Feature specを流していると、100%ではないけどたまに落ちるspecがあったりします。
原因は色々あると思うのですが、もしそこでJSが使われている場合はアニメーションによる時間差のエラーを疑うのはいかかでしょう?というのが今回のお話しです。

アニメーションとspec

こんな動作をするページがあったとします。

  1. ボタンをクリックする
  2. みょいーんと要素がアニメーションし、要素が現れる

具体的にはこのページのような動作です

たったこれだけなのですが、specでテストする際に面倒なことになる可能性があります。
例えば↑の画面をfeature specでテストすると以下のようになると思います

  1. find(".button").click (ボタンを見つけて押す)
  2. expect(page).to have_content "要素" (画面内に特定の要素がある)

とても簡単なspecなので一見通りそうなのですが、実はアニメーションが邪魔して通らない恐れがあります。
spec上ではこんなことが起こる可能性があるからです。

  1. find(".button").click (ボタンを見つけて押す)
  2. (アニメーションが動作を始める)
  3. expect(page).to have_content "要素" (アニメーションが終わる前に検証されてしまう)
  4. Element not found エラーなど (要素が見つからないためエラー)

タイミングの問題なので、これでも通るかもしれませんが、通ったり通らなかったりするのは気持ち悪いので対策します。

対策1:アニメーションをOFFにする

おそらくこれが一番簡単なのではないでしょうか。
jQueryにはアニメーションをOFFにできるメソッドがあるので、これを使います。

specでこれを実行するには以下のように書きます。

def disable_jquery_animation
  page.execute_script("$.fx.off = true;")
end

こいつをアニメーションが発生するボタンを押す前に実行することでアニメーションがOFFになるので、上記タイミング問題は発生しなくなります。
(完全に0秒になるわけではないので、もしかしたら待ち時間が必要になるかもしれません。)

対策2:sleep処理を入れる

これはspecが遅くなるのであまり推奨はされないと思われます。

ボタンをクリックした後に

sleep 3

などと書いて待ち時間を入れ、アニメーションが終わるまで待つようにする方法です。
基本的に使わない方が無難です。

最後に

specは奥が深すぎて結構はまったりするので、何かあったらメモしておきたいです。