Rails + Cucumber/Capybara: How to set/retrieve cookies in tests?

18,892

Solution 1

So eventually I figured it out after trying a lot of different things.

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

UPDATE:

Here's what I use in case I'm using Selenium for some of the tests:

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

Solution 2

Use https://github.com/nruth/show_me_the_cookies which wraps the driver methods. It has methods for getting cookies, deleting cookies, and a method for creating cookies called create_cookie.

Share:
18,892

Related videos on Youtube

bigpotato
Author by

bigpotato

Updated on October 02, 2022

Comments

  • bigpotato
    bigpotato over 1 year

    I'm implementing a lazy login feature. My cucumber feature should describe it:

        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 
    

    And these are my step definitions:

    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
    

    This is what happens when a user logs in: the cookies.signed[:auth_token] gets set. This will be used by a before filter in my ApplicationController so that users who open a fresh browser will be logged in automatically:

    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
    

    end

    This is the before filter in my ApplicationController:

    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
    

    So the issue is that in the last step of my cucumber feature, cookies.signed[:auth_token] returns nil. I'm guessing this is just a capybara thing. So do I actually have to set a cookie in the test as opposed to using the one in my controller?

  • Nakilon
    Nakilon over 9 years
    undefined method `set_cookie' for #<Selenium::WebDriver::Driver
  • Arepo
    Arepo over 7 years
    Instead of Capybara.current_session.driver.request.cookies.[]('auth_tok‌​en'), why not use Ruby's standard sugar for hashes - ie Capybara.current_session.driver.request.cookies['auth_token'‌​]
  • sameers
    sameers about 7 years
    For the Poltergeist driver, the method (as documented on the Poltergeist GitHub page) is page.driver.set_cookie(), and its 3 arguments are the cookie's name, its value, and an options hash for setting, among other things, the cookie's expiry value.
  • Gorm Casper
    Gorm Casper over 5 years
    @JonKern glad to hear it! I see that create_cookie has been documented in the README, so I'm updating my answer.
  • anandvc
    anandvc almost 4 years
    If you get the error undefined method set_cookie for #<Selenium::WebDriver::Chrome::Driver: then you can set cookies like so: page.driver.browser.manage.add_cookie(name: "cookie_name", value: "cookie_value")
  • Maxime Boué
    Maxime Boué about 3 years
    The solution is not on the page from the link you gave anymore