RSpec,水豚:redirect_to 在 create/post 规范中不工作
RSpec, Capybara: redirect_to not working in create/post specs
我根据 feature_spec:
设置了一个简单的控制器
stamps_controller.rb
class StampsController < ApplicationController
def new
@stamp = Stamp.new
end
def create
@stamp = Stamp.new(stamp_params)
if @stamp.save
redirect_to(stamp_url(@stamp.id), status: 201)
else
render 'new'
end
end
def show
@stamp = Stamp.find(params[:id])
end
private
def stamp_params
params.require(:stamp).permit(::percentage)
end
end
specs/requests/stamps_request_spec.rb
RSpec.describe 'stamp requests', type: :request do
describe 'stamp creation', js: true do
before do
FactoryBot.create_list(:domain, 2)
FactoryBot.create_list(:label, 2)
end
it 'allows users to create new stamps' do
visit new_stamp_path
expect(page).to have_content('Percentage')
find('#stamp_percentage').set('20')
click_button 'Create'
expect(current_path).to eq(stamp_path(Stamp.first.id))
end
end
end
Capybara automatically follows any redirects, and submits forms associated with buttons.
但这在测试中并没有发生,而是抛出一个错误:
expected: "/stamps/1
got: "/stamps"
结果很明显:它成功创建了图章,但无法重定向到新图章。我还通过使用 binding.pry
.
确认了这一点
为什么水豚不遵循文档中描述的重定向?
旁注:
- 如果我使用普通驱动而不是js,它甚至会失败
- 我研究了很多 SO 问题和文档,没有找到任何有用的东西。我无法理解的一个潜在尝试是 answer with no specifics of how to implement it.
- 我的配置:
support/capybara.rb
require 'capybara/rails'
require 'capybara/rspec'
Capybara.server = :puma
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, browser: :firefox, marionette: true)
end
Capybara.javascript_driver = :selenium
RSpec.configure do |config|
config.include Capybara::DSL
end
spec_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
require 'rspec/rails'
require 'factory_bot_rails'
require 'pundit/matchers'
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
RSpec.configure do |config|
# .
# unrelated stuff
# .
end
问题可能是 current_path
在提交表单后需要一些时间才能更改。如果您将 sleep(x)
放在 expect(current_path)
之前,您的代码将起作用。
相反,您应该使用具有所谓 "waiting behaviour" 的方法,例如 has_current_path?
、have_current_path
、assert_current_path
:
expect(page).to have_current_path(stamp_path(Stamp.first.id))
或
expect(page.has_current_path?(stamp_path(Stamp.first.id))).to eq true
您的测试中有很多问题。
首先,水豚不适用于 request
规范 - https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec - but should instead be used with feature/system tests. Once you've fixed that you should no longer need to include Capybara into every RSpec test and should remove the config.include Capybara::DSL
from you config (when you require capybara/rspec
it includes Capybara into the test types it should be included in - https://github.com/teamcapybara/capybara/blob/master/lib/capybara/rspec.rb#L10)
其次,click_button
不能保证等待它触发的任何操作完成。因此,在尝试访问将由该操作创建的任何数据库对象之前,您需要等待可视页面更改(从技术上讲,您实际上根本不应该在功能规范中进行直接数据库访问,但如果您要...)
click_button 'Create'
expect(page).to have_text('Stamp created!') # Whatever message is shown after creation
# Now you can safely access the DB for the created stamp
第三,正如@chumakoff 所指出的,您不应该对 Capybara 使用静态匹配器,而应该使用 Capybara 提供的匹配器
click_button 'Create'
expect(page).to have_text('Stamp created!') # Whatever message is shown after creation
expect(page).to have_path(stamp_path(Stamp.first.id))
最后,您应该查看您的 test.log
并使用 save_and_open_screenshot
来查看您的控制器实际做了什么 - 实际上在创建时出现错误导致您的应用程序重定向到/stamps 并显示错误消息(这也意味着您的测试数据库实际上并未在测试之间重置,或者您显示的工厂正在创建嵌套记录等)。
更新: 重新阅读您的控制器代码后,我注意到您将 201 状态代码传递给 redirect_to
。 201
实际上不会进行重定向 - 来自 redirect_to
文档 - https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to
Note that the status code must be a 3xx HTTP code, or redirection will
not occur.
对于其他来这里的人,另一种可能的解决方案是增加等待时间。全局或每次点击
# Globally
Capybara.default_max_wait_time = 5
# Per Click
find("#my-button").click(wait: 5)
我根据 feature_spec:
设置了一个简单的控制器stamps_controller.rb
class StampsController < ApplicationController
def new
@stamp = Stamp.new
end
def create
@stamp = Stamp.new(stamp_params)
if @stamp.save
redirect_to(stamp_url(@stamp.id), status: 201)
else
render 'new'
end
end
def show
@stamp = Stamp.find(params[:id])
end
private
def stamp_params
params.require(:stamp).permit(::percentage)
end
end
specs/requests/stamps_request_spec.rb
RSpec.describe 'stamp requests', type: :request do
describe 'stamp creation', js: true do
before do
FactoryBot.create_list(:domain, 2)
FactoryBot.create_list(:label, 2)
end
it 'allows users to create new stamps' do
visit new_stamp_path
expect(page).to have_content('Percentage')
find('#stamp_percentage').set('20')
click_button 'Create'
expect(current_path).to eq(stamp_path(Stamp.first.id))
end
end
end
Capybara automatically follows any redirects, and submits forms associated with buttons.
但这在测试中并没有发生,而是抛出一个错误:
expected: "/stamps/1
got: "/stamps"
结果很明显:它成功创建了图章,但无法重定向到新图章。我还通过使用 binding.pry
.
为什么水豚不遵循文档中描述的重定向?
旁注:
- 如果我使用普通驱动而不是js,它甚至会失败
- 我研究了很多 SO 问题和文档,没有找到任何有用的东西。我无法理解的一个潜在尝试是 answer with no specifics of how to implement it.
- 我的配置:
support/capybara.rb
require 'capybara/rails'
require 'capybara/rspec'
Capybara.server = :puma
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, browser: :firefox, marionette: true)
end
Capybara.javascript_driver = :selenium
RSpec.configure do |config|
config.include Capybara::DSL
end
spec_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
require 'rspec/rails'
require 'factory_bot_rails'
require 'pundit/matchers'
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
RSpec.configure do |config|
# .
# unrelated stuff
# .
end
问题可能是 current_path
在提交表单后需要一些时间才能更改。如果您将 sleep(x)
放在 expect(current_path)
之前,您的代码将起作用。
相反,您应该使用具有所谓 "waiting behaviour" 的方法,例如 has_current_path?
、have_current_path
、assert_current_path
:
expect(page).to have_current_path(stamp_path(Stamp.first.id))
或
expect(page.has_current_path?(stamp_path(Stamp.first.id))).to eq true
您的测试中有很多问题。
首先,水豚不适用于 request
规范 - https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec - but should instead be used with feature/system tests. Once you've fixed that you should no longer need to include Capybara into every RSpec test and should remove the config.include Capybara::DSL
from you config (when you require capybara/rspec
it includes Capybara into the test types it should be included in - https://github.com/teamcapybara/capybara/blob/master/lib/capybara/rspec.rb#L10)
其次,click_button
不能保证等待它触发的任何操作完成。因此,在尝试访问将由该操作创建的任何数据库对象之前,您需要等待可视页面更改(从技术上讲,您实际上根本不应该在功能规范中进行直接数据库访问,但如果您要...)
click_button 'Create'
expect(page).to have_text('Stamp created!') # Whatever message is shown after creation
# Now you can safely access the DB for the created stamp
第三,正如@chumakoff 所指出的,您不应该对 Capybara 使用静态匹配器,而应该使用 Capybara 提供的匹配器
click_button 'Create'
expect(page).to have_text('Stamp created!') # Whatever message is shown after creation
expect(page).to have_path(stamp_path(Stamp.first.id))
最后,您应该查看您的 test.log
并使用 save_and_open_screenshot
来查看您的控制器实际做了什么 - 实际上在创建时出现错误导致您的应用程序重定向到/stamps 并显示错误消息(这也意味着您的测试数据库实际上并未在测试之间重置,或者您显示的工厂正在创建嵌套记录等)。
更新: 重新阅读您的控制器代码后,我注意到您将 201 状态代码传递给 redirect_to
。 201
实际上不会进行重定向 - 来自 redirect_to
文档 - https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to
Note that the status code must be a 3xx HTTP code, or redirection will not occur.
对于其他来这里的人,另一种可能的解决方案是增加等待时间。全局或每次点击
# Globally
Capybara.default_max_wait_time = 5
# Per Click
find("#my-button").click(wait: 5)