如何在测试之间重复使用 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 更新为测试名称

Rails、Cucumber、Capybara:会话不持久

Capybara:测试何时禁用 cookie、localStorage 和 sessionStorage

如何用 Cucumber 测试确认对话框?

如何使用 Capybara 测试 OPTIONS 请求?