mocha

Rules on Structuring the Test Directory Structure with Mocha

When writing tests, the framework I use for Node.js is Mocha (reviewed version: v2.2.x). But how should I structure the ./test directory? I first started by grouping related tests into directory, for example:

1
2
3
4
5
6
$ tree ./test
./test
├── posts
│ └── main.js
└── users
└── main.js

You can use mocha --recursive to run all test suites.

However, it’s unlikely that all files in the test directory are test suites. You might need to define some shared utilities, data generation scripts, or even setup files. You don’t want these files to be executed by Mocha. You can get away by using:

  • mocha --grep or mocha --fgrep
  • Use find and xargs to locate the files to be executed by Mocha

But these are getting more and more complex. You want something simple and dumb frankly. Therefore, a better approach is to follow the two guidelines. One is the default behavior of Mocha:

Use Custom Message in Chai

When running a test in a loop with Mocha and Chai, it might not be easy to pinpoint the element where the error occurred. For example:

1
2
3
for (let i = 0, len = arr.length; i < len; i += 1) {
expect(arr[i]).to.equal(true);
}

Run the test:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ mocha --harmony test/message.js
Custom Message
1) Should return true
0 passing (37ms)
1 failing
1) Custom Message Should return true:
AssertionError: expected false to equal true
+ expected - actual
-false
+true
at Context.<anonymous> (test/message.js:16:25)

It failed on the expect statement, but the error message does not show which element is in error.

Instead, we can add a custom message to the expect statement:

1
2
3
for (let i = 0, len = arr.length; i < len; i += 1) {
expect(arr[i], 'i = ' + i).to.equal(true);
}

Test Execution Order in Mocha

In synchronous tests, both describe and it statements are executed in the order they are laid out.

Test Foo should run before Bar:

1
2
3
4
5
6
7
describe('Suite', function () {
it('Foo', function () {
});
it('Bar', function () {
});
});

Suite Foo should run before Bar:

1
2
3
4
5
describe('Foo', function () {
});
describe('Bar', function () {
});

In asynchronous tests, the same ordering applies.

Test Foo should run before Bar even Foo takes much longer to execute, and Suite B should also run after Suite A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var should = require('should');
describe('Suite A', function () {
it('Foo', function (done) {
setTimeout(function () {
(true).should.equal(true);
done();
}, 1000);
});
it('Bar', function () {
(true).should.equal(true);
});
});
describe('Suite B', function () {
it('Foo', function () {
(true).should.equal(true);
});
});

Result:

1
2
3
4
5
6
7
8
9
Suite A
✓ Foo (1002ms)
✓ Bar
Suite B
✓ Foo
3 passing (1s)

This is the great feature in Mocha.