topic: Jasmine unit tests

Tags unit-testing bdd jasmine

Jasmine is a unit testing framework we like a lot. Technically it’s a Behavior Driven Development (BDD) framework.

Getting started

Getting set up (beginner)

There are a few different ways to get started with Jasmine. Let’s go with the technically simplest one first:

Download the latest Jasmine release from here: https://github.com/jasmine/jasmine/releases. Unzip the stuff. Now replace the src with your own code and replace the specs with your own tests.

Edit index.html so that it refers to your code.

To run the tests just open index.html in your browser.

Getting set up (advanced)

Open up a terminal. Now execute each of the following commands:

mkdir my_jasmine_goodies
cd my_jasmine_goodies
npm init
npm add jasmine
npx jasmine init
npx jasmine examples

Take a moment to Google npm and npx if these concepts are new to you.

Now, in your editor of choice (vscode, subline, atom…), open up package.json. There should be something that looks like this:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },

Edit it to look like this:

"scripts": {
    "test": "jasmine"
  },

To run your tests you can now just do this:

npm test

Base your project structure on the example code that jasmine created for you.

Advanced topics

Now that you have the basics down, here are a few more advanced ways to use Jasmine.

Testing the DOM

Say you have some code that does some DOM manipulation. Some tools exist that make this pretty straightforward.

npm add jsdom

Now


var jsdom = require("jsdom");

function winning() {
  // This is the function under test. Put it somewhere that makes sense and "require" it here
  document.getElementById("booya").innerHTML = "so cool";
}

describe("FooFighters", function() {
  beforeEach(function() {
    // make a fake DOM to interact with
    const dom = new jsdom.JSDOM('<html><body id="booya">initial</body></html>');
    global.document = dom.window.document;
    global.window = dom.window;
    global.navigator = dom.window.navigator;
  });

  it("updates dom", function() {
    expect(global.document.getElementById("booya").innerHTML).toBe("initial");
    winning(); // call the function that updates the dom
    expect(global.document.getElementById("booya").innerHTML).toBe("so cool");
  });
});

Spies

Spies (often referred to as mocks in other languages and tools) are used to allow a kind of dependency injection within your tests. Here is a basic example of how it works:


class Thing {
  constructor() {
    this.a = "some initial value";
  }

  setA(newA) {
    this.a = newA;
  }
}


describe("Spies", function() {

    it("doesn't do surprising things", function() {
        var o = new.Thing();
        expect(o.a).toBe("some initial value");
    
        o.setA("x");
    
        expect(o.a).toBe("x");
      });

    it("mocks", function() {
      var o = new Thing();
      spyOn(o, "setA");    // spy on the function
      expect(o.a).toBe("some initial value");
  
      o.setA("x"); // o.setA has been replaced with a spy
      o.setA("x");
      o.setA("x");
      o.setA("x");
  
      expect(o.setA).toHaveBeenCalledTimes(4);  
      // we can check how many times it was called. 
      // we can even check what arguments were passed to this function

      // setA now has no side effect
      expect(o.a).toBe(1);
    });
  });
  

Of course, this is just the tip of the iceberg. But it gives a basic intro. Spies are detailed in the official tutorial.

Spy on the filesystem

Use this. The official docs are nice.

https://github.com/tschaub/mock-fs

Click events

Sometimes you’ll want to make sure that click events are fired as and when they should be. The following resources should help with that:

Slides

..* (A brief introduction to unit testing.)

Should the embedded slides not load, you can access the presentation here

..* (A brief introduction to Jasmine)

Should the embedded slides not load, you can access the presentation here.


RAW CONTENT URL