Capybara、Devise、CanCan 和 RSpec 集成测试:有效登录 302 重定向到 example.com [英] Capybara, Devise, CanCan and RSpec integration tests: valid sign in 302 redirects to example.com

查看:20
本文介绍了Capybara、Devise、CanCan 和 RSpec 集成测试:有效登录 302 重定向到 example.com的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:请参阅文章末尾,了解规格现在如何工作,因为我在规格/请求而不是规格/控制器中有我的规格.仍然想知道如何获得有效的登录用户以与我的控制器进行集成测试.

我第一次与 Devise 和 CanCan 合作,但在进行最基本的集成测试时遇到了困难,我正在验证登录用户是否......好吧......登录.我已阅读无数关于 Devise 和 RSpec 集成测试的帖子和答案(即通过直接通过 https://github.com/plataformatec/devise/wiki/How-To%3a-Test-with-Capybara, http://schneems.com/post/15948562424/speed-up-capybara-tests-with-deviseCapybara,RSpec 和 Devise:有什么方法可以通过绕过缓慢的登录和直接设置会话来加快集成测试?,但我有蜜蜂n 甚至无法让标准帖子按预期工作,我很困惑:

  1. 开发环境运行良好(可以登录并重定向到正确的页面,导航登录链接更改为注销等).
  2. test.log 表示没有问题,直到它执行 302 重定向到 http://www.example.com 而不是我的 root_path.

有大量用户遇到类似问题并使用不同的解决方案,显然我不是唯一遇到此问题的人,因为会话等的各个方面在不同的场景中都不可用.

精简测试:

subject { page }描述应该能够登录"做在做之前访问'/users/sign_in'用户 = FactoryGirl.create(:admin)#user.add_role :adminfill_in '用户名',用:user.username填写'密码',用:user.passwordclick_on '登录'结尾它 { 应该有_link '注销' }结尾...

相关的 log.test 输出:

 在 2012-11-06 17:31:10 -0800 开始为 127.0.0.1 POST "/users/sign_in"由 Devise::SessionsController#create as HTML 处理参数:{"utf8"=>"✓", "user"=>{"username"=>"username1", "password"=>"[FILTERED]", "remember_me"=>"0"}, "提交"=>"登录"}[1m[36mUser Load (0.1ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."username" = 'username1' LIMIT 1[0m[1m[35m (0.0ms)[0m SAVEPOINT active_record_1[1m[36m (0.0ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m][1m[35m (0.0ms)[0m SAVEPOINT active_record_1[1m[36m (0.1ms)[0m [1mUPDATE "users" SET "last_sign_in_at" = '2012-11-07 01:31:10.722712', "current_sign_in_at" = '2012-11-07 01:321:102'"last_sign_in_ip" = '127.0.0.1', "current_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "updated_at" = '2012-11-07 01:31:10.723051' "userid"= 1[0米[1m[35m (0.0ms)[0m RELEASE SAVEPOINT active_record_1重定向到 http://www.example.com/在 12ms 内完成 302 Found (ActiveRecord: 0.0ms)

精简routes.rb:

认证:用户做根:到 =>'家#索引'结尾根:到 =>家#index"devise_for : 用户资源:用户

精简能力:

班级能力包括 CanCan::Ability

 def initialize(user)user ||= User.new # 来宾用户(未登录)如果 user.has_role?:行政可以:管理,:所有结尾...

为了彻底,当前的 Gemfile:

source 'https://rubygems.org'宝石导轨",3.2.8"gem "bootstrap-sass", "~> 2.1.0.1"gem 'faker', '1.1.2'gem 'will_paginate', '~>3.0.3'gem 'bootstrap-will_paginate', '~>0.0.9'宝石'jquery-rails'宝石'client_side_validations'宝石薄"宝石设计",〜> 2.1.2"gem "cancan", "~> 1.6.8"gem "rolify", "~> 3.2.0"gem "simple_form", "~> 2.0.4"组:资产做gem 'sass-rails', '~>3.2.3'gem '咖啡轨','~>3.2.1'gem 'uglifier', '>= 1.0.3'结尾组:开发,:测试做宝石'sqlite3','1.3.5'gem "rspec-rails", "~> 2.11.4"gem 'guard-rspec', '1.2.1'#gem 'listen',github:'guard/listen',分支:'polling/double'宝石 'guard-spork'宝石守卫黄瓜"宝石 'spork', '0.9.2'宝石factory_girl_rails",> = 4.1.0"结尾组:开发做宝石'注释','2.5.0'宝石quiet_assets",> = 1.0.1"结尾组:测试做宝石水豚",> = 1.1.2"gem "email_spec", ">= 1.2.1"gem "cucumber-rails", ">= 1.3.0", :require =>错误的宝石database_cleaner",> = 0.9.1"宝石发射",> = 2.1.2"gem 'rb-fsevent', '0.9.1', :require =>错误的宝石咆哮",1.0.3"gem '终端通知程序-警卫'结尾组:生产做宝石pg",0.12.2"结尾

还有一个用户对这个基本任务有问题,但结果证明这只是一个语法错误(参见 使用 rspec/devise 登录集成测试) 所以我确定我只是遗漏了一些非常明显的东西.

更新:

你一定是在开玩笑吧.离开它几个小时后,事实证明我出于某种原因在规范/控制器中有这个规范,当简单地将它切换到规范/请求时,一切都会变绿.

我引用:

<块引用>

如果您使用 Rails,请将您的 Capybara 规格放在 spec/requests 或规格/集成.

位于 https://github.com/jnicklas/capybara#readme

然而,我仍然想知道如何满足未来的需求,我可以对需要登录用户的控制器进行集成测试......对于过去的其他非设计应用程序,这很简单如下所示:

describe SomeController dolet(:user) { FactoryGirl.create(:user) }{ valid_sign_in 用户} 之前...

我的帮手就在这里

 def valid_sign_in(user)访问 signin_path填写电子邮件",使用:user.email填写密码",用:user.password取消选中(:remember_me)click_button "登录"# 不使用 Capybara 时也登录.cookies[:remember_token] = user.remember_token结尾

解决方案

有两个问题在起作用:

1.rspec/控制器与 rspec/请求

我试图在规范/控制器下进行集成测试.根据 https://github.com/jnicklas/capybara#readme,你需要把规范/请求或规范/集成中的 Capybara 规范.根据 https://stackoverflow.com/a/5803121/9344:

<块引用>

请求规范是一个薄的包装器ActionDispatch::IntegrationTest,它不像控制器那样工作规格(包装 ActionController::TestCase).即使有一个会话方法可用,我认为它不受支持(即它是可能是因为一个模块包含在其他实用程序中也包括那个方法).

最初这可以通过 Devise 通过辅助方法解决,例如:

# 文件:spec/requests_helper.rb定义登录(用户)post_via_redirect user_session_path, 'user[email]' =>user.email, '用户 [密码]' =>用户密码结尾

但是我已经实施的官方/最新解决方案(但请参阅下面的第二点,了解为什么它没有解决我的问题),可以在 https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara

2.Devise::HelperTests 用于控制器/视图测试,而不是集成测试.

如果我想在控制器上做一些测试,我可以使用 Devise::TestHelpers(通过 spec_helper.rb 引用),但即使这样我也没有获得 Capybara 集成测试的功能Devise::TestHelpers 是专门为控制器/视图测试而不是集成测试编写的.参见 rspec &设计测试助手.

总而言之,我想在控制器测试中做的事情无法完成,因为它实际上是一个集成测试,并且会话等不适用于规范/控制器.但是,有一些 Devise 测试助手可用于帮助进行控制器/视图测试.

更新

我在很久以后重新审视了这一点,现在已经让 Warden 助手在我的集成测试中发挥作用.欢呼!在我的 448 次测试中,这已经缩短了 8-10 秒.诀窍是 https://github 上的一个新条目.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara.具体:

<块引用>

Capybara-Webkit

如果您在使用 Warden 的 login_as 方法时遇到问题使用 capybara-webkit 驱动程序,尝试将 run_callbacks 设置为 falselogin_as 选项结构

user = Factory.create(:user)login_as(user, :scope =>:user,:run_callbacks =>错误的)

总而言之,每次我需要一个经过身份验证的用户进行集成测试时,不必每次都进行实际的表单填写和发布,现在我只需要 login_as(user, :scope => :user, :run_callbacks => false)(当然重构为辅助方法).

Update: see end of post for how the specs now work now that I have my specs in spec/requests instead of spec/controllers. Still wondering how to get a valid signed in user for integration tests with my controllers.

I'm working with Devise and CanCan for the first time and am having difficulty doing the most basic of integration tests whereby I'm verifying that a logged in user is...well...logged in. I have read countless posts and answers dealing with Devise and RSpec integration tests (i.e. speeding them up by accessing the session directly via https://github.com/plataformatec/devise/wiki/How-To%3a-Test-with-Capybara, http://schneems.com/post/15948562424/speed-up-capybara-tests-with-devise, and Capybara, RSpec and Devise: any way to make integration tests faster by circumventing slow login and setting session directly?, but I have been unable to even get a standard post working as expected and I'm baffled:

  1. Development environment works fine (can log in and get redirected to proper page, with navigation login link changed to logout, etc.).
  2. test.log indicates no problems until it does a 302 redirect to http://www.example.com instead of my root_path.

By the plethora of users with similar issues with varying solutions, I'm obviously not the only one who has had this problem as various aspects of the session etc. are unavailable in different scenarios.

Stripped down test:

subject { page }

describe 'should be able to log in' do
  before do
    visit '/users/sign_in'
    user = FactoryGirl.create(:admin)
    #user.add_role :admin
    fill_in 'Username', with: user.username
    fill_in 'Password', with: user.password
    click_on 'Sign in'
  end
  it { should have_link 'Logout' }
end
...

Relevant log.test output:

 Started POST "/users/sign_in" for 127.0.0.1 at 2012-11-06 17:31:10 -0800
 Processing by Devise::SessionsController#create as HTML
 Parameters: {"utf8"=>"✓", "user"=>{"username"=>"username1", "password"=>"[FILTERED]",        "remember_me"=>"0"}, "commit"=>"Sign in"}
 [1m[36mUser Load (0.1ms)[0m  [1mSELECT "users".* FROM "users" WHERE "users"."username" =   'username1' LIMIT 1[0m
 [1m[35m (0.0ms)[0m  SAVEPOINT active_record_1
    [1m[36m (0.0ms)[0m  [1mRELEASE SAVEPOINT active_record_1[0m
 [1m[35m (0.0ms)[0m  SAVEPOINT active_record_1
 [1m[36m (0.1ms)[0m  [1mUPDATE "users" SET "last_sign_in_at" = '2012-11-07   01:31:10.722712', "current_sign_in_at" = '2012-11-07 01:31:10.722712', "last_sign_in_ip" =   '127.0.0.1', "current_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "updated_at" = '2012-11-  07 01:31:10.723051' WHERE "users"."id" = 1[0m
 [1m[35m (0.0ms)[0m  RELEASE SAVEPOINT active_record_1
 Redirected to http://www.example.com/
 Completed 302 Found in 12ms (ActiveRecord: 0.0ms)

Stripped down routes.rb:

authenticated :user do
  root :to => 'home#index'
end
root :to => "home#index"
devise_for :users
resources :users

Stripped down Ability:

class Ability include CanCan::Ability

 def initialize(user)
  user ||= User.new # guest user (not logged in)
  if user.has_role? :admin
    can :manage, :all
  end
  ...

And to be thorough, the current Gemfile:

source 'https://rubygems.org'

gem 'rails', '3.2.8'
gem "bootstrap-sass", "~> 2.1.0.1"
gem 'faker', '1.1.2'
gem 'will_paginate', '~> 3.0.3'
gem 'bootstrap-will_paginate', '~> 0.0.9'
gem 'jquery-rails'
gem 'client_side_validations'
gem 'thin'
gem "devise", "~> 2.1.2"
gem "cancan", "~> 1.6.8"
gem "rolify", "~> 3.2.0"
gem "simple_form", "~> 2.0.4"

group :assets do
   gem 'sass-rails',   '~> 3.2.3'
   gem 'coffee-rails', '~> 3.2.1'
   gem 'uglifier', '>= 1.0.3'
end

group :development, :test do
 gem 'sqlite3', '1.3.5'
 gem "rspec-rails", "~> 2.11.4"
 gem 'guard-rspec', '1.2.1'
 #gem 'listen', github: 'guard/listen', branch: 'polling/double'
 gem 'guard-spork'
 gem 'guard-cucumber'
 gem 'spork', '0.9.2'
 gem "factory_girl_rails", ">= 4.1.0"
end

group :development do
  gem 'annotate', '2.5.0'
  gem "quiet_assets", ">= 1.0.1"
end

 group :test do
  gem 'capybara', ">= 1.1.2"
 gem "email_spec", ">= 1.2.1"
 gem "cucumber-rails", ">= 1.3.0", :require => false
 gem "database_cleaner", ">= 0.9.1"
 gem "launchy", ">= 2.1.2"
 gem 'rb-fsevent', '0.9.1', :require => false
 gem 'growl', '1.0.3'
 gem 'terminal-notifier-guard'
end

group :production do
    gem 'pg', '0.12.2'
 end

There's another user who had issues with this basic task, but it turned out it was simply a syntax error (see Login integration test with rspec/devise) so I'm sure I'm just missing something very obvious.

Update:

You have got to be kidding me. After leaving it for a couple hours, it turns out I had this spec for some reason in spec/controllers, when simply switching it over to spec/requests made everything green.

I quote:

If you are using Rails, put your Capybara specs in spec/requests or spec/integration.

Found at https://github.com/jnicklas/capybara#readme

However, I'm still wondering how for future requirements I can do integration tests on my controllers that will need to have a logged in user.... for other non-Devise apps in the past, this has been as simple as something like the following:

describe SomeController do

  let(:user) { FactoryGirl.create(:user) }

  before { valid_sign_in user }

...

where my helper is simply

  def valid_sign_in(user)
    visit signin_path
    fill_in "Email", with: user.email
    fill_in "Password", with: user.password
    uncheck(:remember_me)
    click_button "Sign In"

    # Sign in when not using Capybara as well.
    cookies[:remember_token] = user.remember_token
  end

解决方案

There are two issues at play:

1. rspec/controller vs rspec/requests

I was attempting to do an integration test under spec/controller. As per https://github.com/jnicklas/capybara#readme, you need to put Capybara specs in spec/requests or spec/integration. As per https://stackoverflow.com/a/5803121/9344:

A request spec is a thin wrapper around ActionDispatch::IntegrationTest, which doesn't work like controller specs (which wrap ActionController::TestCase). Even though there is a session method available, I don't think it is supported (i.e. it's probably there because a module that gets included for other utilities also includes that method).

Originally this could be solved with Devise via a helper method something like:

# file: spec/requests_helper.rb
def login(user)
  post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
end

But the official/latest solution, which I had implemented already (but see point two below for why it didn't solve my issue), can be found at https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara

2. Devise::HelperTests are for controller/view tests, not integration tests.

If I want to do some tests on a controller, I can use the Devise::TestHelpers (referenced via spec_helper.rb) but even then I don't get functionality for Capybara integration tests as the Devise::TestHelpers are specifically written for controller/view tests, not integration tests. See rspec & devise test helpers.

In summary, what I wanted to do in a controller test can't be done because it was really an integration test and the session etc. isn't available for use in spec/controllers. However, there are some Devise test helpers that can be used to help do controller/view tests.

UPDATE

I revisited this much later, and have now got the Warden helpers functioning on my integration tests. Hurrah! This has taken off 8-10 seconds on my 448 tests. The trick was a new entry on https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara. Specifically:

Capybara-Webkit

If you have trouble using Warden's login_as method with the capybara-webkit driver, try setting run_callbacks to false in the login_as options struct

user = Factory.create(:user) 
login_as(user, :scope => :user,
:run_callbacks => false)

In summary, instead of having to do an actual form fill and post for each time I needed an authenticated user for an integration test, now I just need login_as(user, :scope => :user, :run_callbacks => false) (of course refactored out into a helper method).

这篇关于Capybara、Devise、CanCan 和 RSpec 集成测试:有效登录 302 重定向到 example.com的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆