Archive for the 'cucumber' Tag

Cucumber to test mobile in a Rails project

Friday, July 6th, 2012

This post has been originally published on the Headshift Labs blog and is reposted here with permission.


Recently we had to add support for mobile devices to a Rails application we developed. We decided to go with the excellent suggestion we found in the Railscast about Mobile Devices. The gist of it is to add a method to the ApplicationController to set the mime-type to :mobile whenever the request user-agent is recognised as a mobile browser (see the corresponding ASCIIcast for the full code).

We have also used the format_fallback gem in order to avoid a proliferation of views and partials. In fact, in our application many of the partials are exactly the same in both the html and the mobile version, although they look different thanks to CSS and Javascript. What the gem does is to fallback to the html view whenever a mobile view is not found, thus avoiding the issue of having to duplicate each .html view in the application as a .mobile file. The gem is still a bit rough, but it fits our bill for this application.

Given the importance we give to BDD and TDD, however, this only gets you halfway on the road towards a proper implementation: testing for the mobile version of the application is still missing.

The most straightforward way to test the application using Cucumber is to make sure the test request headers include a user-agent string, thus mimicking a mobile device.

There are a couple of tutorials out there on how to do this (all pointing to comments for a blog post that has now disappeared without a trace). They provided a good foundation to start from, but ultimately we found out there’s an easier way to do it.

The core of this solution is a handful of lines, adding support for custom headers to Capybara’s default rack_test driver. The following code will make an add_headers method available to your steps.

# features/support/capybara_headers.rb:

module CapybaraHeadersHelper
  def add_headers(headers)
    headers.each do |name, value|
      page.driver.browser.header(name, value)

Now that the basic support is in place, we can write some steps to make our life easier.

# features/steps/mobile_steps.rb:

module MobileStepsHelper
    "iPhone" => "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7",
    "Android" => "HTC_Eris Mozilla/5.0 (Linux; U; Android 4.0; en-ca; Build/GINGERBREAD) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1"

Given /^my user agent is "(.+)"$/ do |agent|
  add_headers({'User-Agent'=> agent})

Given /^I have an? (.+)$/ do |phone_name|
  add_headers("User-Agent" => SAMPLE_AGENT_STRING[phone_name])

Notice that, for the sake of brevity, I’ve included only a couple of user agents in the SAMPLE_AGENT_STRING hash. You can find lots more around the Web.

We can then write a feature such as:

Given I have an iPhone
When I visit the homepage
I should see content tailored to my mobile