如何在测试之间重复使用 Capybara 会话?
Posted
技术标签:
【中文标题】如何在测试之间重复使用 Capybara 会话?【英文标题】:How do I re-use Capybara sessions between tests? 【发布时间】:2012-09-18 07:30:37 【问题描述】:我想继续使用同一个会话,我指的是 Rails 在使用 Capybara 的各种 Test::Unit
集成测试之间的会话。 Capybara::Session
对象在所有测试中都是相同的,因为它被重复使用,但是当我在另一个测试中访问另一个页面时,我会立即注销。
我发现capybara_session.driver.browser.manage.all_cookies
在一个测试和下一个测试之间被清除。
有什么想法吗?或者为什么?或者如何避免?
为了解决这个问题,我将 cookie 保存在一个类变量中,然后通过运行重新添加:
capybara_session.driver.browser.manage.add_cookie(@@cookie)
它似乎可以工作,cookie 在那里,但是当有请求时,cookie 会被替换为另一个,所以它没有效果。
还有其他方法可以实现吗?
【问题讨论】:
你解决过这个问题吗?我正在打它,并尝试了下面提出的所有解决方案,但无济于事...... 【参考方案1】:如果您正在尝试将各个示例串联成一个故事(黄瓜风格,但没有黄瓜),您可以使用名为 rspec-steps 的 gem 来完成此操作。例如,通常这是行不通的:
describe "logging in" do
it "when I visit the sign-in page" do
visit "/login"
end
it "and I fill in my registration info and click submit" do
fill_in :username, :with => 'Foo'
fill_in :password, :with => 'foobar'
click_on "Submit"
end
it "should show a successful login" do
page.should have_content("Successfully logged in")
end
end
因为 rspec 会回滚其所有的实例变量、会话、cookie 等。
如果您安装 rspec-steps(注意:目前与 2.9 之后的 rspec 不兼容),您可以将 'describe' 替换为 'steps' 并且 Rspec 和 capybara 将保留示例之间的状态,让您构建更长的故事,例如:
steps "logging in" do
it "when I visit the sign-in page" #... etc.
it "and I fill in" # ... etc.
it "should show a successful" # ... etc.
end
【讨论】:
【参考方案2】:可能值得发布您需要这种行为的原因。通常,需要对 Capybara 进行猴子修补,这表明您正试图将其用于不打算用于的目的。通常可以重新构建测试,这样您就不需要在集成测试中保留 cookie。
【讨论】:
加速测试。保持会话完好无损(通常)不违反测试隔离【参考方案3】:您可以通过猴子修补Capybara::Selenium::Driver#reset!
方法来防止在测试之间发生对@browser.manage.delete_all_cookies
的调用。这不是一种干净的方式,但它应该可以工作......
将以下代码添加到您的项目中,以便在您require 'capybara'
require 'capybara'
之后执行它:
class Capybara::Selenium::Driver < Capybara::Driver::Base
def reset!
# Use instance variable directly so we avoid starting the browser just to reset the session
if @browser
begin
#@browser.manage.delete_all_cookies <= cookie deletion is commented out!
rescue Selenium::WebDriver::Error::UnhandledError => e
# delete_all_cookies fails when we've previously gone
# to about:blank, so we rescue this error and do nothing
# instead.
end
@browser.navigate.to('about:blank')
end
end
end
出于兴趣,可以在 Capybara 的代码库中看到违规行:https://github.com/jnicklas/capybara/blob/master/lib/capybara/selenium/driver.rb#L71
【讨论】:
测试之间没有运行该函数。我实际上在我的 gem 中将它注释掉了,它没有任何区别(我还在那里设置了一个断点,但没有达到)。我认为它可能适用于 RSpec,其中 Capybara 有一些深度集成,但不适用于 Test::Unit。这就是为什么这个问题如此令人费解的原因。 有趣的问题!所以reset!
在这里执行 rspec 测试:github.com/jnicklas/capybara/blob/master/lib/capybara/… 和黄瓜测试:github.com/jnicklas/capybara/blob/master/lib/capybara/… ...情节变厚了...我想你已经经历过这个:github.com/jnicklas/capybara#using-capybara-with-testunit【参考方案4】:
在与页面交互的水豚代码之后添加以下内容:
Capybara.current_session.instance_variable_set(:@touched, false)
or
page.instance_variable_set(:@touched, false)
如果这不起作用,这些可能会有所帮助:
https://github.com/railsware/rack_session_access
http://collectiveidea.com/blog/archives/2012/01/05/capybara-cucumber-and-how-the-cookie-crumbles/
【讨论】:
我爱你,伙计! :) 这工作太棒了。我遇到了 rspec 步骤的问题,关于上下文中的上下文(可能特定于我们的测试设置;我们正在修补 rspec 的上下文)。 使用 gem rack_session_access。干得好! 太好了,将“page.instance_variable_set(:@touched, false)”添加到全局 after(:each) 块和“page.instance_variable_set(:@touched, true)”到全局 after( :all) 为我们节省了大约 20% 的测试运行时间(超过 250 个水豚测试块)。幸运的是,调整只导致了大约 1% 的新测试失败,这可以很容易地修复。好的!!! :) 非常感谢您,我正在为 Angular SPA 编写测试,并且认为我必须等待整个页面重新加载,再次下载所有 .js 资产,这简直是疯了每次测试后。 效果很好,Capybara 2.16。但是在最后的after(:context)
中你还需要在page.instance_variable_set(:@touched, true)
之后做page.reset!
,否则它不会被重置。以上是关于如何在测试之间重复使用 Capybara 会话?的主要内容,如果未能解决你的问题,请参考以下文章
Rails - 失去与集成测试和 Capybara 的会话 - CSRF 相关?
在 Browserstack 中将会话 ID 更新为测试名称