Rails – 与集成测试和Capybara失去会话 – CSRF相关?

我正在使用Rails 3.1.0.rc4,我正在与capybara的新类似DSL和Rspec进行集成测试(使用Devise身份validation)

我遇到的问题是,当我运行集成测试时,来自capybara的机架测试驱动程序似乎完全失去了用户的登录会话,事实上,会话似乎完全清除了。

经过几天的调试,我完全不知道为什么。 逐行通过中间件堆栈,我相信我已经将问题排除在导致这种情况的ActiveRecord::SessionStore中。 我在这里读到如果无法validationCSRF令牌,Rails将清除会话,这让我相信我的配置错误,并且由于某种原因,这个测试没有正确validationCSRF令牌。

这是我在/ initializers目录中的session_store.rb中的内容:

 MyApp::Application.config.session_store :active_record_store 

知道有关铁路CSRF保护的人是否有任何线索可以解释为什么会这样?

此外,还有一些注意事项:

  • 我试图测试的东西实际上在浏览器本身内工作,只有这一个测试正在放弃会话
  • 在将操作URL提交到另一个服务器的表单后,会话似乎被删除。 我正在使用VCR gem来捕获测试中对此外部服务器的请求/响应,虽然我认为我已经将外部请求作为问题,但这可能与CSRF令牌没有进行身份validation直接相关,从而清理会话。
  • 涉及登录/使用会话的其他测试不会丢弃会话

任何人都可以给我任何关于这里发生了什么的线索,以及为什么一个测试似乎随意地放弃了它的会话而对我失败了? 我做了很多调试,并尝试了我能想到的一切。

我也是水豚的新手,我遇到了类似的问题。

我试图登录用户执行以下操作:

 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正在使用句柄自己的会话,因此,从capybara的角度来看,我的用户从未登录过。为此,你必须这样做

 page.driver.post user_session_path, :user => {:email => user.email, :password => 'superpassword'} 

不确定这是否是你的情况,但希望有所帮助。

手动方式非常简单:

 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 

我能够通过在config / initializers / test.rb中将此值设置为true来修复此错误

 # Disable request forgery protection in test environment config.action_controller.allow_forgery_protection = true 

事先,CSRF 标签没有打印到 。 更改此值后,它们最终会出现。

这可能是一个长镜头,但我相信我们在click_button 'Sign in'之后最终处于一个糟糕的状态,并在之后立即呼叫visit elsewhere

我的理论是,当我们点击按钮时,请求尚未完成,我们通过访问另一条路径来杀死它。

从Capybara文档:

向DSL发出指令时,例如:

click_link('foo') click_link('bar') expect(page).to have_content('baz')

如果单击foo链接会触发异步进程,例如Ajax请求,当完成时会向页面添加bar链接,单击bar链接将会失败,因为该链接尚不存在。 然而,Capybara足够聪明,可以在放弃并抛出错误之前重试一段短暂的链接

如果是这种情况,解决方案很简单:给Capybara寻找一些东西,让它等到请求完成。 这可以像添加一样简单:

expect(page).to have_text('Signed in as bob@example.com')

Interesting Posts