dcsimg

Loading External Fixtures with the Jasmine-jQuery Library

By Rob Gravelle

WEBINAR:
On-Demand

Building the Right Environment to Support AI, Machine Learning and Deep Learning


Wojciech Zawistowski's excellent jasmine-jquery library provides a set of custom jQuery matchers for DOM elements as well as a versatile fixture loader. Rob Gravelle shows us how to use the jasmine-jquery library's set() function to provide a pre-initialized fixture.

In the Testing HTML5 Web UIs with Jasmine-jQuery article, I broached the idea that certain coding conventions, such as binding event handlers as anonymous functions, are making unit testing a lot more challenging than need be. The ideal solution would be to simply stop using anonymous functions so that their functionality may be unit tested. Unless you and your team are willing to do that, you will need a way to test anonymous functions and event handlers that won't make the whole exercise more trouble than it's worth. I would suggest using Wojciech Zawistowski, a.k.a. velesin's excellent jasmine-jquery library. It provides a set of custom jQuery matchers for DOM elements as well as a versatile fixture loader. In today's tutorial, we'll use the jasmine-jquery library's set() function to provide a pre-initialized fixture.

The Use of Fixtures in Unit Testing

In unit testing, and within the context of software testing in general, the role of a test fixture is to ensure that there is a well known and fixed environment in which tests are run so that results are repeatable. The idea is to remove all extraneous content and functionality other than that which is being tested. Some people refer to this as the test context.

To this end, the jasmine-jquery library Fixture module provides several methods for loading HTML content to be used by your tests. These methods may be invoked in one of two ways:

  1. by obtaining the Fixtures singleton through a factory and invoking one of its instance methods:
    jasmine.getFixtures().load(...)
    
  2. by calling the equivalent global short-cut function:

    loadFixtures(...)
    

Under the covers, both load() and loadFixtures() fetch one or more fixtures as individual HTML files via Ajax GET calls and appends them to the DOM (the fixtures container) as a DIV element. By default, fixtures are loaded from the spec/javascripts/fixtures directory, but you can override this path by setting the fixturesPath property:

jasmine.getFixtures().fixturesPath = 'my/new/path';

An Example Workflow

Say that we wanted to test a couple of HTML files named myfixture1.html and myfixture2.html respectively:

<div id="fixture1">some complex content here</div>
<div id="fixture2">more complex content here</div>

Inside your test, you would:

//1. Load the test fixtures.
loadFixtures('myfixture1.html', 'myfixture2.html');
//2. Call your functions that you'd like to test.
$('#fixture1').testFunc1();
$('#fixture1').testFunc2();

//3. Verify the results against expectations.
expect($('#fixture1')).to…
expect($('#fixture2')).to…

Initializing the Test Fixtures

In some cases, loading a test fixture isn't sufficient as it may require further initialization. Such is the case that we saw in the last tutorial. That file needs to be parsed to extract the "wpbody-content" DIV from the body and all scripts (other than the one whose functionality is under test) must be removed.

Within the test script, the functionality under test is defined at the top-level scope within the describe() block and initialization code takes place within the beforeAll() function. It's a special initialization function that is called only once before all the specs in describe() are run.

Here's a drill-down on the code that we were introduced to in the last tutorial that focusses on the wpbody-content DIV:

<div id="wpbody-content" aria-label="Main content" tabindex="0">	
<style>
/* styles… */
</style>
<form>
  <p><button class="button button-primary" id="btnSaveTop" type="button">Save</button></p>
  <p id="my-admin-message-top"></p>
  <h2>Carluccio's</h2>
  <h3>Sheffield Meadowhall</h3>
  <div id="1520_1">
	<label for="menu_name_1520_1">Menu Name: </label>
	<input name="menu_name_1520_1" id="menu_name_1520_1" type="text" value="Menu 1">
	<button type="button" data-location="1520_1">Delete</button><br>
	<label for="menu_url_1520_1">Source URL: </label>
	<input name="menu_url_1520_1" id="menu_url_1520_1" type="url" value="http://menuurl.com/menu.pdf">
  </div>
  <h3>Sheffield Ecclesall Road</h3>
  <div id="5411_1"></div>
  <div id="5411_2"></div>
  <div id="5411_3"></div>
  <! -- etc… -- >
  <p><button id="btnAddNewMenu" type="button">Add New Menu</button></p> 
  <div class="add-new-menu">
  <! -- new menu fields… -- >
  </div>
</form>
<script>
</script>
</div><! -- wpbody-content -- >

Inside the beforeAll() function we can either use the preload() method or fetch the page ourselves. Preload() fetches fixture(s) from one or more files and stores them into cache, without returning them or appending them to the DOM. Pre-loading all fixtures before a test suite is run may be useful when working with libraries like jasmine-ajax that block or otherwise modify the inner workings of JS or jQuery AJAX calls. However, there are times where preload() won't work, such as with cross-domain requests. Ironically, while putting together the demo for this tutorial on Codepen, attempting to pre-load the page as a Codepen resource was triggering a cross-domain error! However, invoking the jQuery $.get() method directly did return the page without issue.

Here is the call to beforeAll() from the describe function:

describe("Fixture Loading Test Suite", function() {
  beforeAll(function(done) {
    $.get(
      "https://codepen.io/blackjacques/pen/Vydeyj.html",
      function(html) {
        // Success! load the fixtures.
        var tempDom   = $('<output>').append($.parseHTML(html, null, true)),
            content   = tempDom.find('div#wpbody-content');
        
        jasmine.getFixtures().set( content.html() );
        
        done();
      }
    );
  });
});

Notice that we passed the done function parameter to beforeAll() so that we can tell jasmine when we're done loading our test fixture.

Within the Ajax success() function, a custom output tag is created in order to convert the HTML string into a proper DOM via the $.parseHTML() function. Passing in the true argument in the third position tells $.parseHTML() to remove scripts. From there, the find() method is invoked on the DOM to extract the wpbody-content DIV. We can then call jasmine.getFixtures().set(). It accepts an HTML string, so we must convert the wpbody-content DIV back into a string. This is achieved using the jQuery DOM html() method.

Here is the document produced by jasmine, including our fixture:

fixtures in dom explorer

Our fixtures are now ready for testing. You can see the code in action for yourself on this Codepen demo.

Conclusion

In today's tutorial, we used the jasmine-jquery library's set() function to provide a pre-initialized fixture. In the next instalment, we'll load a script into our fixture and expose functions within jQuery.ready() so that we can test them.



Rob Gravelle

Rob Gravelle resides in Ottawa, Canada. His design company has built web applications for numerous businesses and government agencies. Email him.

Rob's alter-ego, "Blackjacques", is an accomplished guitar player, who has released several CDs and cover songs. His band, Ivory Knight, was rated as one of Canada's top hard rock and metal groups by Brave Words magazine (issue #92).



Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.

    By submitting your information, you agree that htmlgoodies.com may send you HTMLGOODIES offers via email, phone and text message, as well as email offers about other products and services that HTMLGOODIES believes may be of interest to you. HTMLGOODIES will process your information in accordance with the Quinstreet Privacy Policy.

  •  
  •  
  •  
Thanks for your registration, follow us on our social networks to keep up-to-date