Wednesday, June 7, 2017

Rspec test for when an I18n key is missing?

Leave a Comment

How do you simulate a missing I18n key in an Rspec test? I have a helper that looks to use a I18n key if its available. I don't know how to create the test case for when it is not available. Based on console testing I'm pretty sure the helper method is correct, but I don't know how to construct the test against that outcome (when all three possible title types are not set).

# app/helpers/application_helper.rb  def available_page_title   title = ""   case   when content_for?(:page_title)     title = content_for(:page_title)   when !@page_title.nil?     title = @page_title   when I18n.exists?('page_title.default')     title = t('page_title.default')   end end 

--

# config/locales/en.yml  en:   page_title:     delimiter: ' - '     default: Default Page Title     admin_namespace: 'Admin'   # spec/helpers/application_helper.rb describe 'available_page_title' do   it '(1) returns the the translation title if no other titles set' do     allow(I18n).to receive(:t).with('page_title.default').and_return("Test Title from i18n")     @page_title = nil     expect(helper.available_page_title).to eq(t('page_title.default'))   end    it '(2) returns the the @page_title if it exists and no content_for exists' do     allow(I18n).to receive(:t).with('page_title.default').and_return("Test Title from i18n")     translation_title = t('page_title.default')     @page_title = "Test Title from @page_title"     expect(helper.available_page_title).to eq(@page_title)   end    it '(3) returns the the content_for title if it exists' do     allow(I18n).to receive(:t).with('page_title.default').and_return("Test Title from i18n")     translation_title = t('page_title.default')     @page_title = "Test Title from @page_title"     helper.content_for(:page_title, 'Test Title from content_for')     expect(helper.available_page_title).to eq('Test Title from content_for')   end    it '(4) returns a blank string if no titles are found' do     # Things I've tried...     # I18n.backend.store_translations(:en, { page_title: { default: '' }})     # I18n.backend.store_translations(:en)     # I18n.backend.store_translations(:en, { nil })     # I18n.backend.store_translations()     # I18n.backend = I18n::Backend::Simple.new     allow(I18n).to receive(:t).with('page_title.default').and_return(nil)     @page_title = nil     expect(helper.available_page_title).to eq('')   end end 

Here's the test results:

$ bundle exec rspec spec/helpers/application_helper_spec.rb:130 Run options: include {:locations=>{"./spec/helpers/application_helper_spec.rb"=>[130]}}  Randomized with seed 14478  ApplicationHelper   available_page_title     (3) returns the the content_for title if it exists     (1) returns the the translation title if no other titles set     (2) returns the the @page_title if it exists and no content_for exists     (4) returns a blank string if no titles are found (FAILED - 1)  Failures:    1) ApplicationHelper available_page_title should (4) return a blank string if no titles are found      Failure/Error: expect(helper.available_page_title).to eq('')         expected: ""             got: "Default Page Title"         (compared using ==)      # ./spec/helpers/application_helper_spec.rb:160:in `block (3 levels) in <top (required)>'  Finished in 0.69197 seconds (files took 4.32 seconds to load) 4 examples, 1 failure  Failed examples:  rspec ./spec/helpers/application_helper_spec.rb:152 # ApplicationHelper available_page_title should (4) return a blank string if no titles are found  Randomized with seed 14478 

Update 2017-05-31

@gwcodes's answer helped a little but still didn't get the test set up properly.

allow(I18n).to receive(:translate).with('page_title.default').and_return(nil) 

Using that line, the test is set up so that there actually is still a key page_title.default, but its value is nil. That's not useful.

What my helper method checks for is the existence of the key. Here's the pry output of the current test situation:

[5] pry(#<RSpec::ExampleGroups::ApplicationHelper::AvailablePageTitle>)> I18n.translate('page_title.default') => nil [6] pry(#<RSpec::ExampleGroups::ApplicationHelper::AvailablePageTitle>)> I18n.exists?('page_title.default') => true [7] pry(#<RSpec::ExampleGroups::ApplicationHelper::AvailablePageTitle>)> I18n.t('page_title.default').empty? => false 

So the question still remains. How do you set the test environment so that a check for the existence of an I18n key returns false?

2 Answers

Answers 1

I did come up with a solution by stubbing an I18n Backend for testing (although it does seem a little like the ball peen hammer approach).

I created spec/support/i18n_simple_stub.rb:

module I18n   module Backend     class SimpleStub       def exists?(key, *args)         false       end     end   end end 

and then set the backend in that (previously failing) test. Here's the new test:

it '(4) returns a blank string if no titles are found' do   # Sets exists? method to false   I18n.backend = I18n::Backend::SimpleStub.new    @page_title = nil   expect(helper.available_page_title).to eq('') end 

If anyone has a better method, I'd love to hear it and learn.

Answers 2

I am thinking to use your first solution into a shared context.

# spec/support/i18n_stubs.rb  RSpec.shared_context 'i18n stubs' do   def stub_i18n_value_with_nil(key)     allow(I18n).to receive(:t).with(key).and_return(nil)     allow(I18n).to receive(:exists?).with(key).and_return(false)   end end 

Then add require support/i18n_stubs on your spec helper file. Inside wherever your spec file needs it, you can just simply put include_context 'i18n stubs' and call stub_i18n_value_with_nil('some.i18n.key') before doing assertions.

For example in spec file:

require 'spec_helper'  RSpec.describe 'some_file_or_class' do   include_context 'i18n stubs'    describe 'available_page_title' do     context 'when i18n key is not present' do       before(:each) do         stub_i18n_value_with_nil('some.i18n.key')       end        it 'returns blank string' do         # do assertion here       end     end   end end 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment