我正在使用Rails 3.1.0.rc4,我正在与capybara的新型类似DSL和Rspec(使用Devise身份验证)进行集成测试
我遇到的问题是,当我运行集成测试时,来自capybara的机架测试驱动程序似乎完全失去了用户的登录会话,事实上,会话似乎只是完全清除了。
经过几天的调试,我完全失去了原因。逐行通过中间件堆栈,我相信我已经将问题排除在导致此问题的ActiveRecord::SessionStore
中。我已经读过here,如果Rails无法验证CSRF令牌,Rails会清除会话,这让我相信我的配置错误了,并且由于某种原因,这个测试没有验证正确的CSRF令牌。
这是我在/ initializers目录中的session_store.rb中的内容:
MyApp::Application.config.session_store :active_record_store
是否有人知道铁轨中的CSRF保护有任何线索可以解释为什么会这样?
此外,还有一些注意事项:
任何人都可以给我任何关于这里发生了什么的线索,以及为什么一个测试似乎随意地放弃了它的会话而对我失败了?我做了很多调试,并尝试了我能想到的一切。
答案 0 :(得分:20)
我也是水豚的新手,我遇到了类似的问题。
我试图以这样的方式登录用户:
post user_session_path, :user => {:email => user.email, :password => 'superpassword'}
在我尝试使用capybara做某事之前一直工作正常,例如访问页面并测试用户是否已登录。这个简单的测试没有通过:
visit root_path
page.should have_content("logout") #if the user is logged in then the logout link should be present
起初我认为水豚正在清理会议,但我错了。花了我一些时间才意识到的事情是驱动程序capybara正在使用句柄自己的会话,因此,从水豚的角度来看,我的用户从未登录。为此,你必须这样做
page.driver.post user_session_path, :user => {:email => user.email, :password => 'superpassword'}
不确定这是否属于您的情况,但希望有所帮助。
答案 1 :(得分:7)
手动方式非常简单:
it "does something after login" do
password = "secretpass"
user = Factory(:user, :password => password)
visit login_path
fill_in "Email", :with => user.email
fill_in "Password", :with => password
click_button "Log in"
visit # somewhere else and do something
end
然后您可以将其分解为'spec_helper.rb'中的函数:
# at the bottom of 'spec_helper.rb'
def make_user_and_login
password = "secretpass"
@user = Factory(:user, :password => password)
visit login_path
fill_in "Email", :with => @user.email
fill_in "Password", :with => password
click_button "Log in"
end
并在任何测试中使用它(可能是请求规范):
it "does something after login" do
make_user_and_login
# now test something that requires a logged in user
# you have access to the @user instance variable
end
答案 2 :(得分:5)
我能够通过在config / initializers / test.rb中将此值设置为true来修复此错误
# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = true
事先,CSRF <meta>
代码未打印到<head>
。更改此值后,它们最终会出现。
答案 3 :(得分:0)
这可能是一个很长的镜头,但我相信我们会在click_button 'Sign in'
之后最终处于不良状态,并且会立即致电visit elsewhere
。
我的理论是,当我们点击按钮时,请求尚未完成,我们通过访问另一条路径来杀死它。
来自Capybara文档:
向DSL发出指令时,例如:
click_link('foo') click_link('bar') expect(page).to have_content('baz')
如果单击foo链接会触发异步进程,例如Ajax请求,当完成时会向页面添加条形链接,单击条形链接将会失败,因为该链接没有#39但是还存在。 然而,Capybara非常聪明,在放弃并抛出错误之前,会在短时间内重新找到该链接。
如果是这种情况,解决方案很简单:给Capybara寻找一些东西,让它等到请求完成。这可以像添加:
一样简单 expect(page).to have_text('Signed in as bob@example.com')