Unitary test

Mocha

To write test, we rely on the Mocha framework.

Note

To check your version you can use in terminal npm list mocha --depth=0.

Warning

Arrow function should not be used with Mocha (see here)

General example:

describe('Array', function() {
  describe('#indexOf()', function () {
    it('should return -1 when the value is not present', function () {
      expect([1, 2, 3].indexOf(4)).to.equal(-1);
    });
  });
});

Result:

Array
    #indexOf()
        βœ“ should return -1 when the value is not present
1 passing (9ms)

There is multiple hook that should be used :

describe('hooks', function() {
  // runs once before all tests in this block
  before(function() {});
  // runs once after all tests in this block
  after(function() {});
  // runs before each test in this block
  beforeEach(function() {});
  // runs after each test in this block
  afterEach(function() {});
  // test cases
});

Complete example:

describe('dojo._base.array', function() { // Define a test suite and describe it
  var ALPHABET;
  before(function () { // Hook: before this test suite
    ALPHABET = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
  });

  beforeEach(function () { // Hook: before each test
    assert.lengthOf(ALPHABET, 26, 'there are 26 letters in the alphabet');
  });

  it("should support indexOf", function () { // Write a test, do assertions
    assert.equal(dojo.indexOf(ALPHABET, "e") + 1, 5, "the 5th letter in the alphabet is e");
    assert.equal(dojo.indexOf(ALPHABET, "e", 5), -1);
    assert.equal(dojo.indexOf(ALPHABET, "e", 0, 4), -1);
  });

  it("should support split", function () { // Write another test, do other assertions
    assert.equal(ALPHABET.split(",").length, 26);
  });

  afterEach(function () { // Hook: after each test
  // ...
  });

  after(function () { // Hook: after this test suite
    ALPHABET = null;
  });
});

Chai

Chai is an assertion library.

Note

To check your version you can use in terminal npm list chai --depth=0.

There is 3 types of syntax for assertion :

  • expect
  • should
  • assert

Note

As a convention, we will only use expect. If you want to understand differences between each, please visit assertion styles

Then you have a quite large number of syntax to check your assertion with :

  • Linking words (.to / .have / .be / .been / .is …)
  • Negations (.not)
  • Egality: .equal (number, string) / .deep.equal (object, array)
  • Egality: .true / .null / .undefined
  • Comparison (.above / .least / .below / .most β‡’ β€˜>’ / β€˜>=’ / β€˜<’ / β€˜<=’)
  • Spy: .calledOnce / .calledOnceWithExactly / .callCount
  • Objects and array: .instanceof / .property / .lengthOf / .include
  • Errors: .throw

Some examples :

// Primitives (number, string, boolean)
expect(bool).to.be.true; // .undefined || .null
expect(nb).to.equal(1);
expect(str).to.equal("string");
// Objects & arrays
expect(obj).to.deep.equal({key: "value"});
expect(obj).to.have.property("key", "value"); // .deep.property(...
expect(arr).to.deep.equal(["value"]);
expect(arr).to.include("value");
// Spy
expect(spy).to.have.been.calledOnce;
expect(spy.getCall(0)).to.have.been.calledWithExactly(1);
// Errors
expect(() => func()).to.throw(/Fatal error.+/); // Use regex

Sinon

Sinonjs is a test framework.

Note

To check your version you can use in terminal npm list sinon --depth=0.

Integration with Dana

In before, we will use $UnitTest.getXxxx to override classes. It will create a copy of the class and initializes a safe context for your unit test.

In beforeEach, we will instanciate the tested object and set the potential β€œspies” and β€œstubs”.

In afterEach, we will restore the potential β€œspies” and β€œstubs”.

In after, we will use $UnitTest.destroyXxx to destroy the copy of the tested class.

describe('ClassToTest', function () {
  let ClassToTest, classToTest;
  before(function () {
    return $UnitTest.getClass("@ClassToTest").then(function (loadedClasses) {
      ClassToTest = loadedClasses.class;
    });
  });
  after(function () {
    return $UnitTest.destroyClass(ClassToTest);
  });
  beforeEach(function () {
    classToTest = new ClassToTest();
  });
  it("should have created an instance of 'ClassToTest'", function () {
    expect(classToTest).to.exist;
    expect(classToTest).to.be.an.instanceof(ClassToTest);
  });
});

Warning

all unit tests share the same javascript context so all global variables are persistent between tests and may have side effects

Cli

Wiztivi cli offers some commands to shorten commands to run unitary tests.

wtv test:unit:project allows you to run all unitary test files located inside tests/unit/**/*.js'.