Capybara 与异步 JavaScript 集成测试

问题描述 投票:0回答:7

我的 Rails 集成测试失败了,我不明白为什么。我使用 Capybara 和 Selenium 作为驱动程序。

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

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

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

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

当我手动遵循测试过程时,页面的

source

仍然显示内容,但 DOM 不显示(通过查看 Firefox 的 DOM Inspector 并查找元素)。这是问题吗?我什至尝试在 Firefox 中运行测试时检查 DOM,以检查内容是否存在,但似乎并不存在。 我不知道 Capybara 是如何找到这个 DOM 中不再存在的链接的。 Capybara 是否检查源代码而不是 DOM 并找到那里的链接?如果是这样,我不知道如何修复此测试以确保测试通过。刷新页面可以解决问题,但这并不完全是用户会做的,所以我犹豫是否要更改页面只是为了让测试通过...... 希望获得有关如何解决此问题的任何建议。

Thoughtbot 有一篇关于等待 AJAX 的精彩博客文章,您可以在

here
jquery ruby ajax selenium-webdriver capybara
7个回答
3
投票

它非常适合水豚等待时间不够长的情况,但不会增加不必要的长时间超时。我现在主要在 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")

    

有一个名为 wait_until 的方法,但最近已弃用并用同步方法更改。

1
投票
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

目前我还不知道具体如何使用它,但我正在等待作者对我的问题的回答,所以我希望尽快解决这个问题

有一种巧妙的方法可以检查 ajax 请求是否已完成,这是我从

这篇文章

0
投票
wait

函数(该函数不在实际 API 中,但已公开,因此您可以使用它),而不是具有特定时间的

$.active
$.active
告诉您与服务器的活动连接数,因此当它降至零时,您就知道 ajax 请求已完成: wait_until do page.evaluate_script('$.active') == 0 end

如果这不起作用,则问题出在其他地方(从您所写的内容来看,这似乎很可能)。如果更改仅发生在 DOM 中,那么您必须确保为您的测试/规范启用了 javascript。例如,在 rspec 中,您可以设置

:js => true
 来做到这一点;在 Cucumber 中,您可以在场景上方添加一行 
@javascript

。我不使用 Rails 的默认测试,但必须有一个设置来执行相同的操作。

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


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 中再次查询该链接,看看是否得到结果。

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


0
投票

我想到的几种方法:

0
投票

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

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

3:使用has_link?而不是 has_no_link?

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

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


0
投票

© www.soinside.com 2019 - 2024. All rights reserved.