Good time management in CasperJS tests

Exclusive offer: get 50% off this eBook here
Instant Testing with CasperJS [Instant]

Instant Testing with CasperJS [Instant] — Save 50%

Create advanced and efficient CasperJS tests for your web development projects with this book and ebook

$14.99    $7.50
by Éric Bréhault | January 2014 | Open Source Web Development

In this article by Éric Bréhault, the author of Instant Testing with CasperJS, we will learn how to test our use case with CasperJS and how timing is everything.

(For more resources related to this topic, see here.)

When developing with JavaScript, we often need to chain two pieces of code (for instance, first we load some JSON data, and then we update the page content using that data).

But each step is generally non-blocking (meaning the rest of the code will continue to execute even if the step is not complete), and there is no way to predict when the first step will be complete.

The most solid and most common approach to solve this problem is the callback mechanism. We put the second piece of code in a function, and pass it as a parameter to the first one, so that it can call this function when it finishes.

As a result, there is no linear and predictably-ordered execution of the code, which makes testing a little bit tricky.

The following is an example.

Use case – simple place name matching with Geonames.org

<html> <head> <script type='text/javascript' src = 'http://code.jquery.com
/jquery-1.9.1.js'></script> <style> .searching { color: grey;} .success { color: green;} .noresults {color: red;} </style> </head> <body> <script> function geonamesSearch() { $('#results').html("Searching..."); $('#results').attr('class', 'searching'); var url = "http://ws.geonames.org/searchJSON"; var query = $('#searchedlocation').val(); $.getJSON(url + "?q="+ query +"&maxRows=25&featureClass=P", null, function(data) { var data = data.geonames; var names = []; if(data.length > 0) { $.each(data, function(i, val){ names.push(val.name +" ("+val.adminName1+")"); }); $('#results').html(names.join("<br/>")); $('#results').attr('class', 'success'); } else { $('#results').html("No matching place."); $('#results').attr('class', 'noresults'); } } ); } </script> <input type="text" id="searchedlocation" /> <button id="search" onclick="geonamesSearch();">Click me</button> <div id="results"></div> </body> </html>

This page contains a text input field, a button, and an empty div whose ID is 'results'. When we click on the button, the JavaScript function geonamesSearch does the following:

  • It puts the 'searching' class on the results div, and inserts the mention Searching...
  • It reads the current value of the text input
  • It calls the Geonames.org JSON web services to get the place names matching this value
  • This JSON call is performed by jQuery and we provides it with a callback function (that will be called when the Geonames web service will respond), which reads the results
  • If there is no result, it changes the results div class to 'noresults', and its text to No matching place.
  • If there are some results, it sets the class to 'success' and displays the matching place names.

We can try it with our web browser, and see it works nicely.

Testing our use case with CasperJS

Now let's test this page with the following CasperJS script which enters the value 'barcelona' and asserts we do get Barcelona (Catalonia) in the results:

casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)'); casper.test.begin('Search a city by name', 1, function(test) { casper.start('http://localhost:8000/example3.html', function() { this.sendKeys("input#searchedlocation", "barcelona"); this.click("button#search"); }); casper.then(function() { test.assertTextExists('Barcelona (Catalonia)',
'Barcelona (Catalonia) has been found.'); }) casper.run(function() { test.done(); }); });

Note that we need to set up a regular user agent to make sure geonames.org will accept to process our request.

If we run it, we get a failure:

Why is that? It is because our this.click() triggers the geonamesSearch function and immediately after we try to assert the result content, but the Geonames web service had no enough time to respond, the content is not yet the one expected at the time the assertion is performed.

Timing is everything

The CasperJS then() blocks allow to make sure we will execute our test steps sequence in the right order, but they cannot guarantee that an asynchronous call performed in one of the block will be complete before we move to the next block.

To manage this kind of cases, CasperJS offers the ability to wait before executing the rest of our test sequence.

Here is a working test script:

casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)'); casper.test.begin('Search a city by name', 1, function(test) { casper.start('http://localhost:8000/example3.html', function() { this.sendKeys("input#searchedlocation", "barcelona"); this.click("button#search"); }); casper.waitForSelector('div.success', function() { test.assertTextExists('Barcelona (Catalonia)',
'Barcelona (Catalonia) has been found.'); }) casper.run(function() { test.done(); }); });

We can see the tests pass successfully now:

With waitForSelector, we make sure the assertion will be performed only when the results div will have the 'success' class, and it will only happen once our JSON loading callback function has been called.

Summary

In this article, we learned how to test our use case with CasperJS and how timing is everything.

Resources for Article:


Further resources on this subject:


Instant Testing with CasperJS [Instant] Create advanced and efficient CasperJS tests for your web development projects with this book and ebook
Published: January 2014
eBook Price: $14.99
See more
Select your format and quantity:

About the Author :


Éric Bréhault

Éric Bréhault wrote his very first web pages in 1993, started JavaScript application development in 1998, and is still enjoying it.

As an IT engineer, he has used a lot of different server-side technologies, but since 2006, he has been focusing on Plone—a Python open source CMS—and been an active participant of its community. His main contribution has probably been Plomino, a Plone-based application builder. He has also worked on different, modern web mapping solutions such as Leaflet.

JavaScript has always been an important part of his work, and he started using CasperJS in 2012 as his favorite testing utility. He developed Resurrectio, a CasperJS test recorder Chrome extension.

He works as a technical manager at Makina Corpus—a French open source consulting and development company providing services for web and mobile applications—specifically on environmental issues and in the fields of spatial analysis and data visualization.

Books From Packt


 JavaScript Testing Beginner's Guide
JavaScript Testing Beginner's Guide

Moodle JavaScript Cookbook
Moodle JavaScript Cookbook

Object-Oriented JavaScript - Second Edition
Object-Oriented JavaScript - Second Edition

Jasmine JavaScript Testing
Jasmine JavaScript Testing

Getting Started with Meteor.js JavaScript Framework
Getting Started with Meteor.js JavaScript Framework

JavaScript Unit Testing
JavaScript Unit Testing

Getting Started with CreateJS
Getting Started with CreateJS

Instant Zepto.js [Instant]
Instant Zepto.js [Instant]


Your rating: None Average: 1.5 (4 votes)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
k
X
L
s
v
b
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software