我有一个失败的Rails集成测试,我无法弄清楚原因。我正在使用Capybara和Selenium作为驱动程序。
在进行AJAX调用后,测试会检查页面内容是否已被删除。相关操作是单击一个按钮,单击该按钮会导致页面的一部分通过jQuery remove()
调用删除。以下是集成测试代码的近似值:
click_button("Remove stuff")
assert has_no_link?("This should be removed")
断言失败,暗示链接仍然存在。
我一直在阅读Capybara,我知道你可以延长默认的等待时间。我把它扩展到一个荒谬的值(20秒),但断言仍然失败。
当我自己手动关注测试过程时,页面的源仍显示内容,但 DOM 不显示(通过查看Firefox的DOM Inspector并查找元素)。这是问题吗?我甚至尝试检查DOM ,而测试在Firefox中运行,以检查内容是否存在,并且看起来不是。
我不知道Capybara如何在DOM中找到不再存在的链接。 Capybara是在检查源而不是DOM并在那里找到链接吗?如果是这样,我不知道如何修复此测试以确保测试通过。刷新页面可以解决问题,但这不完全是用户会做的事情,所以我犹豫改变页面只是为了让测试通过......
会喜欢有关如何解决此问题的任何建议。
谢谢!
答案 0 :(得分:3)
Thoughtbot有关于等待AJAX的精彩博文,您可以阅读here,虽然它基于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
您可以在需要时将其包含在单个测试文件中,也可以使用this SO post中提供的某种策略自动将其包含在每个测试文件中。
然后,只要您的测试没有正确等待AJAX完成,只需插入行wait_for_ajax
即可。以您的代码为例:
click_button("Remove stuff")
wait_for_ajax
assert has_no_link?("This should be removed")
答案 1 :(得分: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
目前我不知道如何使用它,但我正在等待作者回答我的问题,所以我希望尽快解决这个问题
答案 2 :(得分:0)
有一种巧妙的方法来检查ajax请求是否已完成,这是我从this article学到的。您可以使用ajax wait
函数(not in the actual API but is exposed来代替$.active
,而不是$.active
,因此您可以使用它。 wait_until do
page.evaluate_script('$.active') == 0
end
告诉您与服务器的活动连接数,因此当它降至零时,您就知道ajax请求已完成:
:js => true
如果这不起作用,那么问题就出在其他地方(根据你所写的内容来判断)。如果更改仅发生在DOM中,那么您必须确保为您的测试/规范启用了javascript。例如,在rspec中,您设置@javascript
来执行此操作;在Cucumber中,您可以使用{{1}}在方案上方添加一行。我不使用rails的默认测试,但必须有一个设置来做同样的事情。
答案 3 :(得分: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中查询链接,看看是否得到了结果。
答案 4 :(得分: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
答案 5 :(得分:0)
我想到了几种方法:
1:检查您的水豚版本并查找您的版本
的任何错误2:也许在单击按钮后尝试在链接上进行查找
click_button(“删除内容”) find(:xpath,'// a [text()='Link应该删除')。应该be_false
3:使用has_link?而不是has_no_link?
click_button(“删除内容”) page.has_link?(“应该删除链接”)。应该是be_false
答案 6 :(得分: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