Rails + Cucumber/Capybara:如何在测试中设置/获取cookies?

24

我正在实现一种“懒惰登录”功能。我的cucumber测试应该描述如下:

    Feature: User log in

        Scenario: Lazy login
            Given I didn't log out the last time I was on the site
            When I go to the homepage
            Then I should automatically be logged in 

以下是我的步骤定义:

Given(/^I didn't log out the last time I was on the site$/) do
  user = FactoryGirl.create(:user)
  visit new_user_session_path
  fill_in('user[email]', with: user.email)
  fill_in('user[password]', with: 'test123')
  click_button('Sign in')

  Capybara.reset_sessions!
end

When(/^I go to the homepage$/) do
  visit root_path
end

Then(/^I should automatically be logged in$/) do #<-- Fails here
  page.should have_content("Logout")
end

当用户登录时,会设置 cookies.signed [:auth_token]。应用程序控制器中的一个前置过滤器将使用此标记,以使开启新浏览器的用户自动登录。
class SessionsController < Devise::SessionsController

def create
  super
  if user_signed_in?
    puts 'yesssssss'
    session[:user_id] = current_user.id  
    current_user.remember_me! if current_user.remember_token.blank?
    cookies.signed[:auth_token] = {
      :value => current_user.remember_token,
      :domain => "mysite.com",
      :secure => !(Rails.env.test? || Rails.env.development?)
      }
    puts "current_user.remember_token = #{current_user.remember_token}"
    puts 'cookies:'
    puts cookies.signed[:auth_token]
  end
end

这是我 ApplicationController 中的 before 过滤器:

end

def sign_in_through_cookie
  logger.info "logging in by cookie"
  puts "logging in by cookie"
  puts cookies.signed[:auth_token] #<-- PROBLEM: this returns nil.
  return true if !current_user.nil?
  if !cookies[:auth_token].nil? && cookies[:auth_token] != ''
    user = User.find_by_remember_token(cookies.signed[:auth_token])
    return false if user.blank?
    sign_in(user)
    puts 'success'
    return true
  else
    return false
  end
end

问题在于,在我的cucumber功能的最后一步中,cookies.signed [:auth_token]返回nil。我猜这只是capybara的一个问题。所以,我是否实际上必须在测试中设置一个cookie,而不是使用控制器中的cookie?

3个回答

24

尝试了很多不同的方法之后,最终我找到了解决方案。

Given(/^I didn't log out the last time I was on the site$/) do
  user = FactoryGirl.create(:user)
  visit new_user_session_path
  fill_in('user[email]', with: user.email)
  fill_in('user[password]', with: 'test123')
  click_button('Sign in')

  Capybara.current_session.driver.request.cookies.[]('auth_token').should_not be_nil
  auth_token_value = Capybara.current_session.driver.request.cookies.[]('auth_token')
  Capybara.reset_sessions!
  page.driver.browser.set_cookie("auth_token=#{auth_token_value}")
end

When(/^I go to the homepage$/) do
  visit root_path
end

Then(/^I should automatically be logged in$/) do
  page.should have_content("Logout")
end

更新:

以下是我在使用Selenium进行某些测试时所使用的内容:

if Capybara.current_session.driver.class == Capybara::Selenium::Driver
  auth_token = page.driver.browser.manage.cookie_named('auth_token')[:value]
  page.driver.browser.manage.delete_all_cookies
  page.driver.browser.manage.add_cookie(:name => "auth_token", :value => auth_token)
else
  puts "cookies = #{Capybara.current_session.driver.request.cookies}"
  Capybara.current_session.driver.request.cookies.[]('auth_token').should_not be_nil
  auth_token_value = Capybara.current_session.driver.request.cookies.[]('auth_token')
  Capybara.reset_sessions!
  page.driver.browser.set_cookie("auth_token=#{auth_token_value}")
end

2
未定义方法 `set_cookie' 于 #<Selenium::WebDriver::Driver - Nakilon
1
为什么不使用 Ruby 的标准哈希语法,即 Capybara.current_session.driver.request.cookies['auth_token'],而不是 Capybara.current_session.driver.request.cookies.[]('auth_token') - Arepo
2
对于Poltergeist驱动程序,方法(如Poltergeist GitHub页面所述)是page.driver.set_cookie(),它有3个参数:cookie的名称、其值以及用于设置其他内容的选项哈希,包括cookie的到期值。 - sameers
如果你遇到了以下错误:undefined method set_cookie for #<Selenium::WebDriver::Chrome::Driver:那么你可以这样设置cookies:page.driver.browser.manage.add_cookie(name: "cookie_name", value: "cookie_value") - anandvc

11

@JonKern 很高兴听到这个消息!我看到create_cookie已经在README中有了文档,所以我正在更新我的答案。 - Benjamin Atkin

-1

我只需要测试cookie的值

灵感来自于https://collectiveidea.com/blog/archives/2012/01/05/capybara-cucumber-and-how-the-cookie-crumbles

并移植到Rails 5.x

创建features/support/cookies.rb

内容如下

module Capybara
  class Session
    def cookies
      @cookies ||= ActionDispatch::Request.new(Rails.application.env_config.deep_dup).cookie_jar
    end
  end
end

Before do
  allow_any_instance_of(ActionDispatch::Request).to receive(:cookie_jar).and_return(page.cookies)
  allow_any_instance_of(ActionDispatch::Request).to receive(:cookies).and_return(page.cookies)
end

然后进行测试的步骤

Then('is set cookie {string} with value {string}') do |cookie, value|
  expect(page.cookies.signed[cookie]).to eq value
end

解决方案不再在您提供的链接页面上。 - Maxime Boué

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接