Rails - 失去与集成测试和 Capybara 的会话 - CSRF 相关?
我正在使用 Rails 3.1.0.rc4,并且正在使用 capybara 的新 Steak-like DSL 和 Rspec(使用 Devise 身份验证)进行集成测试。
我遇到的问题是,当我运行集成测试时,机架来自水豚的测试驱动程序似乎完全丢失了用户登录的会话,事实上,会话似乎完全清除了。
经过几天的调试,我完全不知道为什么。通过逐行检查中间件堆栈,我相信我已经将问题归结为导致此问题的 ActiveRecord::SessionStore
中发生的事情。我在此处读到,如果可以的话,Rails 将清除会话' t 验证 CSRF 令牌,这让我相信我配置了错误,并且由于某种原因,这个测试没有正确验证 CSRF 令牌。
这是我的 /initializers 目录中的 session_store.rb 中的内容:
MyApp::Application.config.session_store :active_record_store
有谁了解 Rails 中的 CSRF 保护,有任何线索可以解释为什么会发生这种情况吗?
另外,这里有一些需要注意的事情:
- 我试图测试的东西实际上在浏览器本身内工作,只有这一个测试正在删除会话,
- 在提交操作网址为的表单后,会话似乎被删除到另一台服务器。我在测试中使用 VCR gem 捕获对此外部服务器的请求/响应,虽然我相信我已经将外部请求视为问题,但这可能与 CSRF 令牌未进行身份验证直接相关,从而清除会话。
- 涉及登录/使用会话的其他测试不会删除会话
任何人都可以给我任何关于这里到底发生了什么的线索,以及为什么一个测试似乎任意删除其会话并在我身上失败?我已经做了很多调试,并尝试了我能想到的一切。
I'm using Rails 3.1.0.rc4 and I'm working on doing integration tests with capybara's new Steak-like DSL and Rspec (using Devise authentication)
The issue I'm having is that when I run an integration test, the rack-test driver from capybara seems to just completely lose the user's logged in session, in fact, the session seems to just clear out altogether.
After days of debugging, I'm at a complete loss as to why. Going line by line through the middleware stack, I believe I've ruled the problem down to something going on in the ActiveRecord::SessionStore
that is causing this. I've read here that Rails will clear out a session if it can't validate the CSRF token, which leaves me to believe that I've got something configured wrong, and for some reason this one test is not authenticating the CSRF token correctly.
This is what is in my session_store.rb in the /initializers directory:
MyApp::Application.config.session_store :active_record_store
Does anyone who knows about CSRF protection in rails have any leads on why this may be happening?
Also, here are some things to note:
- the thing I'm trying to test actually works within the browser itself, only this one test is dropping the session
- the session seems to get dropped after the submission of a form to which the action url is to another server. I'm using the VCR gem for capturing the requests/responses to this external server in the test, and while I believe I've ruled the external request as the problem, this may have something directly to do with the CSRF token not authenticating, thus clearing out the session.
- other tests involving logging in / using sessions are not dropping sessions
Can anyone give me any leads as to what is going on here exactly, and why the one test just seems to arbitrarily drop its session and fail on me? I've done lots of debugging and have tried everything I can possible think of.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我也是水豚新手,也遇到了类似的问题。
我试图登录用户做这样的事情:
并且工作正常,直到我尝试用水豚做一些事情,例如访问页面并测试用户是否登录。这个简单的测试没有通过:
首先我以为水豚正在清除会话,但我错了。我花了一些时间才意识到,水豚驱动程序正在使用处理自己的会话,因此,从水豚的角度来看,我的用户从未登录过。为此,您必须这样做
不确定是否这是你的情况,但希望有所帮助。
I'm new to capybara too and I was having a similar problem.
I was trying to login a user doing something like this:
And that was working ok until I tried to do something with capybara, such as visiting a page and just testing if the user was logged in. This simple test was not passing:
At first I thought capybara was clearing the sessions but I was wrong. The thing that took me some time to realize is that the driver capybara is using handles its own sessions, so, from the point of view of capybara my user was never logged in. To do so you have to do it like this
Not sure if this is your case, but hope that helps.
我可以通过在 config/initializers/test.rb 中将此值设置为 true 来修复此错误
之前,CSRF
标记未打印到
中。
。改变这个值后,它们终于出现了。I was able to fix this error by setting this value to true in config/initializers/test.rb
Beforehand, the CSRF
<meta>
tags were not printing out to the<head>
. After changing this value they finally appear.手动执行此操作的方法非常简单:
然后您可以将其分解为“spec_helper.rb”中的一个函数:
并在任何测试中使用它(可能是请求规范):
The manual way of doing it is very simple:
You can then break this out into a function in your 'spec_helper.rb':
and use it in any of your tests (probably request specs):
这可能不太可能,但我相信在
click_button 'Sign in'
并立即调用visit else
后,我们最终会处于糟糕的状态。我的理论是,当我们单击按钮时,请求尚未完成,我们通过访问另一条路径来终止它。
来自水豚文档:
如果是这种情况,解决方案很简单:给水豚一些东西来寻找并让它等待,直到请求完成。这可以很简单,只需添加:
expect(page).to have_text('Signed in as [电子邮件受保护]')
This might be a long shot but I believe we end up in a bad state after
click_button 'Sign in'
and callingvisit elsewhere
immediately after.My theory is that when we click the button the request hasn't completed yet, and we kill it by visiting another path.
From the Capybara documentation:
If this is the case the solution is simple: give Capybara something to look for and let it wait until the request is complete. This can be as simple as adding:
expect(page).to have_text('Signed in as [email protected]')