使用RSpec+Poltergeist测试Rails功能时authenticity_token失败
我之前用Poltergeist做Rails JS功能测试时,也碰到过完全一样的CSRF验证失败问题,结合你的代码场景,给你几个实用的解决方案:
1. 修正Devise login_as 的调用逻辑
JS测试的浏览器会话是独立的,Devise默认的login_as可能没法正确初始化会话。你试过的带参数写法方向是对的,但可以调整run_callbacks参数试试:
login_as(owner, scope: :user, run_callbacks: true)
run_callbacks: true会确保Devise执行完整的登录回调流程,包括设置必要的会话Cookie,这在无头浏览器环境下是关键。同时要确认你的rails_helper.rb里已经引入了Devise测试模块:include Devise::Test::IntegrationHelpers。
2. 确认表单中存在Authenticity Token
Rails的form_with/form_for会自动生成authenticity_token隐藏字段,但如果是手动写的表单或者视图有自定义逻辑,可能会丢失这个字段。你可以在测试里加调试代码,查看页面实际HTML:
scenario 'successfully', js: true do save_and_open_page # 生成临时页面,直接查看HTML结构 # ... 原有测试代码 end
如果确实没有这个字段,就在表单里手动添加:
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
3. 检查Poltergeist的会话与Cookie配置
Poltergeist的默认配置偶尔会导致会话丢失,确保你的spec_helper.rb里的驱动配置启用了Cookie支持:
Capybara.register_driver :poltergeist do |app| Capybara::Poltergeist::Driver.new(app, { cookies: true, js_errors: false, # 避免无关JS错误中断测试 timeout: 30 }) end Capybara.javascript_driver = :poltergeist
另外,在before块里可以加一句Capybara.reset_session!,清空残留的会话数据,有时候能解决奇怪的会话问题。
4. 临时禁用CSRF验证(仅测试环境,不推荐生产)
如果以上方法都没效果,作为临时调试手段,可以在test环境的ApplicationController里添加:
skip_before_action :verify_authenticity_token, if: -> { Rails.env.test? }
这只是权宜之计,尽量找到根本原因再移除,毕竟CSRF验证是重要的安全机制。
最后建议你先确认登录是否真的生效——比如在visit new_listing_path后,断言页面显示了登录用户的标识(比如用户名),如果登录失败,页面可能被重定向到登录页,此时提交的表单自然会因为没有正确的token而失败。
内容的提问来源于stack exchange,提问作者DaniG2k

