Testing Localization With Cucumber

Nowadays, it is uncommon for a website to only support one language. Large corporations aspire to offer their online products to the entire world and not limit themselves to just their country of origin. This is a logical approach, and many people appreciate finding their native language in the list of supported languages. Selecting your mother tongue provides you with a better understanding of information. However, this presents a problem - how can we automate the testing process? Some might assume that the more languages a web application supports, the more test cases should be generated. However, this is not entirely accurate. This article aims to clarify how to utilize Cucumber to validate all languages in 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">
    <p>body text</p>

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>

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

    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

    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"))

It's quite easy. When we verify the content on the page we specify the keys with adding I18n.

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|

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)

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.

Running tests

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

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!