用异步JavaScript进行Capybara集成测试

用异步JavaScript进行Capybara集成测试,javascript,jquery,ruby-on-rails,selenium,capybara,Javascript,Jquery,Ruby On Rails,Selenium,Capybara,我有一个Rails集成测试失败了,我不知道为什么。我正在使用水豚和硒作为驱动程序 测试检查在AJAX调用发生后页面内容是否已被删除。相关操作是单击一个按钮,该按钮单击会通过jQueryremove()调用删除页面的一部分。下面是集成测试代码的近似值: click_button("Remove stuff") assert has_no_link?("This should be removed") 断言失败,这意味着链接仍然存在 我一直在读水豚,我知道你可以延长默认的等待时间。我将其扩展到一个

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

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

click_button("Remove stuff")
assert has_no_link?("This should be removed")
断言失败,这意味着链接仍然存在

我一直在读水豚,我知道你可以延长默认的等待时间。我将其扩展到一个荒谬的值(20秒),但断言仍然失败

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

我不知道水豚是如何找到这个不再存在于DOM中的链接的。水豚是否在检查源代码而不是DOM,并在那里找到链接?如果是这样,我不知道如何修复此测试以确保测试通过。刷新页面可以解决这个问题,但这并不是一个用户会做的,所以我不愿意仅仅为了通过测试而更改页面

我想知道如何解决这个问题


谢谢

我从中学到了一种检查ajax请求是否完成的简洁方法。您可以使用ajax
$.active
函数(这样您就可以使用它),而不必等待特定的时间
$.active
告诉您与服务器的活动连接数,因此当连接数降至零时,您就知道ajax请求已完成:

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

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

有一个名为wait_until的方法,但最近它被弃用,并用synchronize方法进行了更改


现在我不知道如何准确地使用它,但我正在等待作者回答我的问题,所以我希望尽快解决这个问题

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

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

has_no_link = $('#id_for_link')
//.... some test
click_button("Remove stuff")
assert has_no_link?("This should be removed")
如果是这样,那么has_no_链接仍将指向该链接。remove()将从DOM中删除它,但您的变量在内存中仍然指向它


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

我必须重写等待测试,该测试涉及等待通过将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

我想到了两种方法:

1:检查你的水豚版本,看看你的版本有没有bug

2:可能在点击按钮后尝试查找链接

单击按钮(“删除内容”) find(:xpath,//a[text()=“链接应被删除”)。应为\u false

3:使用has\u link?而不是has\u no\u link

单击按钮(“删除内容”)
page.has_link?(“应删除链接”)。应为_false

您始终可以手动执行此操作。使用@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

Thoughtbot有一篇关于等待AJAX的博文,您可以阅读,尽管它基于Rspec,并且看起来您正在使用TestUnit

它适用于水豚等待时间不够长的情况,但不会增加不必要的长时间超时。我现在主要在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
您可以在需要时将其包含在单个测试文件中,也可以使用中提供的策略之一,以便每次自动包含它

然后,当您的测试没有正确地等待AJAX完成时,只需插入行
wait\u for\u AJAX
。以您的代码为例:

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

嗯……我正在使用Capybara下的Selenium驱动程序,默认情况下它似乎支持JavaScript测试(请参阅)。我尝试添加等待代码,但没有解决问题。好主意!只是还没有解决…您是否使用capybara进行任何其他涉及javascript的测试?是的,但这是唯一一个查找删除信息的测试。所有其他内容似乎都可以工作…例如,检查AJAX查询是否会生成新按钮或更改图标但是关于jQuery
remove()
似乎不是很好。如果我检查
page.html
,它仍然显示那里的内容,因此这里肯定出了问题。哦,好吧,那是另一个问题。这似乎不适用于当前版本的水豚/poltergeist:Failure/Error:wait_,直到执行nomethoderor:undefined m你最终找到了解决问题的方法了吗?我有一个类似的方法,我想知道你是否能帮我。没有,不幸的是没有。我花了太多的时间让这个单一的测试工作,所以我最终只是注释它而不是修复它。对不起,我不能提供更多的帮助…我没有en花了这么多时间之后,现在开始深入研究了!如果你能解决这个问题,请随意回答,我会很高兴给你评分!你记得在你的rspec中包含
js:true
吗?对于水豚的最新版本,请注意
default\u wait\u time
已被弃用。使用
default\u max\u wait\u time