LoginSignup
3
2

More than 5 years have passed since last update.

Bootstrap3のコンポーネントを使うテストを安定させる方法

Last updated at Posted at 2017-07-12

課題:poltergeistのテストが安定しない

Bootstrap3のモーダル系を使ったテストがpoltergeistの気分次第で落ちる:ghost:
sleepで調整しても終わりがないので、それを是正したい。

改善策:JavaScriptでフラグを立てて管理する方式にする

Capybara Poltergeist で Bootstrap3 のモーダルを使ったテストが失敗する

という記事を読んで、これはいいなぁと思ったので参考にすることに。
自分の場合は、モーダルが表示されたときよりもモーダルが消える前にテストが評価しようとして落ちたりしたので、そっちをなんとかしたかった。ついでにモーダル以外のも定義しときたかった(後で追加するの面倒)ので、いろんなイベントに対応できるようにメタプログラミングでメソッドを作るようにした。

(2018-07-03 追記)
wait_until_hidden_backdropを定義しました。hidden.bs.modalが走った後でも、モーダルダイアログの背景(透過の黒背景)が画面を覆っている場合があったので、追加しました。wait_until_hidden_bs_modalの中で背景が消えるまで待つという処理を入れてみたのですが、モーダルから更にモーダルを呼び出したりすると初回のモーダルの影響で背景が消えなくて処理が終わらずタイムアウトエラーになったので、個別に使うようにしています。

wait_until_bootstrap3_components.rb
module WaitUntilBootstrap3Components

  def self.define_wait_bootstrap3_event(event_name)
    event_name_underscore = event_name.gsub('.', '_')
    event_name_camelcase = event_name_underscore.camelize
    define_method :"wait_until_#{event_name_underscore}" do |&b|
      script = <<~EOS
        window._capybara#{event_name_camelcase} = 1;
        jQuery(document).one("#{event_name}", function(){ window._capybara#{event_name_camelcase} = 0; });
      EOS
      page.execute_script(script)
      b.call unless b.nil?
      Timeout.timeout(Capybara.default_max_wait_time) do
        loop until page.evaluate_script("window._capybara#{event_name_camelcase}").zero?
      end
    end
  end

  def wait_until_hidden_backdrop
    Timeout.timeout(Capybara.default_max_wait_time) do
      loop until page.all('.modal-backdrop').blank?
    end
  end

  def self.included(_)
    %w(popover modal tooltip collapse dropdown tab).each do |component_name|
      %w(shown.bs hidden.bs).each do |event_prefix|
       define_wait_bootstrap3_event("#{event_prefix}.#{component_name}")
      end
    end
    %w(loaded.bs.modal closed.bs.alert slid.bs.carousel inserted.bs.tooltip inserted.bs.popover).each do |event_name|
     define_wait_bootstrap3_event(event_name)
    end
  end
end

RSpec.configure do |config|
  config.include WaitUntilBootstrap3Components, type: :feature
end

使い方

Bootstrap3で使われるイベント名の._に変換して、メソッドの接頭辞にwait_until_をつけるという感じです。

# モーダルが開き終わるのを待つ
wait_until_shown_bs_modal do
  click_button "モーダルを表示する"
end
# モーダル上で作業する

# モーダルが閉じるのを待つ
wait_until_hidden_bs_modal do
  click_button "閉じる"
end

感想

よく落ちていた箇所のテストがこれで安定するようになったので、bootstrap3を入れているプロジェクトにどんどん適用していきたい所存。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2