To run this gist install git, node and npm and then:
$ git clone https://gist.github.com/19e682776b2716283983abda78e6f8aa.git
$ cd 19e682776b2716283983abda78e6f8aa
$ npm it
To run the browser example:
$ npx http-server -o
Mocha is a JavaScript test framework that provides:
- Functions for registering tests (
describe()
,context()
,it()
andspecify()
) ("describing your tests") and for running setup and teardown before and after tests (before()
,after()
,beforeEach()
, andafterEach()
) - A command line interface for running tests with Node.js
- A JavaScript interface for running tests in the browser
- A few other bits and bobs, like writing asynchronous tests with
done()
or by returning promises or usingasync
andawait
; running only some tests withonly()
andskip()
(or with command line options)
Similar tools are Jasmine and QUnit.
Mocha does not provide:
- Functions for doing assertions. By default, when running tests on the command
line, it'll use Node.js's built-in
assert
. Or you can use an assertions library like Chai. - Spies, mocks or stubs. Use Sinon.JS.
- Coverage. Although there's a
mocha-html-cov-reporter
npm package. Or you can use another coverage tool.
It seems to be possible to use a different test runner, such as Karma, with Mocha instead of using Mocha's own command line interface and browser API. I'm not sure why you would do that.
Mocha has built in support for running your tests in a browser or on the command line. Running in a browser is easy, you just:
- Include Mocha's CSS with a
<link href="...mocha.css" rel="stylesheet">
- Put an empty
<div id="mocha"></div>
somewhere in your HTML body - Include Mocha's JavaScript with a
<script src="...mocha.js"></script>
- Include an assertions library to use with Mocha, such as Chai, with
a
<script src="...chai.js"></script>
- Call
<script>mocha.setup('bdd')</script>
- Register your tests using
describe()
,it()
,chai.assert()
, etc - Call
mocha.run()
Complete example:
<html>
<head>
<meta charset="utf-8">
<title>Mocha Browser Example</title>
<link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet" />
</head>
<body>
<div id="mocha"></div>
<script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
<script src="http://chaijs.com/chai.js"></script>
<script>
mocha.setup("bdd");
describe("my code", function() {
it("does something", function() {
chai.assert.isTrue(true);
});
});
mocha.run();
</script>
</body>
</html>
You can pass other options to mocha.setup()
, see https://mochajs.org/#browser-configuration.
You can run your Mocha tests on the command line with Node.js:
-
Install Node.js and npm
-
Have a JavaScript file or files, such as
test.js
, where you write all your tests usingdescribe()
,it()
,assert()
, etc. You need torequire("assert")
:let assert = require("assert"); describe("my code", function() { it("does something", function() { assert.equal(true, true); }); });
When we were running Mocha in the browser we had to include an assertions library such as Chai and use
chai.assert
. On the command line Mocha will use Node.js's built-inassert
by default, so you can just useassert
without having torequire()
any assertions module. You can stillrequire()
and use Chai or any other assertions library instead if you want (you'll need to add Chai topackage.json
as a dev dependency). -
Have a
package.json
file for your package in which you list Mocha as a dev dependency and givemocha
as the test command:{ "name": "19e682776b2716283983abda78e6f8aa_mocha", "version": "1.0.0", "description": "", "main": "test.js", "scripts": { "test": "mocha" }, "repository": { "type": "git", "url": "git+ssh://[email protected]/19e682776b2716283983abda78e6f8aa.git" }, "author": "Sean Hammond", "license": "ISC", "bugs": { "url": "https://gist.github.com/19e682776b2716283983abda78e6f8aa" }, "homepage": "https://gist.github.com/19e682776b2716283983abda78e6f8aa", "devDependencies": { "mocha": "^5.0.0" } }
-
Install and run:
$ npm it npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN [email protected] No description added 24 packages in 0.767s > [email protected] test /home/seanh/Gists/19e682776b2716283983abda78e6f8aa_mocha > mocha my code - pending test ✓ does something 1 passing (3ms) 1 pending
It automatically finds your tests by looking for
./test/*.js
files and executing them. It also seems to findtest.js
. And see the--recursive
option.(If you don't have any other dependencies besides mocha to put in your
package.json
then you can just skip thepackage.json
and run the tests withnpx mocha
instead ofnpm it
.)
You can also use Mocha programmatically
from your own Node.js script, instead of using the mocha
command from a shell.
If using npm test
insert an additional --
before these to pass the arguments
to mocha
rather than to npm
, example:
$ npm test -- --reporter dot
Some of the more interesting ones:
--recursive
to look for tests in subdirs as well, probably need this-w
,--watch
to automatically re-run tests when files change--bail
bail after first test failure-d
,--debug
use node's debugger (doesn't seem to work)--inspect
activate devtools in Chrome (?)-g
,--grep <pattern>
to only run tests matching<pattern>
(if running tests in the browser you can use this with a?grep=<pattern>
query string) or-f
,--fgrep <string>
to only run tests containing<string>
, and-i
,--invert
to invert the--grep
and--fgrep
matches, instead of usingonly()
andskip()
in the code
Mocha supports various different interfaces or styles of functions for registering your tests. They're all equivalent, just with different names for the same functions and different ways of calling them.
The default interface is BDD-style functions for registering tests (describe()
,
context()
, it()
, specify()
, before()
, after()
, beforeEach()
, and
afterEach()
) (context()
is an alias for describe()
, and specify()
is an
alias for it()
).
Alternatively you can use TDD-style which is just the same functions but with
different names: suite()
, test()
, suiteSetup()
, suiteTeardown()
,
setup()
, and teardown()
.
Or a QUnit style: suite()
, test()
, before()
, after()
, beforeEach()
,
and afterEach()
, and you don't nest the test()
s inside the suite()
s.o
Or a require style in which you have to require()
describe
, before
, it
etc instead of just having them available as globals.
There's also a module.exports
style:
module.exports = {
before: function() {
// ...
},
'Foo': { // Equivalent to a describe()
'#bar()': { // Equivalent to a describe()
'should return -1 when not present': function() { // Equivalent to an it()
[1,2,3].indexOf(4).should.equal(-1);
}
}
}
};
describe()
should usually be passed the name of a class, function or method,
and can be nested. #
is used before method names. Examples from the Mocha
docs:
describe('Array', function() {
describe('#indexOf()', function() {
describe('#concat()', function () {
describe('#slice()', function () {
describe('User', function() {
describe('#save()', function() {
describe('#find()', function() {
describe('add()', function() { // Just a top-level function.
There are a couple of examples in the docs that deviate from this style. For example describing an API:
describe('api', function() {
describe('GET /api/users', function() {
describe('app', function() {
describe('GET /users', function() {
And things like:
describe('hooks', function() {
describe('retries', function() {
context()
is an alias for describe()
, to be used to group certain contexts within a describe()
. Examples from docs:
describe('#indexOf()', function() {
context('when not present', function() {
context('when present', function() {
Works particularly well with different beforeEach
s inside different context()
s.
it()
is for the test functions themselves. "It should" is by far the most
common style in the docs:
it('should not throw an error', function() {
it('should return -1', function() {
it('should return the index where the element first appears in the array', function() {
Or just "it <VERB>
":
it('responds with matching records',
it('correctly adds ' + test.args.length + ' args', function() {
specify()
is just an alias for it()
. No examples are given in the docs, but
I think you would use it when it's awkward for the sentence describing your
test to begin with "It".
-
Nesting inside nested describes and contexts
-
A single block can have multiple of each, so you can split them up by what they do.
-
You can pass named functions to aid with code readability and debugging:
beforeEach(function namedFun() { // beforeEach:namedFun });
This makes the code more readable by documenting the intention of the hook function and makes the code easier to debug because if something goes wrong in the hook function its name is printed to the console.
-
Even better than a named function, you can pass a strinG:
beforeEach('some description', function() { // beforeEach:some description });
If your hook function needs to do something asynchronous it can take the
done
parameter and call it when done, just like tests can:
beforeEach(function(done) {
db.clear(function(err) {
if (err) return done(err);
db.save([tobi, loki, jane], done);
});
});
When Mocha sees that your hook function takes the done
param it'll wait for
it to call done()
before continuing.
Can you also return a Promise from a hook function? Or use async and await? Probably.
If you use =>
then this
is lexically bound, so you can't use Mocha's this
which has useful things on it like this.timeout()
.
https://mochajs.org/#arrow-functions
You can call it()
and pass a description but no function:
it('should return -1 when the value is not present');
This registers a "pending" test that hasn't been written yet. These are listed as pending (instead of passing or failing) in the console when you run the tests.
If a test does have code you can still mark it as pending by using
it.skip()
(or describe.skip()
or context.skip()
).
Don't comment out tests! Use skip()
instead.
Run just one test or suite. Multiple only()
s will run multiple tests only.
An it.only()
overrides a describe.only()
that contains the it.only()
(other it()
s in the describe.only()
won't be run).
skip()
works the same way but blacklists tests instead of whitelisting them.
The blacklisted tests are marked as pending tests.
You can call skip()
dynamically:
it('should only test in the correct environment', function() {
if (/* check test environment */) {
// make assertions
} else {
this.skip();
}
});
Note: of course, calling this.skip()
does not return from the function, any
more lines of code after the this.skip()
will still be executed (don't do
that).
this.skip()
can also be called in a before()
and will abort all tests in
the before()
s scope.
You can call describe()
, context()
and skip()
inside a loop. Allows you
to do something similar to a pytest parametrize, for example.
[
{args: [1, 2], expected: 3},
{args: [1, 2, 3], expected: 6},
{args: [1, 2, 3, 4], expected: 10}
].forEach(function(test) {
it('correctly adds ' + test.args.length + ' args', function() {
var res = add.apply(null, test.args);
assert.equal(res, test.expected);
});
});
If your it()
function takes a done
parameter then Mocha doesn't mark the
test as passed until done()
is called (and the test fails if done isn't
called before a timeout):
it('should save without error', function(done) {
var user = new User('Luna');
user.save(function(err) {
if (err) done(err);
else done();
});
});
Mocha will error if a test calls done()
more than once.
You can also just do this (not sure how this works):
it('should save without error', function(done) {
var user = new User('Luna');
user.save(done);
});
Instead of calling done()
you can just return a Promise:
it('responds with matching records', function() {
return db.find({ type: 'User' }).should.eventually.have.length(3);
});
Mocha will error if a test both calls done()
and returns a Promise.
If your environment supports it (IE doesn't) you can use JavaScript's new
async
and await
keywords:
it('responds with matching records', async function() {
const users = await db.find({ type: 'User' });
users.should.have.length(3);
});
Lots of example Mocha tests: https://mochajs.org/#examples