Have an old AngularJS app that would benefit from unit tests?

Here is a step by step recipe for getting started unit testing with the classic framework ‘Jasmine.’

Forget Node, we don’t have to install anything per se. All we do is hook up some JavaScript files and we are Unit testing away.

  1. Download the Jasmine stand alone project. https://github.com/jasmine/jasmine/releases

[jas-1] 2. Create a folder to place the Jasmine files.

mkdir Jasmine
  1. “Unzip” and open the SpecRunner.html file. [jas-2]
  2. Modify the spec and source files
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Jasmine Spec Runner v4.1.0</title>

  <link rel="shortcut icon" type="image/png" href="lib/jasmine-4.1.0/jasmine_favicon.png">
  <link rel="stylesheet" href="lib/jasmine-4.1.0/jasmine.css">

  <script src="lib/jasmine-4.1.0/jasmine.js"></script>
  <script src="lib/jasmine-4.1.0/jasmine-html.js"></script>
  <script src="lib/jasmine-4.1.0/boot0.js"></script>
  <!-- optional: include a file here that configures the Jasmine env -->
  <script src="lib/jasmine-4.1.0/boot1.js"></script>

  <!-- include source files here... -->
  <script src="src/Player.js"></script>
  <script src="src/Song.js"></script>

  <!-- include spec files here... -->
  <script src="spec/SpecHelper.js"></script>
  <script src="spec/PlayerSpec.js"></script>

</head>

<body>
</body>
</html>

[jas-3] In Jasmine, the it() block represents a single unit test]] The first parameter of an it() block describes what the function should do. We can think of it as our assert statement.

describe("MeaningOfLife", function () {
    it("should return the meaning of life.", function () {

    });
});

I’m told it is good form to start this block with should.

Method() What it does
it() single unit test
describe() a test suite

Ok, back to our recipe:

  1. Delete the source and spec files.
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Jasmine Spec Runner v4.1.0</title>

  <link rel="shortcut icon" type="image/png" href="lib/jasmine-4.1.0/jasmine_favicon.png">
  <link rel="stylesheet" href="lib/jasmine-4.1.0/jasmine.css">

  <script src="lib/jasmine-4.1.0/jasmine.js"></script>
  <script src="lib/jasmine-4.1.0/jasmine-html.js"></script>
  <script src="lib/jasmine-4.1.0/boot0.js"></script>
  <!-- optional: include a file here that configures the Jasmine env -->
  <script src="lib/jasmine-4.1.0/boot1.js"></script>

  <!-- include source files here... -->

  <!-- include spec files here... -->

</head>

<body>
</body>
</html>
  1. Delete all files in the spec and src folders
cd spec
rm *.*
cd ..
cd src
rm *.*

Testing a simple JavaScript app

  1. Create a new file in src
new-item .\calculator.js
cd ..
code .
  1. Make a simple function to add two numbers src/calculator.js
function add(x, y) {
	return x + y;
}
  1. Add our new program to the SpecRunner.html file.
...
<!-- include source files here... -->
<script src="src/calculator.js"></script>

[jas-4] 9. Create a file which contains our tests

cd spec
new-item /calculator.spec.js

[jas-9] 10. Link to our document in the main script file.

<!-- include spec files here... -->
<script src="spec/calculator.spec.js"></script>
  1. Inside our new, spec/calculator.spec.js - Create a describe block for the main piece of functionality
// spec/calculator.spec.js
describe("Calculator", function() {
	
});
  1. Create our unit test with it()
describe("Calculator", function () {
    it("should add two numbers together", function () {

    });
});
  1. Define the assert and actual (in xUnit speak) or expecter and matcher with expect and toBe.
decribe("Calculator", function() {
	it("should add two numbers together", function () {
		expect(true).toBe(false);
	});
});

~The above will always fail - as you are saying you expect a boolean true value to return false – which is impossible.

  1. Open SpecRunner.html in the browser
ii .\SpecRunner.html

Note the failing test: [jas-5] 13. Change toBe to `toBe(true);

// spec/calculator.spec.js
describe("Calculator", function() {
    it("should add two numbers together", function () {
        expect(true).toBe(true);
    });
});

[jas-6] [gif-1]

Testing Calculator

Always make a test fail before you make it work

  1. Create a FAILING test for our calculator function
describe("Calculator", function () {
	it("should add two numbers together", function () {
		expect(add(1,2)).toBe(4);
	});
});

[jas-7] [jas-8] 15. Change it to pass

// spec/calculator.spec.js
describe("Calculator", function() {
    it("should add two numbers together", function () {
        expect(add(2,2)).toBe(4);
    });
});
  1. Add a test for subtraction
//  spec/calculator.spec.js

describe("Calculator", function () {
    it("should add two numbers together", function () {
        expect(add(1, 2)).toBe(3);
    });
    
    it("should subtract two numbers", function () {
        expect(subtract(3, 2)).toBe(3);  // Wrong, to make sure test is running correctly
        expect(subtract(-10, -1)).toBe(-9);  // not really necessary - just meant to demonstrate multiple expectations inside one it() block
    });
});
  1. Now add a subtract method
//  src/calculator.js

...
function subtract(x, y) {
    return x - y;
}

[jas-10] 18. The first subtract fails - lets change it to where they both pass. [jas-11] 18. Create tests for multiplication and divide

//  spec/calculator.spec.js

describe("Calculator", function () {
    it("should add two numbers together", function () {
        expect(add(1, 2)).toBe(3);
    });

    it("should subtract two numbers", function () {
        expect(subtract(3, 2)).toBe(1);
        expect(subtract(-10, -1)).toBe(-9);
    });

    it("should multiply correctly", function () {
        expect(multiply(2, 3)).toBe(6);
    });

    it("should divide correctly", function () {
        expect(divide(10, 5)).toBe(2);
    });

    it("should return 0 when dividing by 0", function () {
        expect(divide(1, 0)).toBe(0);
    });
});

Note: By default, JavaScript returns Infinity when you try to divide by 0.

  1. Add our multiplication and divide methods
function multiply(x, y) {
    return x * y;
}

function divide(x, y) {
    if (y === 0) {
        return 0;
    } else {
        return x / y;
    }
}

[jas-12]

  1. Refactor the divide to use a ternary operator Note: Unit tests greatly help in re-factoring.
//  src/calculator.js

...
function divide(x, y) {
    return (y === 0) ? 0 : x / y;
}

Our tests should still pass!