django09
django09

Reputation: 235

Rspec view specs broken by default_locale

I localized my Rails app recently and added a default locale of 'en' (I followed the directions here for adding locales into my URLs). This broke most of my specs; I've been able to figure out solutions/workarounds for all of them except for my View specs.

Here's an example of a basic view spec that is broken, my articles view spec:

RSpec.describe 'articles/index', type: :view do
  before(:each) do
    assign(:articles, [
      FactoryGirl.create(:article, number: '11.22.33'),
      FactoryGirl.create(:article, number: '22.33.44')
    ])
  end

  it 'renders a list of articles' do
    render
  end
end

This spec results in the following error:

 1) articles/index renders a list of articles
     Failure/Error: render
     ActionView::Template::Error:
       No route matches {:action=>"show", :controller=>"articles", :id=>nil, :locale=>#<Article id: 2, number: "11.22.33", criminal_code_id: 3, description: nil, created_at: "2015-05-25 08:58:56", updated_at: "2015-05-25 08:58:56">} missing required keys: [:id, :locale]

Seems like there are three problems:

  1. Rspec should be using action "index" instead of "show"
  2. There should be no required :id key for "index" action
  3. The locale should be "en" instead of one of the articles I created.

Here are my relevant routes:

Rails.application.routes.draw do
  scope ':locale', locale: /#{I18n.available_locales.join("|")}/ do
    resources :articles do
      collection do
        get 'custom_json', constraints: { format: :json }, defaults: { format: :json }
      end
    end

    get "*path", to: redirect("/#{I18n.default_locale}") # handles /en/fake/path/whatever
  end

  get '', to: redirect("/#{I18n.default_locale}") # handles /
  get '*path', to: redirect("/#{I18n.default_locale}/%{path}") # handles /not-a-locale/anything
end

Here's the relevant part of my application controller:

before_action :set_locale

def set_locale
  I18n.locale = params[:locale] || I18n.default_locale
end

def default_url_options(options = {})
  { locale: I18n.locale }.merge options
end

And my article view is at app/views/articles/index.html.erb (there's nothing out of the ordinary about it).

Anybody have an idea on how to get View specs to play nice with locales?

Upvotes: 2

Views: 1521

Answers (2)

Joshua Muheim
Joshua Muheim

Reputation: 13195

The following may help you:

# Set locale for view specs, see https://github.com/rspec/rspec-rails/issues/255#issuecomment-2865917
class ActionView::TestCase::TestController
  def default_url_options(options = {})
    {locale: I18n.default_locale}
  end
end

# Set locale for feature specs, see https://github.com/rspec/rspec-rails/issues/255#issuecomment-24698753
RSpec.configure do |config|
  config.before(:each, type: :feature) do
    default_url_options[:locale] = I18n.default_locale
  end
end

It helped in my case. Still, I find it quite awkward that after so many years of Rails I18n one still has to care about such things oneself.

Upvotes: 9

ryan2johnson9
ryan2johnson9

Reputation: 724

Here is a potential workaround while you wait for someone to post a better answer:

Looks like you are doing a link_to in your index page for each of your articles. The url helper call in the link_to, e.g. article_path is where your spec may be breaking. I was having a similar problem and could not solve it. The url_helper methods did not work the same way for me in test env as they did in dev or prod env. More specifically, in test env they did not work unless I explicitly declared the locale in the url_helper call using locale: 'en'.

I looked around for a long time and could not work out why.

So I decided just to stub out the calls to url_helpers in my view spec like this

allow(view).to receive(:conversation_transmission_path).and_return("/")
allow(view).to receive(:edit_conversation_transmission_path).and_return("/")

that is rspec 3.2 syntax

Upvotes: 0

Related Questions