Automated UI Testing With Cucumber for Cordova/Phonegap Apps

Dec 14th, 2013

Both iOS and Android have UI automation frameworks for driving the UI which is great for integration/acceptance testing for your app. However, when you’re using a web/native hybrid framework like Cordova, this can get tricky.

If you come from the Ruby world, you may also be used to using Cucumber for integration testing. While the testing landscape for hybrid apps is a little rocky, a lot of smart people are working on some great tools to improve things. With some effort, you can have Cucumber-based integration spec suite up and running for your hybrid app with relative ease.

Updated 1st March 2015: fixed typos

The Main Players

Appium

Appium can launch your app and interact with it via the platform’s automation framework. It provides a Selenium remote compatible interface to your app that you can use with an driver that supports it.

Selenium WebDriver JS

We’re going to use WebDriver JS - the official Javascript driver for the Selenium project. The documentation is a little thin on examples but once you get the hang of it

The web driver talks to any Seleinum-compatible REST-style API over HTTP. For our purposes this will be Appium but you can also point it at services like Browser stack which support a compatible API.

As you can see, the webdriver is setup to send configuration details to the Appium interface. We pass in versioning information along with the path to the app we’d like to launch.

First Steps

Create features/step_definitions/app_steps.js:

12345678910111213141516171819202122232425

varappSteps=function(){this.World=require("../support/world.js").World;this.Given(/^I load the app$/,function(callback){vardriver=this.driver;driver.getAllWindowHandles().then(function(handles){driver.switchTo().window(handles[0]).then(function(){callback();});});});this.Then(/^I should see "([^"]*)"$/,function(text,callback){this.driver.getPageSource().then(function(source){if(source.match(newRegExp(text)){callback();else{callback.failure();}});});};module.exports=appSteps;

Take particular note of the ‘I load the app’ step. This code selects the UIWebView that contains your hybrid app as the main window to drive. Without this, you’ll be running against the native app.

One gotcha here is the webdriver syntax. It uses promises which can be a little strange to work with if you’re coming from other platforms. I’ll be digging deeper on this syntax in a future post.

With these steps we can build a basic cucumber feature:

12345678

Feature: App load As a user I want to load the app So that I can experience great joyScenario: Loading the app successfully Given I load the appThen I should see "Hello"

Save this as features/app_load.feature. Replace ‘Hello’ with some text that appears on the first screen of your app.

Running

Try this all out by running cucumberjs:

1

cucumber.js

You should see the simulator start up at this point, hopefully followed by some pleasing pass messages:

1234

..1 scenario (1 passed)2 steps (2 passed)

By this point I hope you’re up and running with the stack. Next time, we’ll dig a little further into the Selenium webdriver.