it’s not THAT scary…
In the realm of application testing, User Interface Testing is the younger brother and the somewhat neglected member of the family who seems forever in the shadow of its bigger brother, Unit Testing.
Both provide benefits to an application's health by testing it with the expected usage and behaviour. With Unit testing different aspects of of an application that fit into the puzzle of the whole application itself, UI testing programmatically runs through the user facing aspect of a website / application and tests the behaviour as if a real person were using it.
This testing environment is possible using a headless browser and a test runner that sits on top of this - replacing the GUI negotiation with direct orders telling browser what it should do programmatically. At the moment there are two main* headless options, PhantomJS for Webkit and SlimerJS for Gecko. Yup, that JS means these tools run on Node and help avoid confusion between PhantomC#. CasperJS is the second component which brings common testing paradigms such as asserts into battle, with CasperJS being compatible with both headless solutions. This post aims at giving a light introduction on UI testing with CasperJS.*A third option in the form of TrifleJS provides a headless trident offering. This does however require, as probably expected, require a windows environment to run. At the time of writing CasperJS does not allow to be used with TrifleJS
Get up and running
Modern package managers mean that getting your setup ready from scratch is über easy (via homebrew). Fear not Windownians you are well catered for having windows installers for all three options (with CasperJS requiring an extra step).
brew update && brew install phantomjs
brew install slimerjs
A similar one line installs Casper (using npm though homebrew installation is also available)
npm install -g casperjs
With these steps down, we're ready to test, yay!
With boring installation formalities over it’s time to run some tests. CasperJS runs in the console behind the
'casperjs [options] [filename]' operative with testing requiring
'casperjs test [filename]'.
Enough talk! Time for some codez
From the top the
casper begin() method is called, with a callback invoked when Casper is ready to go (and the test object passed into it). This example then uses the
.start() call to define the first step - opening a page, checking the page is actually there (doesn't 404, 500 etc), the URL is root (login page for instance) and that the title is correct and as expected.
After this, using the
.then() call, test data is filled into the login form (navigated to using a CSS selector) where it is submitted and the resultant URL is tested.
Each 'chunk' of code handles individual aspects the that result in the full test. Casper requires that the first function call is
.start() with each subsequent part of the test using the
.then() function (extended functions such as
.thenClick() are also available).
With casper using BDD qualities a test flow can be seen - defining the test for casper to run (with it’s local namespace, test in this example being passed into the main function) and defining each step to be executed in order using the
The test then requires the
.done() to be the last call to signify to casper that all of the test have been defined - without this the test would hang and never be completed.
The code above is defined into micro steps with callbacks being the body of the test.
Tip of the iceberg
The casper API allows you to programmatically click areas of the page or assert values with known expected values and also fill in forms and submit them. In the example provided the assert function is used to check HTTP status code, title and URI are used.
This would then be run in the console via ‘casperjs test you-dont-scare-me-ghost.js‘ (assuming the filename was called you-dont-scare-me-ghost.js) - where casper will run each test outputting results to the console.
That's it! This was a simple example, but the casper Casper documentation offers many API hooks allowing for versatile testing of a application's UI.