Testing Localization With Cucumber
Today, it's hard to imagine a website that supports only one language. Large companies want to provide their online products for the whole world and not to limit themselves only by the country of location. It's a reasonable approach and a lot of people like if they find their native language in the list of supported languages. You select your native language with great pleasure and you take information easily. And this is where a problem comes up - how to test this (I mean automatic testing)? On the one hand it can be assumed that the more languages are supported by a web application the more testing cases should be created. But it's completely wrong. In this article I try to explain how to make Cucumber verify all languages in the Ruby on Rails applications.
Handling internationalization in the Rails apps
Gem Rails Internationalization provides multi-language support in the Rails applications (the manual for gem is here).
Before digging into specifics of testing language localization with Сucumber, let's see how internationalization gem for Rails works: we will look through some views without localizations.
<%= content_for :page_title, "Page title" %> <div class="editorial"> <h1>Header</h1> <p>body text</p> </div>
As you can see, in the first line we have a title of the page, followed by a header and a text block. When we add localization to the view it looks like this:
<%= content_for :page_title, t("home.title") %> <div class="editorial"> <h1><%= t("home.header") %></h1> <p><%= t("home.body") %></p> </div>
What were changed? All text values were changed to the keys like
t("home.title"). These keys lead to folder ~/config/locales/ where files *.yml with all existing translations are located. For example, if there are two localizations (English and French) two locale files will be placed in the folder en.yml and fr.yml.
The structure of *.yml files looks like this:
For English localization en.yml
en: home: title: "This is a title for my web page" header: "This is a header for my web page" body: "This is a body for my web page"
For French localization fr.yml
fr: home: title: "Cest un titre pour ma page web" header: "Cest un en-tete de ma page web" body: "Il sagit dun corps de ma page web"
Folder ~/config/locales/ can contain a lot of folders or files. It's more functional when all pages are placed in separate folders.
Automated tests for a page with localization
Now, lets turn to the main aspects of website language localization testing with Cucumber and discuss how to write the auto test for verifying page with localization. For example, we have the next scenario:
Scenario: User should be able to visit a guest page When I visit guest page And I should be stay on the guest page
Steps definitions look like this:
And(/^I should be stay on the guest page$/) do page.should have_content(I18n.t("guest.title")) page.should have_content(I18n.t("guest.body")) end
It's quite easy. When we verify the content on the page we specify the keys with adding
Introducing variables into tests
There are cases when we should pass a variable. For example we should press the "Send" button which is placed on the page with the sending form. There are several ways to solve this issue. Let's look at the first example:
Scenario: User should be able to send application form Given I visit form page Then I write in form And I press "application_form.button.send"
Steps Definition look like this:
And(/^I press "([^\"]*)"$/) do |key| click_button(I18n.t(key)) end
In this case we simply pass the key as a variable and insert it into the line
I18n.t(…). Everything is fine, test works and checks cases for all locales but the problem is that the ease of reading the text is neglected. After reading this test the Customer can't understand what we're doing in this scenario - and this is a big disadvantage of such test. Cucumber was created to make test scenarios easily understandable even for those people who are not familiar with functionality, software and IT industry at all.
Solving the readability problem
There is the solution for this case! Let's look through the second example:
Scenario: User should be able to send application form Given I visit form page Then I write in form And I press "Send"
Steps definition look like this:
And(/^I press "([^\"]*)"$/) do |button| case button when ‘Send’ button = I18n.t('application_form.send’) when ‘XXX’ button = I18n.t('application_form.xxx’) end click_button(I18n.t(button)) end
Thus we have the easily readable test and the operative scenario for all locales. However, there is a disadvantage. We added a
case block for going through all buttons which we need to press. But we have to sacrifice something. You may choose which example is the best in your case.
The next step is running tests. If you load all cucumber features/scenarios tests in a usual way, the tests will be passed for a locale which is set by default. To switch a language for testing we should add the following line in
Before block of the env.rb file.
Before do I18n.locale = :en end
This way, before running the tests, Cucumber goes to the env.rb file for reading settings, sees
Before block and sets a locale from this block.
It may seem easy and simple! But in such case we will have to change variable every time when we need to set up the required language. To do this, we should find a file, find a required line and change it again and again. This variant doesn't fit us as we need to automatize everything :). In order to avoid these tedious manual changes when you start the tests, you need to replace the line:
I18n.locale = :en by
I18n.locale = ENV[‘LOCALE’].
We added the global variable where the locale from command line will be passed before starting tests. Now for running tests with the required language we should run the following command: cucumber features/scenarios LOCALE=en
If you forget to set the variable and simply run cucumber features/scenarios, tests will pass under the default locale.
Now, when we have sorted out what is the use of Cucumber for Ruby applications with multiple language options, hopefully everything looks simple, easy and flexible… Enjoy testing with this wonderful open source tool!