Using HTML fixtures

Continuing with the development of the NewInvestmentView component, we can write some basic acceptance criteria, such as the following:

  • NewInvestmentView should allow the input of the stock symbol
  • NewInvestmentView should allow the input of shares
  • NewInvestmentView should allow the input of the share price

There are many more, but this is a good start.

Create a new spec file for this component in the new file NewInvestmentViewSpec.js inside the spec folder, and we can start to translate those specs, as follows:

describe("NewInvestmentView", function() {
  it("should allow the input of the stock symbol", function() {
  });

  it("should allow the input of shares", function() {
  });

  it("should allow the input of the share price", function() {
  });
});

However, before we can start to implement these, we must first understand the concept of HTML fixtures.

Test fixtures provide the base state in which the tests run. It could be a class instantiation, the definition of an object, or a piece of HTML. In other words, to test JavaScript code that handles a form submission, we need to have the form available when running the tests. The HTML code containing the form is an HTML fixture.

One way to handle this requirement is to manually append the required DOM element inside a setup function, as follows:

beforeEach(function() {
  $('body').append('<form id="my-form"></form>'),
});

Then, remove it during teardown, as follows:

afterEach(function() {
  $('#my-form').remove();
});

Otherwise, the spec would append a lot of garbage inside the document, and it could interfere with the results of other specs.

Tip

It is important to know that specs should be independent, and that they can be run in any particular order. So, as a rule, treat specs completely in isolation from each other.

A better approach is to have a container in the document where we always put the HTML fixtures, as follows:

<div id="html-fixtures">
</div>

Change the code to the following:

beforeEach(function() {
  $('#html-fixtures').html('<form id="my-form"></form>'),
});

That way, the next time a spec runs, it automatically overwrites the previous fixture with its own.

But, this can soon escalate into an incomprehensible mess as the fixtures get more complex:

beforeEach(function() {
  $('#html-fixtures').html('<form id="new-investment"><h1>New  investment</h1><label>Symbol:<input type="text" class="new-investment-stock-symbol" name="stockSymbol"  value=""></label><input type="submit" name="add"  value="Add"></form>'),
});

Wouldn't it be great if this fixture could be loaded from an external file? That is exactly what the Jasmine jQuery extension does with its HTML fixture module.

We can place that HTML code in an external file and load it in the document with a simple call to loadFixtures, passing the fixture file path, as follows:

beforeEach(function() {
  loadFixtures('MyFixture.html'),
});

By default, the extension looks for files inside the spec/javascripts/fixtures folder (for the previous example, it would be spec/javascripts/fixtures/MyFixture.html) and loads its content inside a container, as follows:

<div id="jasmine-fixtures">
  <form id="new-investment">
    <h1>New investment</h1>
    <label>
      Symbol:
      <input type="text" class="new-investment-stock-symbol" name="stockSymbol" value="">
    </label>
    <input type="submit" name="add" value="Add">
  </form>
</div>

We can also use another of the extension's global functions to recreate the first example. The setFixtures(html) function accepts a parameter with the content to be placed in the container:

beforeEach(function() {
  setFixtures('<form id="my-form"></form>'),
});

The other available functions are as follows:

  • appendLoadFixtures(fixtureUrl[, fixtureUrl, …]): Instead of overwriting the content of the fixture container, this appends it
  • readFixtures(fixtureUrl[, fixtureUrl, …]): This reads a fixture container's content, but instead of appending it to the document, it returns a string with its contents
  • appendSetFixtures(html): This is the same as appendLoadFixtures but with an HTML string instead of a file

The Jasmine jQuery fixture module caches each file, so we can load the same fixture multiple times without penalty at the test suite's speed.

It loads the fixtures using AJAX, and sometimes, a test might want to modify the inner workings of JavaScript or jQuery AJAX, as we will see in Chapter 6, Light Speed Unit Testing, which would break the loading of a fixture. A workaround for this issue is to preload the required fixtures on the cache using the preloadFixtures() function.

The preloadFixtures(fixtureUrl[, fixtureUrl, …]) function loads one or more files in the cache without appending them to the document.

There is an issue, though, while using HTML. Jasmine jQuery loads the HTML fixtures using AJAX, but because of the same origin policy (SOP), modern browsers will block all AJAX requests when opening the SpecRunner.html with a file:// protocol.

A solution to this problem is to serve the spec runner through an HTTP server, as described in Chapter 4, Asynchronous Testing – AJAX.

For now, there is a workaround available in Chrome through the command-line interface (CLI) argument --allow-file-access-from-files.

As an example, in Mac OS X, it would require the following command in bash to open Chrome with this flag:

$ open "Google Chrome.app" --args --allow-file-access-from-files

More details on this issue can be seen at the GitHub ticket https://github.com/velesin/jasmine-jquery/issues/4.

Coming back to the NewInvestmentView component, we can start the development of the spec with the help of this HTML fixture plugin.

Create a folder named fixtures inside the spec folder. Based on the mockup interface, we can create a new HTML fixture called NewInvestmentView.html inside the fixtures folder, as follows:

<form id="new-investment">
  <h1>New investment</h1>
  <label>
    Symbol:
    <input type="text" class="new-investment-stock-symbol" name="stockSymbol" value="">
  </label>
  <label>
    Shares:
    <input type="number" class="new-investment-shares" name="shares" value="0">
  </label>
  <label>
    Share price:
    <input type="number" class="new-investment-share-price" name="sharePrice" value="0">
  </label>
  <input type="submit" name="add" value="Add">
</form>

This is an HTML fixture because it would otherwise be rendered by a server and the JavaScript code would simply attach to it and add behavior.

Because we are not saving this fixture at the plugin's default path, we need to add a new configuration at the end of the SpecHelper.js file, as follows:

jasmine.getFixtures().fixturesPath = 'spec/fixtures';

In the NewInvestmentSpec.js file, add a call to load the fixture:

describe("NewInvestmentView", function() {
  beforeEach(function() {
    loadFixtures('NewInvestmentView.html'),
  });
});

And finally, add both the spec and the source to the runner after the Stock.js and Investment.js files are added, as follows:

<script src="src/NewInvestmentView.js"></script>
<script src="spec/NewInvestmentViewSpec.js"></script>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset