Mats Bryntse
14 February 2013

Testing a Sencha Touch application

I recently joined Arthur Kay for an online webinar about writing tests for Sencha applications. As a follow up to […]

I recently joined Arthur Kay for an online webinar about writing tests for Sencha applications. As a follow up to the webinar, I thought we should really have a basic sample showing how to write application level tests with Siesta. Note that application tests are very different from unit tests, where you typically take one class and focus on testing its API. For an application test, we typically just point Siesta to a hostPageUrl and perform actions on the page. The sample in this blog post has been added to the Siesta examples folder. I picked one of the samples in the Sencha Touch 2.1.1 examples folder and used it as my demo app. I also added a login screen, since this is a very common use case in apps built with Sencha Touch. Overall, the demo application is very simple and features these screens:

Screen Shot 2013-02-13 at 5.46.03 PMScreen Shot 2013-02-13 at 5.47.15 PMScreen Shot 2013-02-13 at 5.47.25 PM

First, a user has to login and after logging in, an address list is shown. You can then click a contact in the list and see his or her details. To test this app, I wrote three basic application tests.

1. A sanity test to assert that upon visiting the app page, the login screen is shown
2. A basic login test, which navigates to one of the contacts in the list.
3. A basic logout test which makes sure we can log out ok.

The Harness code can be seen below:

[crayon striped=”false” lang=”javascript” nums=”false” toolbar=”false”]
var Harness = Siesta.Harness.Browser.SenchaTouch;

Harness.configure({
title : ‘Sencha Touch 2 samples’
});

Harness.start(
{
group : ‘Application tests’,
hostPageUrl : ‘DemoApp/’,
preload : [],
performSetup : false, // This is done by the app itself
items : [
‘application_tests/100_sanity.t.js’,
‘application_tests/101_login.t.js’,
‘application_tests/102_logout.t.js’
]
}
);
// eof Harness.start
[/crayon]

1. The ‘sanity’ test

A sanity test is a just a nice simple way of knowing the health of a test subject. For a typical application, that might mean to load up the start page and assure the login window can be seen. No errors should be found, and no globals leaked etc. Here’s the Siesta test code for the ‘sanity’ test.

[crayon striped=”false” lang=”javascript” nums=”false” toolbar=”false”]
StartTest(function(t) {

t.chain(
{ waitFor : ‘CQ’, args : ‘loginview’ },

function(next) {
t.pass(‘Should find login view on app start’);
t.ok(t.cq1(‘#logInButton’), ‘Should find a login button’);
}
);
});
[/crayon]

The test waits for a known Ext.ComponentQuery, the ‘loginview’ xtype. Once it’s detected, we consider that a green light and just check that the login button is also created. This is very simplistic, but still tells us that the landing page is healthy.

2. The ‘login’ test

This test starts by waiting for the login button to be visible. Since we want to tap
the button, it’s not enough just to wait for it to exist – it also has to be visible so we can ‘reach’ it (during rendering, components are often rendered off-screen). After this step, we simply set some values in the login fields. We’re not simulating typing, since there is no reason to test this – it’s a lot faster and more robust to just use the public Field API. After logging in, we wait for a CompositeQuery – a component query combined with a CSS query. Once we find a contact item in the DOM, we tap it to show the contact details.

[crayon striped=”false” lang=”javascript” nums=”false” toolbar=”false”]
StartTest(function(t) {

t.chain(
{ waitFor : ‘componentVisible’, args : ‘#logInButton’ },

function(next) {
t.cq1(‘#userNameField’).setValue(‘John Doe’);
t.cq1(‘#passwordField’).setValue(‘SecretUnhackablePW’);
next();
},

{ action : ‘tap’, target : ‘>> #logInButton’ },

// We’d like to find a headshot icon the DOM, that’s proof the main app has been launched ok
{ waitFor : ‘compositeQuery’, args : ‘contacts => .headshot’ },

function(next) {
t.pass(‘Should be able login login and see contact list’);
next();
},

{ action : ‘tap’, target : ‘contacts => .headshot’ },

{ waitFor : ‘componentVisible’, args : ‘map’ },

function(next) {
t.pass(‘Should see a detail view with map after tapping a contact’);
}
);
});
[/crayon]

3. The ‘logout’ test

This logout test just logs in, and immediately logs out again. This should take the user back to the login dialog, and this is exactly what’s being assured in the test code below.

[crayon striped=”false” lang=”javascript” nums=”false” toolbar=”false”]
StartTest(function(t) {

t.chain(
{ waitFor : ‘componentVisible’, args : ‘#logInButton’ },

function(next) {
t.cq1(‘#userNameField’).setValue(‘John Doe’);
t.cq1(‘#passwordField’).setValue(‘SecretUnhackablePW’);
next();
},

{ action : ‘tap’, target : ‘>> #logInButton’ },

// We’d like to find a headshot icon the DOM, that’s proof the main app has been launched ok
{ waitFor : ‘compositeQuery’, args : ‘contacts => .headshot’ },

function(next) {
t.willFireNTimes(App, ‘logout’, 1);
next();
},

{ action : ‘tap’, target : ‘>>#logoutButton’ },

{ waitFor : ‘componentVisible’, args : ‘loginview’ },

function(next) {
t.pass(‘Should be able to log out and see login view’);
}
);
});
[/crayon]

Refactoring

As you can see in the logout test, we’re duplicating the login process code. If we want to perform a login in many tests, it makes sense to break this behavior out to its own Test method. You do this by creating your own Test class.

[crayon striped=”false” lang=”javascript” nums=”false” toolbar=”false”]
Class(‘Your.Test.Class’, {

isa : Siesta.Test.SenchaTouch,

methods: {
login : function(user, pw, next){
var me = this;

this.chain(
{ waitFor : ‘componentVisible’, args : ‘#logInButton’ },

function(next) {
me.cq1(‘#userNameField’).setValue(user);
me.cq1(‘#passwordField’).setValue(pw);
next();
},

{ action : ‘tap’, target : ‘>> #logInButton’ },
{ waitFor : ‘compositeQuery’, args : ‘contacts => .headshot’ },

next
);
}
}
});
[/crayon]

To plug this test class into your Siesta test suite, you simply configure the testClass property of the harness.

I hope this gives you some inspiration on how to write application level tests for your Sencha Touch applications. Don’t forget to write unit tests too 🙂

Mats Bryntse

Testing