Skip to main content

Using Jasmine with JavaScript

4 min read

Older Article

This article was published 9 years ago. Some information may be outdated or no longer applicable.

Testing matters. In this article we’ll wire up unit tests for JavaScript (ES6 / ES2015) code using Jasmine.

Unit Testing

Units are the smallest pieces of functionality we can test against in our code. We’ll test individual pieces in isolation.

Jasmine

Jasmine is a behaviour-driven development framework for testing JavaScript. It ships with a clean syntax that reads almost like natural language.

We’re going to use it with Node.js.

Installation

Grab Jasmine from npm: npm i jasmine (or install it globally with the -g flag).

Configuration

Jasmine reads its configuration from a file called jasmine.json. You can create it by hand or run jasmine’s init command: jasmine init.

If Jasmine isn’t installed globally, call init from the local install: node_modules/jasmine/bin/jasmine init.

The init command creates this structure:

|-spec
  |---support
    |---jasmine.json

With jasmine.json containing these defaults:

{
  "spec_dir": "spec",
  "spec_files": ["**/*[sS]pec.js"],
  "helpers": ["helpers/**/*.js"],
  "stopSpecOnExpectationFailure": false,
  "random": false
}

Jasmine expects all specs (tests) to live in a spec folder. Filenames can be anything, as long as they end with spec (upper or lower case s) and have a .js extension.

Suites, Specs and Expectations

Some quick terminology. A suite is created by calling describe, which takes a string (what the test covers) and a function (where specs live).

Specs are the actual tests. You create them with it, which also takes a string and a function.

Inside that function, you write expectations. Each expectation returns true or false based on an actual value and an expected value.

Test Driven Development

TDD is a methodology where developers write tests first, before any application code. They run the tests, watch them fail, then write code to make them pass. We’re not following that approach here. We’ll write code first, then build the tests.

Example

Let’s start with a simple ES2015 class:

class Warrior {
  constructor(name, health, weapon) {
    this.name = name;
    this.health = health;
    this.weapon = weapon;
  }

  getWeapon() {
    return this.weapon;
  }

  takeDamage(damage) {
    return this.health - damage;
  }
}

export default Warrior;

Now the test file. Drop this in the spec folder with a name containing “spec” (I’m calling mine warrior-spec.js):

import Warrior from './../warrior';

describe('Warrior Unit Test', () => {
  let warrior;
  beforeEach(() => {
    warrior = new Warrior('Dave, the Nomad', 100, 'sword');
  });

  it('should return warrior weapon', () => {
    expect(warrior.getWeapon()).toBe('sword');
  });
  it('should decrease warrior health by 10', () => {
    expect(warrior.takeDamage(10)).toBe(90);
  });
});

One test suite, two specs. We expect the warrior’s weapon to be ‘sword’, and we expect 10 damage to leave 90 health out of 100.

Notice how the code reads like plain English.

A couple of things to flag:

  1. beforeEach() runs before every spec. Here it instantiates the Warrior class so we don’t have to repeat that setup in each spec. You can also declare and assign variables inside it.
  2. We’re using the import keyword, which (at the time of writing) isn’t supported natively in Node.js. So we’ll need Babel to transpile.

Babel to transpile

To run code that Jasmine can understand, we’ll transpile with Babel, specifically babel-node.

Install babel and the ES2015 preset: npm i babel-core babel-preset-es2015 --save.

Then create a .babelrc file telling Babel to use the ES2015 preset:

{
  "presets": ["es2015"]
}

A preset in Babel is a collection of plugins for a particular language target. Ours is ES2015.

Add a run.js file to kick off Jasmine:

import Jasmine from 'jasmine';

const jasmine = new Jasmine();
jasmine.loadConfigFile('spec/support/jasmine.json');
jasmine.execute();

Run the tests with: babel-node spec/run.js.

You should see:

Started
..


2 specs, 0 failures

All tests passed.

Babel is only needed here because we’re using ES2015 syntax. Without it, Jasmine runs perfectly well on its own.