Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Learning jQuery - Fourth Edition

You're reading from   Learning jQuery - Fourth Edition Add to your current website development skills with this brilliant guide to JQuery. This step by step course needs little prior JavaScript knowledge so is suitable for beginners and more seasoned developers alike.

Arrow left icon
Product type Paperback
Published in Jun 2013
Publisher Packt
ISBN-13 9781782163145
Length 444 pages
Edition 4th Edition
Languages
Tools
Arrow right icon
Toc

Table of Contents (24) Chapters Close

Learning jQuery Fourth Edition
Credits
Foreword
About the Authors
About the Reviewers
www.PacktPub.com
Preface
1. Getting Started FREE CHAPTER 2. Selecting Elements 3. Handling Events 4. Styling and Animating 5. Manipulating the DOM 6. Sending Data with Ajax 7. Using Plugins 8. Developing Plugins 9. Advanced Selectors and Traversing 10. Advanced Events 11. Advanced Effects 12. Advanced DOM Manipulation 13. Advanced Ajax JavaScript Closures Testing JavaScript with QUnit Quick Reference Index

Adding and running tests


In test-driven development, we write tests before writing code. This way, we can observe when a test fails, add new code, and then see that the test passes, verifying that our change has the intended effect.

Let's start by testing the child selector that we used in Chapter 2, Selecting Elements, to add a horizontal class to all <li> elements that are children of <ul id="selected-plays">:

test('Child Selector', function() {
  expect(1);
  var topLis = $('#selected-plays > li.horizontal');
  equal(topLis.length, 3, 'Top LIs have horizontal class');
});

Listing B.2

Here we've actually introduced two tests. We begin with the expect() test, which tells QUnit how many tests we expect to run in this set. Then, because we're testing our ability to select elements on the page, we use the equal() test to compare the number of top-level <li> elements against the number 3. If the two are equal, the test is successful and is added to the number of passed tests. If not, the test fails:

Of course, the test fails because we have not yet written the code to add the horizontal class. It is simple to add that code, though. We do so in the main script file for the page, which we called B.js:

$(document).ready(function() {
  $('#selected-plays > li').addClass('horizontal');
});

Listing B.3

When we run the test now, it gives the result in the following screenshot:

Now the Selecting: Child Selector test shows the numbers 0, 1, 1 in parentheses, indicating that no tests failed, one test passed, and the total number of tests is one. We can take the testing a step further now by adding a couple of attribute selector tests:

module('Selecting', {
  setup: function() {
    this.topLis = $('#selected-plays > li.horizontal');
  }
});
test('Child Selector', function() {
  expect(1);
  equal(this.topLis.length, 3, 
    'Top LIs have horizontal class');
});
test('Attribute Selectors', function() {
  expect(2);
  ok(this.topLis.find('.mailto').length == 1, 'a.mailto');
  equal(this.topLis.find('.pdflink').length, 1, 'a.pdflink');
});

Listing B.4

Here we've introduced another type of test: ok(). This one takes two arguments: an expression that should evaluate to true if successful, and a description. Also note that we've moved the local topLis variable out of the Child Selector test, where it was in Listing B.2, and into the module's setup() callback function. The module() function takes an optional second argument, which is a plain object that can include a setup() and a teardown() function. Within these functions, we can use the this keyword to assign variables once for all of a module's tests.

Again, the new tests will fail without corresponding working code:

Here we can see the difference in test failure output between the ok() test, which only shows the test's label (a.mailto) and source, and the equal() test, which also details the expected result. Because it provides more information for test failures, the equal() test is typically preferred over the ok() test.

Let's include the necessary code:

$(document).ready(function() {
  $('#selected-plays > li').addClass('horizontal');
  $('a[href^="mailto:"]').addClass('mailto');
  $('a[href$=".pdf"]').addClass('pdflink');
});

Listing B.5

The two tests now pass, as we can see by expanding the set:

Although on failure the equal() test presented more information than the ok() test, on success both tests simply display the label.

Asynchronous testing

Testing asynchronous code such as Ajax requests presents an additional challenge. The rest of the tests must pause while the asynchronous test occurs, and then they must begin again when it is complete. This type of scenario is by now very familiar; we have seen such asynchronous operations in effects queues, Ajax callback functions, and promise objects. In QUnit, we use a special test set called asyncTest(). It looks just like the regular test() set except that it will pause the running of tests until we resume them with a call to the special start() function:

asyncTest('JSON', function() {
  $.getJSON('b.json', function(json, textStatus) {
    // add tests here
  }).always(function() {
    start();
  });
});

Listing B.6

Here we're simply requesting JSON from b.json and allowing the tests to continue once the request has completed, whether it succeeds or fails, by calling start() inside the .always() callback function. For the actual tests, we're going to check the textStatus value to ensure that the request is successful and check the value of one of the objects within the response JSON array:

asyncTest('JSON', function() {
  expect(2);
  var backbite = {
    "term": "BACKBITE",
    "part": "v.t.",
    "definition": "To speak of a man as you find him when he can't find you."
  };
  $.getJSON('b.json', function(json, textStatus) {
    equal(textStatus, 'success', 'Request successful');
    deepEqual(json[1], backbite,
      'result array matches "backbite" map');
  }).always(function() {
    start();
  });
});

Listing B.7

For testing the response value, we use yet another test function: deepEqual(). Normally when two objects are compared, they are considered not equal unless they actually refer to the same location in memory. If we want to compare the object contents instead, deepEqual() meets the need. This function walks through two objects to ensure that they have the same properties and that those properties have the same values.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime