Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rspec for mailers with I18n

I don't understand how to test with rspec and internationalization. For example, in requests tests I do

I18n.available_locales.each do |locale|
  visit users_path(locale: locale)
  #...
end

and it works just fine: every locale tests correct.

But in mailers this trick doesn't work.

user_mailer_spec.rb

require "spec_helper"

describe UserMailer do
  I18n.available_locales.each do |locale|
    let(:user) { FactoryGirl.build(:user, locale: locale.to_s) }
    let(:mail_registration) { UserMailer.registration_confirmation(user) }

    it "should send registration confirmation" do
      puts locale.to_yaml
      mail_registration.body.encoded.should include("test") # it will return error with text which allow me to ensure that for each locale the test call only :en locale email template
    end
  end
end

It runs few times (as many as many locales I have), but every time it generate html for the default locale only.

When I call UserMailer.registration_confirmation(@user).deliver from controller, it works fine.

user_mailer.rb

...
def registration_confirmation(user)
  @user = user
  mail(to: user.email, subject: t('user_mailer.registration_confirmation.subject')) do |format|
      format.html { render :layout => 'mailer'}
      format.text
  end
end
...

views/user_mailer/registration_confirmation.text.erb

<%=t '.thx' %>, <%= @user.name %>.
<%=t '.site_description' %>
<%=t '.credentials' %>:
<%=t '.email' %>: <%= @user.email %>
<%=t '.password' %>: <%= @user.password %>
<%=t '.sign_in_text' %>: <%= signin_url %>
---
<%=t 'unsubscribe' %>

I repeat - it works fine for all locales. I have the question only about rspec tests for it.

like image 971
alex Avatar asked Dec 14 '12 08:12

alex


2 Answers

I think you may have to wrap your test in a describe/context block to allow the it block to see your let variables:

require "spec_helper"

describe UserMailer do
  I18n.available_locales.each do |locale|
    describe "registration" do
      let(:user) { FactoryGirl.build(:user, locale: locale.to_s) }
      let(:mail_registration) { UserMailer.registration_confirmation(user) }

      it "should send registration confirmation" do
        puts locale.to_yaml
        mail_registration.body.encoded.should include("test")
      end
    end
    # ...
  end
  # ...
end

As for why, perhaps this StackOverflow answer on let variable scoping may help.

Edit

Is the issue that you've assigned a locale to your user, but you don't pass it into the mail method anywhere? Perhaps this StackOverflow answer would be of reference. Hopefully one of the two answers there would be relevant in your situation. Here's my simple attempt at adapting the first answer there to your situation (untested obviously):

user_mailer.rb

...
def registration_confirmation(user)
  @user = user
  I18n.with_locale(user.locale) do
    mail(to: user.email, 
             subject: t('user_mailer.registration_confirmation.subject')) do |format|
      format.html { render :layout => 'mailer' }
      format.text
    end
  end
end
... 
like image 175
Paul Fioravanti Avatar answered Nov 10 '22 15:11

Paul Fioravanti


You probably need to specify the locale, as in:

mail_subscribe.body.encoded.should include(t('user_mailer.subscribe_confirmation.stay', locale: locale))

You can also try adding I18n.locale = user.locale right before the mail call in the registration_confirmation method.

like image 25
eugen Avatar answered Nov 10 '22 15:11

eugen