水豚 + Selenium-webdriver + RSpec 文件装置 + SSR 给予 Net::ReadTimeout
Capybara + Selenium-webdriver + RSpec file fixtures + SSR giving Net::ReadTimeout
我注意到一个奇怪的问题,几天来我一直无法解决。
我有一个 Rails 5 API 服务器,系统测试使用 RSpec 和 Capybara + Selenium-webdriver 无头驾驶 Chrome。
我正在使用 Capybara.app_host = 'http://localhost:4200'
使测试命中一个单独的开发服务器,该服务器 运行 正在 Ember front-end。 Ember front-end 查看用户代理知道然后将请求发送到 Rails API 测试数据库。
所有测试 运行 都很好,除了使用 RSpec file fixtures.
的测试
这是一项失败的规范:
describe 'the affiliate program', :vcr, type: :system do
fixtures :all
before do
Capybara.session_name = :affiliate
visit('/')
signup_and_verify_email(signup_intent: :seller)
visit_affiliate_settings
end
it 'can use the affiliate page' do
affiliate_token = page.text[/Your affiliate token is \b(.+?)\b/i, 1]
expect(affiliate_token).to be_present
# When a referral signs up.
Capybara.session_name = :referral
visit("?client=#{affiliate_token}")
signup_and_verify_email(signup_intent: :member)
refresh
# It can track the referral.
Capybara.session_name = :affiliate
refresh
expect(page).to have_selector('.referral-row', count: 1)
# When a referral makes a purchase.
Capybara.session_name = :referral
find('[href="/videos"]').click
find('.price-area .coin-usd-amount', match: :first).click
find('.cart-dropdown-body .checkout-button').click
find('.checkout-button').click
wait_for { find('.countdown-timer') }
order = Order.last
order.force_complete_payment!
Rake::Task['affiliate_referral:update_amounts_earned'].invoke
# It can track the earnings.
Capybara.session_name = :affiliate
refresh
amount = (order.price * AffiliateReferral::COMMISSION_PERCENTAGE).floor.to_f
amount_in_dom = find('.referral-amount-earned', match: :first).text.gsub(/[^\d\.]/, '').to_f * 100
expect(amount).to equal(amount_in_dom)
end
end
这可能会在 99% 的情况下失败。它通过的情况很奇怪。我可以让我的测试套件最终通过 运行循环一天。
我最终将所有版本升级到最新版本(Node 10,最新 Ember,最新 Rails),但问题仍然存在。
我可以 post 稍后重现该问题的示例存储库。我只是想得到这个 posted 以防有人遇到这个问题。
这是超时发生时的典型堆栈跟踪:
1.1) Failure/Error: page.evaluate_script('window.location.reload()')
Net::ReadTimeout:
Net::ReadTimeout
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/webmock-3.3.0/lib/webmock/http_lib_adapters/net_http.rb:97:in `block in request'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/webmock-3.3.0/lib/webmock/http_lib_adapters/net_http.rb:110:in `block in request'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/webmock-3.3.0/lib/webmock/http_lib_adapters/net_http.rb:109:in `request'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/http/default.rb:121:in `response_for'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/http/default.rb:76:in `request'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/http/common.rb:62:in `call'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/bridge.rb:164:in `execute'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/oss/bridge.rb:584:in `execute'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/oss/bridge.rb:267:in `execute_script'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/common/driver.rb:211:in `execute_script'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/capybara-3.8.2/lib/capybara/selenium/driver.rb:84:in `execute_script'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/capybara-3.8.2/lib/capybara/selenium/driver.rb:88:in `evaluate_script'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/capybara-3.8.2/lib/capybara/session.rb:575:in `evaluate_script'
# ./spec/support/selenium.rb:48:in `refresh'
# ./spec/support/pages.rb:70:in `signup_and_verify_email'
# ./spec/system/payment_spec.rb:43:in `block (3 levels) in <top (required)>'
我应该指出 page.evaluate_script('window.location.reload()')
并不总是这样。它可能发生在像 visit('/')
.
这样的良性事物上
Edit:我尝试使用 DISABLE_FASTBOOT
env 变量禁用 Ember FastBoot(server-side 渲染),突然所有测试都通过了。我在想 RSpec 固定装置以某种方式导致 Ember FastBoot 在某些情况下无法完成渲染。这肯定与我偶尔在生产日志中看到的断开连接一致。
我一直在试验客户端代码,这可能是因为我使用了 FastBoot's deferRendering
call。
编辑:我使用的是以下版本:
- ember-cli: 3.1.3
- ember-data: 3.0.2
- rails: 5.2.1
- rspec: 3.8.0
- 水豚:3.8.2
- selenium-webdriver: 3.14.0
- google chrome:69.0.3497.100(正式版)(64 位)
编辑:我正在使用这个有点不稳定的 Node/Express 库 fastboot-app-server 来进行 server-side 渲染。我发现它有时会删除重要的响应 headers(Content-Type 和 Content-Encoding)。我想知道这是否导致了这个问题。
编辑:我添加了严格的内容安全策略以确保在测试套件期间没有外部请求 运行ning 可能导致 Net::ReadTimeout
.
我在 Chrome 网络选项卡锁定时检查它,它似乎没有加载任何内容。手动刷新浏览器允许测试开始并继续 运行ning。真奇怪。
我已经在这上面花了几个星期了,可能是时候放弃 Selenium 测试了。
我升级到 Chrome 70 和 chromedriver 2.43。好像没什么区别。
我尝试使用 rspec-retry gem 在超时发生时强制刷新,但 gem 似乎无法捕获超时异常。
我已经检查了对 chromedriver 的原始请求,那里有问题。看起来总是 POST http://127.0.0.1/session/<session id>/refresh
。我尝试以另一种方式刷新:visit(page.current_path)
这似乎可以解决问题![=26=]
通过将 page.driver.browser.navigate.refresh
切换为 visit(page.current_path)
,我终于让我的测试套件通过了。
我知道这是一个丑陋的技巧,但这是我能找到的唯一让事情正常进行的方法(请参阅我在问题编辑中的各种尝试)。
我查看了每次导致超时的 chromedriver 请求:POST http://127.0.0.1/session/<session id>/refresh
。我只能猜测这是 chromedriver 的某种问题。也许顺便说一下,它仅在多个 chromedriver 实例处于活动状态时挂起(这在使用多个 Capybara 会话时发生)。
编辑:我还需要考虑查询参数:
def refresh
query = URI.parse(page.current_url).query
path = page.current_path
path += "?#{query}" if query.present?
visit(path)
end
我试过只做 visit(page.current_url)
但那也会超时。
我注意到一个奇怪的问题,几天来我一直无法解决。
我有一个 Rails 5 API 服务器,系统测试使用 RSpec 和 Capybara + Selenium-webdriver 无头驾驶 Chrome。
我正在使用 Capybara.app_host = 'http://localhost:4200'
使测试命中一个单独的开发服务器,该服务器 运行 正在 Ember front-end。 Ember front-end 查看用户代理知道然后将请求发送到 Rails API 测试数据库。
所有测试 运行 都很好,除了使用 RSpec file fixtures.
的测试这是一项失败的规范:
describe 'the affiliate program', :vcr, type: :system do
fixtures :all
before do
Capybara.session_name = :affiliate
visit('/')
signup_and_verify_email(signup_intent: :seller)
visit_affiliate_settings
end
it 'can use the affiliate page' do
affiliate_token = page.text[/Your affiliate token is \b(.+?)\b/i, 1]
expect(affiliate_token).to be_present
# When a referral signs up.
Capybara.session_name = :referral
visit("?client=#{affiliate_token}")
signup_and_verify_email(signup_intent: :member)
refresh
# It can track the referral.
Capybara.session_name = :affiliate
refresh
expect(page).to have_selector('.referral-row', count: 1)
# When a referral makes a purchase.
Capybara.session_name = :referral
find('[href="/videos"]').click
find('.price-area .coin-usd-amount', match: :first).click
find('.cart-dropdown-body .checkout-button').click
find('.checkout-button').click
wait_for { find('.countdown-timer') }
order = Order.last
order.force_complete_payment!
Rake::Task['affiliate_referral:update_amounts_earned'].invoke
# It can track the earnings.
Capybara.session_name = :affiliate
refresh
amount = (order.price * AffiliateReferral::COMMISSION_PERCENTAGE).floor.to_f
amount_in_dom = find('.referral-amount-earned', match: :first).text.gsub(/[^\d\.]/, '').to_f * 100
expect(amount).to equal(amount_in_dom)
end
end
这可能会在 99% 的情况下失败。它通过的情况很奇怪。我可以让我的测试套件最终通过 运行循环一天。
我最终将所有版本升级到最新版本(Node 10,最新 Ember,最新 Rails),但问题仍然存在。
我可以 post 稍后重现该问题的示例存储库。我只是想得到这个 posted 以防有人遇到这个问题。
这是超时发生时的典型堆栈跟踪:
1.1) Failure/Error: page.evaluate_script('window.location.reload()')
Net::ReadTimeout:
Net::ReadTimeout
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/webmock-3.3.0/lib/webmock/http_lib_adapters/net_http.rb:97:in `block in request'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/webmock-3.3.0/lib/webmock/http_lib_adapters/net_http.rb:110:in `block in request'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/webmock-3.3.0/lib/webmock/http_lib_adapters/net_http.rb:109:in `request'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/http/default.rb:121:in `response_for'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/http/default.rb:76:in `request'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/http/common.rb:62:in `call'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/bridge.rb:164:in `execute'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/oss/bridge.rb:584:in `execute'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/remote/oss/bridge.rb:267:in `execute_script'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.14.0/lib/selenium/webdriver/common/driver.rb:211:in `execute_script'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/capybara-3.8.2/lib/capybara/selenium/driver.rb:84:in `execute_script'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/capybara-3.8.2/lib/capybara/selenium/driver.rb:88:in `evaluate_script'
# /home/mhluska/.rvm/gems/ruby-2.5.1/gems/capybara-3.8.2/lib/capybara/session.rb:575:in `evaluate_script'
# ./spec/support/selenium.rb:48:in `refresh'
# ./spec/support/pages.rb:70:in `signup_and_verify_email'
# ./spec/system/payment_spec.rb:43:in `block (3 levels) in <top (required)>'
我应该指出 page.evaluate_script('window.location.reload()')
并不总是这样。它可能发生在像 visit('/')
.
Edit:我尝试使用 DISABLE_FASTBOOT
env 变量禁用 Ember FastBoot(server-side 渲染),突然所有测试都通过了。我在想 RSpec 固定装置以某种方式导致 Ember FastBoot 在某些情况下无法完成渲染。这肯定与我偶尔在生产日志中看到的断开连接一致。
我一直在试验客户端代码,这可能是因为我使用了 FastBoot's deferRendering
call。
编辑:我使用的是以下版本:
- ember-cli: 3.1.3
- ember-data: 3.0.2
- rails: 5.2.1
- rspec: 3.8.0
- 水豚:3.8.2
- selenium-webdriver: 3.14.0
- google chrome:69.0.3497.100(正式版)(64 位)
编辑:我正在使用这个有点不稳定的 Node/Express 库 fastboot-app-server 来进行 server-side 渲染。我发现它有时会删除重要的响应 headers(Content-Type 和 Content-Encoding)。我想知道这是否导致了这个问题。
编辑:我添加了严格的内容安全策略以确保在测试套件期间没有外部请求 运行ning 可能导致 Net::ReadTimeout
.
我在 Chrome 网络选项卡锁定时检查它,它似乎没有加载任何内容。手动刷新浏览器允许测试开始并继续 运行ning。真奇怪。
我已经在这上面花了几个星期了,可能是时候放弃 Selenium 测试了。
我升级到 Chrome 70 和 chromedriver 2.43。好像没什么区别。
我尝试使用 rspec-retry gem 在超时发生时强制刷新,但 gem 似乎无法捕获超时异常。
我已经检查了对 chromedriver 的原始请求,那里有问题。看起来总是 POST http://127.0.0.1/session/<session id>/refresh
。我尝试以另一种方式刷新:visit(page.current_path)
这似乎可以解决问题![=26=]
通过将 page.driver.browser.navigate.refresh
切换为 visit(page.current_path)
,我终于让我的测试套件通过了。
我知道这是一个丑陋的技巧,但这是我能找到的唯一让事情正常进行的方法(请参阅我在问题编辑中的各种尝试)。
我查看了每次导致超时的 chromedriver 请求:POST http://127.0.0.1/session/<session id>/refresh
。我只能猜测这是 chromedriver 的某种问题。也许顺便说一下,它仅在多个 chromedriver 实例处于活动状态时挂起(这在使用多个 Capybara 会话时发生)。
编辑:我还需要考虑查询参数:
def refresh
query = URI.parse(page.current_url).query
path = page.current_path
path += "?#{query}" if query.present?
visit(path)
end
我试过只做 visit(page.current_url)
但那也会超时。