Rspec 使用可选的语言环境路径查看测试

Rspec view test with optional locale path

我的路线中有一个可选的语言环境参数。

# config/routes.rb
  scope '(:locale)' do
    resources :orders
    resources :line_items
    resources :carts
    root 'store#index', as: 'store_index', via: :all
  end
# config/initializers/i18n.rb
#encoding: utf-8
I18n.default_locale = :en

LANGUAGES = [
  ['English',                  'en'],
  ["Español".html_safe, 'es']
]

如果我想像这样测试我的观点,

# /spec/views/carts/edit.html.erb_spec.rb
require 'rails_helper'

RSpec.describe "carts/edit", type: :view do
  let(:cart) { create(:cart) }

  before(:each) do
    assign(:cart, cart)
  end

  it "renders the edit cart form" do
    render

    assert_select "form[action=?][method=?]", cart_path(cart), "post" do
    end
  end
end

我收到一个错误

/Users/burak/.rvm/rubies/ruby-2.7.3/bin/ruby -I/Users/burak/.rvm/gems/ruby-2.7.3/gems/rspec-core-3.10.1/lib:/Users/burak/.rvm/gems/ruby-2.7.3/gems/rspec-support-3.10.2/lib /Users/burak/.rvm/gems/ruby-2.7.3/gems/rspec-core-3.10.1/exe/rspec spec/views/carts/edit.html.erb_spec.rb
F

Failures:

  1) carts/edit renders the edit cart form
     Failure/Error: <%= form_with(model: cart) do |form| %>

     ActionView::Template::Error:
       No route matches {:action=>"show", :controller=>"carts", :format=>nil, :locale=>#<Cart id: 1252, created_at: "2021-04-27 13:45:09.842106000 +0000", updated_at: "2021-04-27 13:45:09.842106000 +0000">}, missing required keys: [:id]
       Did you mean?  cart_url
                      carts_url
                      carts_path
                      new_cart_url
     # ./app/views/carts/_form.html.erb:1:in `_app_views_carts__form_html_erb__2203507052991398875_16560'
     # ./app/views/carts/edit.html.erb:3:in `_app_views_carts_edit_html_erb___4312857554407673387_16540'
     # ./spec/views/carts/edit.html.erb_spec.rb:11:in `block (2 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # ActionController::UrlGenerationError:
     #   No route matches {:action=>"show", :controller=>"carts", :format=>nil, :locale=>#<Cart id: 1252, created_at: "2021-04-27 13:45:09.842106000 +0000", updated_at: "2021-04-27 13:45:09.842106000 +0000">}, missing required keys: [:id]
     #   Did you mean?  cart_url
     #                  carts_url
     #                  carts_path
     #                  new_cart_url
     #   ./app/views/carts/_form.html.erb:1:in `_app_views_carts__form_html_erb__2203507052991398875_16560'

Finished in 0.02277 seconds (files took 0.60597 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/views/carts/edit.html.erb_spec.rb:10 # carts/edit renders the edit cart form

据我所知,这是因为我的购物车对象通过 :locale 关键字传递到某个地方。如果我在我的 _form 部分中显式地将 URL 传递给 form_with,则错误会消失,但随后会破坏其他一些测试。我该如何解决这个问题?

这是必要的部分和视图。

# app/views/carts/edit.html.erb
<h1>Editing Cart</h1>

<%= render 'form', cart: @cart %>

<%= link_to 'Show', @cart %> |
<%= link_to 'Back', carts_path %>
# app/views/carts/_form.html.erb
<%= form_with(model: cart) do |form| %>
  <% if cart.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(cart.errors.count, "error") %> prohibited this cart from being saved:</h2>

      <ul>
        <% cart.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

因此您的表单要指向的 URL 的路由是(在您将从 rails routes 中看到的格式中):

(/:locale)/carts/:id(.:format)

看起来正在发生的事情是,当您的视图规范正在呈现时,它会调用 cart_path(cart) 来构建表单的 action 属性。发生的事情是辅助方法 cart_path 尝试从左到右填充路径的参数化部分,它使用 cart 尝试填充 :locale 段而不是:id 段。

rails server 中的控制器操作呈现的上下文中,您不会看到这种情况发生,因为控制器具有 locale 具有默认值的概念,因此它理解 cart 代表路径的第二个 :id 部分。

如果你想确保你的视图在单独测试时表现相似,那么你可以在你的路由文件中添加一个默认值:

scope '(:locale)', defaults: { locale: 'en' } do
  ...

并在您的 config/environments/test.rb 中添加另一个默认值:

Rails.application.configure do
 # ...
 routes.default_url_options[:locale] = 'en'
end

routes.rb中设置默认值将允许您的视图文件正确生成有效路径;添加 default_url_options 意味着您可以在视图规范中写入 cart_path(cart),它会知道默认使用 'en' 作为语言环境。没有它,您必须断言操作路径是 cart_path(cart, locale: 'en').