Help us understand the problem. What is going on with this article?

RSpec+Capybaraでajaxとかcssとかを待つ

More than 1 year has passed since last update.

以下のようにちょっと待たないとテストが通ったり通らなかったりすることに対する対策です。

  • ajaxの処理完了を待ちたい
  • なんらかのDOM操作などをして要素が表示される(または消える)のを待ちたい

ググればいろいろと既に対策法は出ているのですが、この2つがあればなんとか事足りそうだったので、自分なりにちょこっと改良したバージョンです。

参考:
Capybaraでsleep地獄から抜け出すための便利なメソッド
Automatically Wait for AJAX with Capybara

rails_helper.rbの下記コメントアウトが外れていること。

spec/support/rails_helper.rb
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

下記2つのファイルをspec/supportの配下に入れます。

spec/support/wait_for_css.rb
module WaitForCss
  # cssが表示されるまで待つ
  def wait_for_css_appear(selector, wait_time = Capybara.default_max_wait_time)
    Timeout.timeout(wait_time) do
      loop until has_css?(selector)
    end
    yield if block_given?
  end

  # cssが表示されなくなるまで待つ
  def wait_for_css_disappear(selector, wait_time = Capybara.default_max_wait_time)
    Timeout.timeout(wait_time) do
      loop until has_no_css?(selector)
    end
    yield if block_given?
  end
end

RSpec.configure do |config|
  config.include WaitForCss, type: :system
end
spec/support/wait_for_ajax.rb
module WaitForAjax
  # ajaxが完了するまで待つ
  def wait_for_ajax(wait_time = Capybara.default_max_wait_time)
    Timeout.timeout(wait_time) do
      loop until finished_all_ajax_requests?
    end
    yield if block_given?
  end

  def finished_all_ajax_requests?
    page.evaluate_script('jQuery.active').zero?
  end
end

RSpec.configure do |config|
  config.include WaitForAjax, type: :system
end

使い方

spec/system/expamle_test.spec
RSpec.feature "DirectMessage", type: :system do
  scenario "待つテスト", js: true do
    click_button "#something1を表示するボタン"
    wait_for_css_appear("#something1") do
      # なんらかの検証処理
    end

    click_button "#something2を消すボタン"
    wait_for_css_disappear("#something2") do
      # なんらかの検証処理
    end

    click_button "ajaxをキックするボタン1"
    wait_for_ajax do
      # なんらかの検証処理
    end

    click_button "ajaxをキックするボタン2"
    wait_for_ajax # => ブロックを渡さずただ処理完了を待つことも可
    # なんらかの後続処理
  end
end

デフォルトでCapybara.default_max_wait_time(変えてなければ2秒)の間待ち続け、タイムアウトするとTimeout::Errorになります。タイムアウト時間を任意に設定したい場合は、

wait_for_css_appear("#something1", 5)
wait_for_ajax(5)

みたいにすると良いです。

johnslith
アイ アム リス
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away