![](/img/trans.png)
[英]Capybara with Selenium throws a Net::ReadTimeout: 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前端的獨立開發服務器。 Ember前端查看要知道的用戶代理,然后將請求發送到Rails API測試數據庫。
除了使用RSpec文件夾具的測試外,所有測試都運行良好。
這是一個失敗的規范:
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%的時間。 有一個奇怪的情況,它通過。 我可以讓我的測試套件最終通過循環運行一天來通過。
我最終將所有版本升級到最新版本(節點10,最新的Ember,最新的Rails),但問題仍然存在。
我可以發布一個樣本倉庫,以便稍后再現該問題。 我只是想發布這個以防萬一有人遇到過這個問題。
這是超時發生時的典型堆棧跟蹤:
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('/')
這樣的良性事物上。
編輯 :我嘗試使用DISABLE_FASTBOOT
env變量禁用Ember FastBoot(服務器端渲染),並突然通過所有測試。 我想在某種情況下,RSpec燈具會導致Ember FastBoot無法完成渲染。 這肯定與我在生產日志中偶爾看到的連接斷開有關。
我一直在試驗客戶端代碼,這可能是由於我使用了FastBoot的deferRendering
調用 。
編輯 :我使用以下版本:
編輯 :我正在使用這個有點不穩定的Node / Express庫fastboot-app-server來進行服務器端渲染。 我發現它有時會刪除重要的響應頭(Content-Type和Content-Encoding)。 我想知道這是否有助於解決這個問題。
編輯 :我添加了嚴格的內容安全策略,以確保在測試套件中沒有可能導致Net::ReadTimeout
外部請求。
我檢查Chrome網絡選項卡,當它鎖定時,似乎什么都沒有加載。 手動刷新瀏覽器允許測試接收並繼續運行。 多么奇怪。
我現在花了幾個星期的時間,可能是時候放棄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)
這似乎解決了問題!
我終於讓我的測試套件通過切換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)
但也提供了超時。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.