Using Jasmine for JavaScript Testing

Written by: Clemens Helm

https://fast.wistia.com/embed/medias/bsj62en2io.jsonphttps://fast.wistia.com/assets/external/E-v1.js

This is the 16th Testing Tuesday episode. Every week we will share our insights and opinions on the software testing space. Drop by every Tuesday to learn more! Last week we showed you how to set up Cucumber with standalone Ruby applications and Rails web applications.


How to test JavaScript with Jasmine

We already tested JavaScript in previous episodes with Selenium and Cucumber. Both frameworks perform integration tests by running a browser, interacting with the user interface and checking the outcome. Like the users of our web applications, these tests didn't care if certain functionality was implemented in JavaScript, in our backend application or at the database level.

This kind of testing is totally sufficient if you only implement occasional click-handlers and AJAX calls in JavaScript. But once you start writing your own components like JQuery plugins or data models, you probably want to test them at a finer-grained level. That's what Jasmine is for.

Jasmine is a unit testing framework for JavaScript. Its syntax encourages behavior-driven development and looks similar to RSpec's syntax. To get started with Jasmine we only need to download the latest version of the Jasmine Standalone.

In this screencast we'll walk you through creating a little application using behavior-driven development with Jasmine.

Up next Testing Tuesday:

Next week we'll show you how to use Jasmine spies to check if methods on JavaScript objects got called or not. If you've got any questions or suggestions, please leave us a comment!

Further info:

Transcript

Getting started with Jasmine

Intro

Ahoy and welcome! My name is Clemens Helm and you're watching Codeship Testing Tuesday number 16. Recently we talked a lot about testing Ruby applications. But today we start an entirely new series on JavaScript testing. This episode is about testing JavaScript applications with Jasmine.

Screencast

We already tested JavaScript in previous episodes with Selenium and Cucumber. Both frameworks performed integration tests by running a browser, interacting with the user interface and checking the outcome. Like the users of our web applications, these tests didn't care if certain functionality was implemented in JavaScript, in our backend application or at the database level.

This kind of testing is totally sufficient if you only implement occasional click-handlers and AJAX calls in JavaScript. But once you start writing your own components like JQuery plugins or data models, you probably want to test them at a finer-grained level. That's what Jasmine is for.

Jasmine is a unit testing framework for JavaScript. Its syntax encourages behavior-driven development and looks similar to RSpec's syntax. To get started with Jasmine we only need to download the latest version of the Jasmine Standalone (https://github.com/jasmine/jasmine) and unzip it.

I already opened the package in my text editor. The package includes a demo application, so we can already run a sample test suite by opening SpecRunner.html in the browser. Jasmine runs all specs and reports the results on a web page. Let's look into the SpecRunner HTML file to see how this works!

open SpecRunner.html

The SpecRunner loads the necessary jasmine files first: jasmise.js contains the testing framework, jasmine-html.js contains the HtmlReporter, which will run the tests when we open this web page and display the results. And jasmine.css is responsible for formatting the test results.

Then the source files are included, followed by the spec files, which contain the tests. The source files live in the src directory and the spec files in the spec directory, but it is really up to you where you put them in your application, as long as you include them in the SpecRunner HTML file.

The following script block sets up the jasmine environment, you probably want to leave this block unchanged. As we saw when we run the spec suite, there are already a number of specs defined, but let's delete the src and spec files to start a new project. I recommend you to check them out though, to get a better understanding on how to write Jasmine specs.

rm spec/* src/*

We want to develop a catalog of animals, so we start by creating an Animal.js file in the src folder. In there we add a constructor function

function Animal() {}

One important feature of many animals is that they've got a certain number of legs, depending on what kind of animal they are. Let's add a spec to specify that insects should have six legs:

describe("Animal", function() {
  it("should have 6 legs if it is an insect", function() {
    var insect = new Animal();
    insect.kind = "insect";
    expect(insect.numLegs()).toBe(6);
  });
});

The call to describe defines a test suite. Here we name the subject that we want to test in this suite. All specs in this test suite should refer to this subject. So our spec it "should have 6 legs if it is an insect" refers to an animal. The call to it is called a spec. In the function we pass to it we can write whatever code we want and some expectations. If one or more expectations fail, the spec fails. If all expectations succeed, the spec succeeds.

In our case we've only got one expectation: We expect the animal to have 6 legs after we defined "insect" as its kind.

To run our specs we need to include our JavaScript files in the SpecRunner. So we remove the obsolete script tags and add our Animal.js and AnimalSpec.js.

<!-- include source files here... -->
http://src/Animal.js
<!-- include spec files here... -->
http://spec/AnimalSpec.js

When we refresh our SpecRunner in the browser, our spec fails, because our animal doesn't have a method numLegs yet. Let's add this method:

Animal.prototype.numLegs = function () {
};

Now Jasmine complains that it expected the legs to be 6, but they were undefined. When we let our method return 6,

Animal.prototype.numLegs = function () {
  return 6;
};

the spec works.

Let's add one more spec to make our app a little smarter:

it("should have 8 legs if it is a spider", function() {
  var spider = new Animal();
  spider.kind = "spider";
  expect(spider.numLegs()).toBe(8);
});

The spec fails, because our animal has only 6 legs instead of 8. But distinguishing between insects and non-insects solves the problem:

Animal.prototype.numLegs = function () {
  if (this.kind == "insect") {
    return 6;
  } else {
    return 8;
  }
};

Jasmine also supports other expectations. For example, the number of legs of a millipede varies, so we expect it to be undefined:

it("shouldn't know the number of legs of a millipede", function() {
  var millipede = new Animal();
  millipede.kind = "millipede";
  expect(millipede.numLegs()).toBeUndefined();
});

We can implement this behavior by explicitly mentioning the spider:

Animal.prototype.numLegs = function () {
  if (this.kind == "insect") {
    return 6;
  } else if (this.kind == "spider") {
    return 8;
  }
};

Now we can do a little refactoring to make our method more concise:

Animal.prototype.numLegs = function () {
  switch (this.kind) {
    case "insect": return 6;
    case "spider": return 8;
  }
};

Our specs still work, so we can be sure that our refactory didn't break anything. Great!

Outro

Jasmine has many more nice features. Next week I'll show you how to use spies to check if methods on objects got called or not. Have a beautiful week and see you next Testing Tuesday. And of course, always stay shipping!

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.