使用#all时如何在水豚中等待

How to wait in Capybara when using #all

我知道 wait_until 由于某种原因已从水豚中删除。 Capybara 擅长等待,用find 等待很好,但在处理AJAX 应用程序时,有时我不得不使用all 方法。例如,我正在处理 HTML table,我可以通过单击列名称对其进行排序。当我对列名应用排序然后调用 all(td, text: column_name) 它 returns 排序之前存在的值,因为 all 方法不像 find 方法那样等待做。我目前正在使用定制助手 wait_for_ajax 来处理此类情况。我不想传递额外的 :wait 参数。有更好的处理方式吗?

如果您正在测试应用程序,那么这相对容易,因为您知道测试数据,所以您可以像

expect(page).to have_css('table tr:first-child', text 'text first in order when sorted')

这将等待 table 的第一行出现排序后应首先出现在排序顺序中的文本。

如果您正在 screen-scraping 或测试您不知道测试数据的应用程序,那么它会变得更加困难。当您对列进行排序时,除了行的顺序之外,页面上是否有任何变化?是否有排序指示器、排序列 header 突出显示等?如果是这样,您可以等待它,假设它在列更新之前实际上没有更新(如果它在单击后立即更新,那么这将不起作用,并且可能实际上是一个错误 UI因为您最终可能会遇到数据不一致的情况)。例如,如果 header 列获得 'sorted' 的 class,您可以执行类似

的操作
expect(page).to have_css('table th td.sorted', text: 'text of the column header you sorted by')

这将等待正确的 header 指示它已排序。

如果确实没有任何变化表明排序已完成,那么您就不走运了,您遇到了极少数应该使用 wait_for_ajax 之类的情况之一。

注意:在这种情况下,传递 :wait 选项对您完全没有帮助。这是因为它是等待找到匹配元素的 最大 时间量,并且 #all 有效匹配 0 个元素 - 它仍然会立即 return (没有另一个答案中提到的任何计数选项,正如您指出的那样,无论如何在这里对您没有帮助)

我正在使用它在触发事件之前加载所有 HTML 内容。只要你想指定等待就可以调用这个方法

def wait_for_ajax
  Timeout.timeout(Capybara.default_wait_time) do
    loop do
      active = page.evaluate_script('jQuery.active')
      break if active == 0
    end
  end
end

这是 wait_for_ajax 方法实际上是正确选择的极端情况之一。这是我的实现,它不使用 Tom 建议的 Timeout 可能会导致错误。

def wait_for_ajax
  start = Time.now.tv_sec
  stop = false
  until stop do
    active = page.evaluate_script('jQuery.active')
    if active == 0
      stop = true
    elsif (Time.now.tv_sec - start) > Capybara.default_max_wait_time
      stop = true
      raise Exception.new("WaitForUrlError: Timed out waiting for url: #{url}")
    end
  end
end