首页 > 解决方案 > Ruby Selenium Capybara 不会超时

问题描述

我的规格没有超时。我的一些规格达到了一定程度,只是挂起。我确定其中一个规范有问题导致它被破坏,我无法弄清楚为什么当我定义超时时它们只是无限期地挂起......

# frozen-string-literal: true
require 'rspec'
require 'capybara/rspec'
require 'capybara/dsl'
require 'selenium-webdriver'
require 'site_prism'

Dir[File.dirname(__FILE__) + '/page_objects/*/*.rb'].each do |page_object|
  require page_object
end

def wait_for_ajax
  Timeout.timeout(Capybara.default_max_wait_time) do
    loop until page.evaluate_script('jQuery.active').zero? && page.has_no_css?(".k-loading-color")
  end
end

def whole_page
  Capybara.current_session
end

Capybara.register_driver :selenium do |app|
  Capybara::Selenium::Driver.new(app, browser: :chrome)
end

Capybara.default_driver = :selenium
Capybara.app_host = #REDACTED
Capybara.default_max_wait_time = 20

RSpec.configure do |config|
  config.before(:each) do
    config.include Capybara::DSL
  end

  config.after(:each) do
    Capybara.reset_sessions! 
  end
end

标签: rubyseleniumselenium-webdriverrspeccapybara

解决方案


你没有提到它挂在什么命令上,但我猜它在你的wait_for_ajax方法中。如果是这种情况,那是因为您使用Timeout.timeout的是 Ruby 提供的最危险的使用方法。它的工作方式是启动第二个线程,然后在发生超时时在原始线程中引发异常。问题是异常可能发生在原始线程的任何地方,这意味着如果timeout调用中的块正在做任何不平凡的事情,它可能最终处于完全不可恢复的状态(网络通信等)。基本上Timeout.timeout只有非常详细地了解发生在其块中的每一件小事,才能安全地使用它,这意味着它永远不应该有效地用于对第三方库的任何调用。相反,如果您需要超时,您应该只使用计时器并休眠。就像是

def wait_for_ajax
  start = Time.now
  until page.evaluate_script('jQuery.active').zero? && page.has_no_css?(".k-loading-color", wait: false) do
    sleep 0.1
    raise <Some Error> if (Time.now - start) > Capybara.default_max_wait_time
  end
end

话虽这么说,您确实不需要wait_for_ajax可用的 UI 和正确编写的测试。

此外,通过包含capybara/rspec您已经设置为reset_sessions在每次测试后被调用并Capybara::DSL包含在应该包含的测试类型中 - https://github.com/teamcapybara/capybara/blob/master/lib /capybara/rspec.rb#L9 - 因此,通过添加您自己的after块,您最终只会reset_sessions在每次测试后调用两次,这只是浪费时间。


推荐阅读