Capybara,Devise,CanCan和RSpec集成测试:有效登录302重定向到example.com [英] Capybara, Devise, CanCan and RSpec integration tests: valid sign in 302 redirects to example.com
问题描述
更新:有关规范现在的工作原理,请参阅我们的规范/ spec,而不是spec / controllers。仍然想知道如何获得一个有效的登录用户进行集成测试与我的控制器。
我正在与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-devise 和 Capybara,RSpec和Devise:任何方式使集成t可以通过避免缓慢的登录和直接设置会话来加快收益?,但是我一直无法按期望得到一个标准的职位,我感到困惑:
- 开发环境工作正常(可以登录并重定向到正确的页面,导航登录链接更改为注销等)。
- test.log表示没有任何问题,直到302重定向到 http://www.example.com ,而不是我的root_path。
由于具有不同解决方案的类似问题的用户众多,我显然不是唯一一个有这个问题的人,因为各方面会话等在不同的情况下不可用。
剥离测试:
subject {page}
描述'应该能够登录'do
之前
访问'/ users / sign_in'
user = FactoryGirl。 create(:admin)
#user.add_role:a dmin
fill_in'Username',with:user.username
fill_in'Password',with:user.password
click_on'登录'
end
it {should has_link'Logout'}
end
...
相关log.test输出:
启动POST/ users / sign_in为127.0.0.1在2012-11-06 17:31:10 - 0800
Devise :: SessionsController#创建为HTML
参数:{utf8=>✓,user=> {username=>username1,密码=>[FILTERED],remember_me=>0},commit=>登录}
[1m [36mUser Load(0.1ms)[0m [1mSELECT users。* FROMusersWHEREusers。username='username1'LIMIT 1 [0m
[1m [35m(0.0ms)[0m SAVEPOINT active_record_1
[1m [36m 0.0m)[0m [1mRELEASE SAVEPOINT active_record_1 [0m
[1m [35m(0.0ms)] [0m SAVEPOINT active_record_1
[1m [36m(0.1ms)[0m [1mUPDATEusersSETlast_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=' 11- 07 01:31:10.723051'WHEREusers。id= 1 [0m
[1m [35m(0.0ms)] [0m RELEASE SAVEPOINT active_record_1
重定向到http: example.com/
完成302找到12ms(ActiveRecord:0.0ms)
routes.rb:
authenticated:user do
root:to => 'home#index'
end
root:to => home#index
devise_for:users
resources:users
能力:
class能力
包含CanCan ::能力
def initialize(user)
user || = User.new#guest用户(未登录)
如果user.has_role? :admin
可以:管理,全部
结束
...
要彻底,现在的Gemfile:
源'https://rubygems.org'
gem'rails','3.2.8'
gembootstrap-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'
gemdevise,〜> 2.1.2
gemcancan,〜> 1.6.8
gemrolify,〜> 3.2.0
gemsimple_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
组:开发,:test do
gem'sqlite3' '1.3.5'
gemrspec-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'
gemfactory_girl_rails,> = 4.1.0
end
group:development do
gem'annotate','2.5.0'
gemquiet_assets,> = 1.0.1
end
group:test do
gem'capybara',> = 1.1.2
gememail_spec,> = 1.2.1
gemcucumber-rails,> = 1.3.0,:require => false
gemdatabase_cleaner,> = 0.9.1
gemlaunchy,> = 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
还有另一个用户有这个问题基本的任务,但事实证明它只是一个语法错误(请参阅使用rspec登录集成测试/ devise ),所以我确定我只是错过了一些非常明显的东西。
更新:
你必须在开玩笑吧。离开它几个小时后,原来我在spec / controller中有一些原因,当简单的切换到spec /请求使一切都是绿色的。
我引用:
如果您使用Rails,请将您的Capybara规格在规范/请求或
规范/集成中。
在 https://github.com/jnicklas/capybara#readme
然而,我是仍然想知道如何为将来的要求,我可以在我的控制器上进行集成测试,需要有一个登录用户....对于其他非Devise应用程序过去,这已经像以下一样简单: p>
描述SomeController do
let(:user){FactoryGirl.create(:user)}
之前{valid_sign_in user}
...
我的帮手只是简单的
def valid_sign_in(user)
访问signin_path
fill_in电子邮件 :user.email
fill_inPassword,带:user.password
uncheck( :remember_me)
click_button登录
#当不使用Capybara时登录。
cookies [:remember_token] = user.remember_token
end
有两个问题:
1。 rspec / controller vs rspec / requests
我试图在spec / controller下进行集成测试。根据 https://github.com/jnicklas/capybara#readme ,您需要将Capybara规范/请求或规范/集成规范。根据 http://stackoverflow.com/a/5803121/9344 :
请求规范是围绕
ActionDispatch :: IntegrationTest的薄包装,它不像控制器
规范(其中包含ActionController :: TestCase)。即使有一个
会话方法可用,我不认为它是支持的(即它是
可能是因为一个包含其他实用程序
的模块也包括该方法) / p>
最初这可以通过帮助方法解决Devise,如:
#file:spec / requests_helper.rb
def login(user)
post_via_redirect user_session_path,'user [email]'=> user.email,'user [password]'=> user.password
end
但是我已经实现的官方/最新解决方案但是请看下面第二点为什么没有解决我的问题),可以在 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 /色器件/维基/操作方法: - 测试与 - 水豚。具体来说:
Capybara-Webkit
如果您在使用Warden的login_as方法时遇到问题
与capybara-webkit驱动程序,尝试在
中将run_callbacks设置为false login_as选项结构
user = Factory.create(:user)
login_as(user,:scope =>:user,
:run_callbacks => false)
$总而言之,我不需要做一个实际的表单填写和发布,每次我需要经验证的用户进行集成测试时,现在我只需要 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:
- Development environment works fine (can log in and get redirected to proper page, with navigation login link changed to logout, etc.).
- 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 http://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屋!