13

我有一个失败的 Rails 集成测试,我不知道为什么。我正在使用 Capybara 和 Selenium 作为驱动程序。

该测试检查页面内容是否在 AJAX 调用发生后被删除。相关的操作是单击按钮,并且该按钮单击会导致页面的一部分通过 jQueryremove()调用被删除。这是集成测试代码的近似值:

click_button("Remove stuff")
assert has_no_link?("This should be removed")

断言失败,意味着链接仍然存在。

我一直在阅读 Capybara,我知道您可以延长默认等待时间。我已经将它扩展到一个荒谬的值(20 秒),但断言仍然失败。

当我自己手动执行测试过程时,页面仍然显示内容,但DOM没有(通过查看 Firefox 的 DOM Inspector 并查找元素)。这是问题吗?我什至尝试在 Firefox 中运行测试检查 DOM以检查内容是否存在,但似乎不存在。

我不知道 Capybara 是如何找到这个不再存在于 DOM 中的链接的。Capybara 是否检查源而不是 DOM 并在那里找到链接?如果是这样,我不知道如何修复此测试以确保测试通过。刷新页面可以解决问题,但这并不是用户会做的事情,所以我犹豫是否要更改页面只是为了让测试通过......

希望有任何关于如何解决这个问题的建议。

谢谢!

4

7 回答 7

3

Thoughtbot 有一篇很棒的关于等待 AJAX 的博文,你可以在这里阅读,虽然它是基于 Rspec 的,而且看起来你正在使用 TestUnit。

它适用于 Capybara 等待时间不够长但不会添加不必要的长时间超时的情况。我现在主要在 Rspec 中工作,但我认为您可以通过以下方式对其进行修改:

# Create this file in test/support/wait_for_ajax.rb
module WaitForAjax
  def wait_for_ajax
    Timeout.timeout(Capybara.default_max_wait_time) do
      loop until finished_all_ajax_requests?
    end
  end

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

您可以在需要时将其包含在单个测试文件中,也可以使用此 SO 帖子中提供的策略之一来自动包含它。

然后,每当您的测试未正确等待 AJAX 完成时,只需插入wait_for_ajax. 以您的代码为例:

click_button("Remove stuff")
wait_for_ajax
assert has_no_link?("This should be removed")
于 2016-06-09T21:26:22.137 回答
1

有一些称为 wait_until 的方法,但它最近已被弃用,并使用 synchronize 方法进行了更改。

http://www.elabs.se/blog/53-why-wait_until-was-removed-from-capybara

https://github.com/jnicklas/capybara/blob/master/lib/capybara/node/base.rb#L44

目前还不知道具体怎么用,等待作者解答,希望能尽快解决这个问题

于 2013-01-30T15:17:37.350 回答
0

有一种检查 ajax 请求是否完成的好方法,我从这篇文章中学到了这一点。wait您可以使用 ajax$.active函数(不在实际 API 中,但已公开,因此您可以使用它) ,而不是使用某个特定时间。$.active告诉您与服务器的活动连接数,因此当它降至零时,您就知道 ajax 请求已完成:

wait_until do
  page.evaluate_script('$.active') == 0
end

如果这不起作用,那么问题出在其他地方(从你写的内容来看,这似乎很可能)。如果更改只发生在 DOM 中,那么您必须确保为您的测试/规范启用了 javascript。例如,在 rspec 中,您设置:js => true这样做;在 Cucumber 中,您在场景上方添加一行@javascript. 我不使用 rails 的默认测试,但必须有一个设置来做同样的事情。

于 2012-09-23T22:16:11.600 回答
0

您始终可以手动执行此操作。使用@shioyama 的想法:

  def wait_for_ajax
    timer_end = Time.now + 5.seconds 
    while page.evaluate_script('$.active') != 0    
      if Time.now > timer_end
        fail "Page took more than 5 seconds to load via ajax"
      end 
      sleep 0.1
    end
  end
于 2014-05-20T15:02:39.243 回答
0

我想到的几种方法:

1:检查您的水豚版本并查找您的版本的任何错误

2:也许在单击按钮后尝试在链接上进行查找

click_button("删除东西") find(:xpath, '//a[text()='链接应该被删除').should be_false

3:使用has_link?而不是 has_no_link?

click_button("删除东西") page.has_link?("链接应该被删除").should be_false

于 2014-01-10T18:07:44.117 回答
0

我必须重写 wait_until 进行测试,该测试涉及等待通过将 youtube 视频流式传输到某个点而触发的回调。这是我使用的:

# in spec_helper.rb
require "timeout"
def wait_until time=0.1
    Timeout.timeout(Capybara.default_wait_time) do
        sleep(time) until value = yield
        value
    end
end
于 2013-12-26T22:49:16.783 回答
0

您是否首先使用链接测试其他内容,然后测试它是否已被删除?

换句话说,您的测试是否类似于:

has_no_link = $('#id_for_link')
//.... some test
click_button("Remove stuff")
assert has_no_link?("This should be removed")

如果是这种情况,那么 has_no_link 仍将指向该链接。remove() 会将其从 DOM 中删除,但您的变量仍指向内存中的它。

您应该在 DOM 中再次查询该链接以查看是否得到结果。

于 2013-12-14T16:41:39.760 回答