Rails + Cucumber / Capybara:如何在测试中设置/检索cookie?

时间:2013-10-11 19:39:58

标签: ruby-on-rails cookies capybara

我正在实施一个懒惰的登录功能。我的黄瓜特征应该描述它:

    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]已设置。这将由我的ApplicationController中的before过滤器使用,以便打开全新浏览器的用户将自动登录:

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过滤器:

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

所以问题是在我的黄瓜功能的最后一步,cookies.signed[:auth_token]返回nil。我猜这只是一个水豚的事情。那么我是否真的必须在测试中设置一个cookie而不是在我的控制器中使用它?

3 个答案:

答案 0 :(得分:20)

所以最终我在尝试了很多不同的事情后想出来了。

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

答案 1 :(得分:9)

使用包含驱动程序方法的https://github.com/nruth/show_me_the_cookies。它有获取cookie,删除cookie的方法,以及创建名为create_cookie的cookie的方法。

答案 2 :(得分:0)

我只需要测试Cookie值

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

并移植到Rails 5.x

创建import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { AnimationController transitionAnimation; @override void initState() { super.initState(); transitionAnimation = AnimationController( duration: const Duration(seconds: 5), vsync: this, ); transitionAnimation.forward(); } @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: <Widget>[ Positioned( left: MediaQuery.of(context).size.width * 0.15, child: AnimatedBuilder( animation: transitionAnimation, builder: (context, child) { return SlideTransition( position: Tween<Offset>( begin: const Offset(-2, 0), end: const Offset(0, 0), ).animate(CurvedAnimation( curve: const Interval(0, 1, curve: Curves.easeIn), parent: transitionAnimation)), child: child); }, child: Container( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width * 0.85, color: Colors.orange, ), ), ), Positioned( left: 0, child: AnimatedBuilder( animation: transitionAnimation, builder: (context, child) { return SlideTransition( position: Tween<Offset>( begin: const Offset(-1, 0), end: const Offset(0, 0), ).animate(CurvedAnimation( curve: const Interval(.01, 0.25, curve: Curves.easeInExpo), parent: transitionAnimation)), child: child); }, child: Container( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width * 0.15, color: Colors.black, ), ), ), ], ), floatingActionButton: FloatingActionButton( onPressed: () { transitionAnimation.repeat(); // Navigator.of(context).push(MaterialPageRoute( // builder: (context) => FirstPage(), // )); }, ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, ); } }

有内容

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