Mocha (pronounced “Mocha”), launched in 2011, is one of the most popular JavaScript testing frameworks available in both browsers and Node environments.

A “test framework” is a tool for running tests. It allows you to add tests to your JavaScript application to ensure the quality of your code.

This article provides a comprehensive overview of how to use Mocha and makes it easy for you to get started. If you don’t know anything about testing before, this article can also be a good introduction to JavaScript unit testing. It is worth noting that in addition to Mocha, there are similar testing frameworks like Jasmine, Karma, Tape, etc., which are also worth studying.

A, install,

I wrote a sample library for this article, Mocha-Demos, which you need to install first.


$ git clone https://github.com/ruanyf/mocha-demos.git
Copy the code

If you don’t have Git installed on your computer, you can download the zip package and unzip it.

Then, go to the Mocha-demos directory and install the dependencies (your computer must have Node).


$ cd mocha-demos
$ npm install
Copy the code

The above code will install Mocha inside the directory. For ease of operation, install Mocha in the full environment as well.


$ npm install --global mocha
Copy the code

Two, test script writing method

Mocha’s role is to run test scripts, and you must first learn to write test scripts. A “test script” is a script that tests the source code.

Here is the code for the addition module Add.js.


// add.js
function add(x, y) {
  return x + y;
}

module.exports = add;
Copy the code

To test whether the addition module is correct, write a test script.

Typically, a test script has the same name as the source code script to be tested, but with the suffix.test.js (for tests) or.spec.js (for specifications). For example, the name of the add.js test script is add.test.js.

// add.test.js var add = require('./add.js'); var expect = require('chai').expect; Function () {expect(add(1, 1)).to.be.equal(2); }); });Copy the code

The above code is the test script, which can be executed independently. The test script should contain one or more Describe blocks, and each DESCRIBE block should contain one or more IT blocks.

The describe block is called a test suite and represents a set of related tests. It is a function that takes the name of the test suite (” test of the addition function “) as its first argument and an actual function to execute as its second argument.

The IT block, called a test case, represents a single test and is the smallest unit of testing. It is also a function whose first argument is the name of the test case (“1 plus 1 should equal 2”) and whose second argument is an actual function to execute.

The usage of the assertion library

In the test script above, there is a claim.


expect(add(1, 1)).to.be.equal(2);
Copy the code

The “assertion” is to determine whether the actual execution of the source code matches the expected result and throw an error if it does not. Call add(1, 1) and the result should be 2.

All test cases (IT blocks) should contain one or more assertions. It is the key to writing test cases. The assertion function is implemented by the assertion library. Mocha does not come with an assertion library, so it must be introduced first.


var expect = require('chai').expect;
Copy the code

There are many assertion libraries, and Mocha doesn’t limit which one to use. The assertion library introduced in the above code is CHAI and specifies the Expect assertion style to use it.

Expect assertions have the advantage of being close to natural language. Here are some examples.

// expect(4 + 5).to.be.equal(9); expect(4 + 5).to.be.not.equal(10); expect(foo).to.be.deep.equal({ bar: 'baz' }); // True expect('everthing').to.be.ok; expect(false).to.not.be.ok; // typeof expect('test').to.be.a('string'); expect({ foo: 'bar' }).to.be.an('object'); expect(foo).to.be.an.instanceof(Foo); / / include expect ([1, 2, 3]). To. Include (2); expect('foobar').to.contain('foo'); expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); // empty expect([]).to.be.empty; expect('').to.be.empty; expect({}).to.be.empty; // match expect('foobar').to.match(/^foo/);Copy the code

Basically, Expect assertions are written the same way. The header is the Expect method and the tail is the assertion method, such as equal, A/AN, OK, match, and so on. The two are connected using to or to.be.

If expect’s assertion is not true, an error is thrown. In fact, as long as no errors are thrown, the test case passes.

It ('1 + 1 should equal 2', function() {});Copy the code

The above test case, with no code in it, will pass because no errors are thrown.

The basic usage of Mocha

Once you have the test script, you can run it with Mocha. Go to the demo01 subdirectory and run the following command.

✓ $mocha add.test.js + 1 should equal 2, 1 passing (8ms);Copy the code

The above results show that the test script passed the test, with only one test case and 8 milliseconds.

The mocha command is followed by the path and file name of the test script, and you can specify multiple test scripts.


$ mocha file1 file2 file3
Copy the code

Mocha runs the test scripts in the test subdirectory by default. Therefore, the test script will be placed in the test directory, and mocha will be executed without parameters. Go to the demo02 subdirectory and run the following command.

$mocha addition function test should ✓ 1 plus 1 equals 2 ✓ any number plus 0 should be equal to its own 2 passing (ms)Copy the code

You can see that the test script in the test subdirectory has been executed. However, if you open the test subdirectory, there is also a test/dir subdirectory with a test script called multiplicate.test.js that has not been executed. Originally, by default, Mocha only executes test cases at the first level below the Test subdirectory, and does not execute use cases lower down.

To change this behavior, we must add the –recursive parameter, so that all test cases under the test subdirectory —- will be executed at any level —-.

$mocha -- recursive addition function test should ✓ 1 plus 1 equals 2 ✓ any number plus 0 should be equal to its multiplication function test ✓ 1 by 1 should be equal to 1 3 passing (ms)Copy the code

5. Wildcards

When specifying test scripts on the command line, you can use wildcards to specify multiple files at the same time.


$ mocha spec/{my,awesome}.js
$ mocha test/unit/*.js
Copy the code

The first command above specifies to execute my.js and awesome. Js under the spec directory. The second line specifies that all js files under the test/unit directory be executed.

In addition to using Shell wildcards, you can also use Node wildcards.


$ mocha 'test/**/*.@(js|jsx)'
Copy the code

The above code specifies to run the test script in any subdirectory under the test directory with the file extension js or JSX. Note that Node wildcards must be enclosed in single quotes, otherwise the asterisk (*) will be interpreted by the Shell first.

The above line of Node wildcards, if used as Shell wildcards, would be written as follows.


$ mocha test/{,**/}*.{js,jsx}
Copy the code

Command line parameters

In addition to the recursive described earlier, Mocha can add other command-line arguments. Run the following command in the demo02 subdirectory to see the result.

6.1 –help, -h

The –help or -h argument is used to view all command line arguments of Mocha.


$ mocha --help
Copy the code

6.2 – reporter, – R

The reporter argument is used to specify the format of the test report. The default format is spec.

$mocha # = $mocha -- Reporter specCopy the code

In addition to the SPEC format, there are many other report formats available on the official website.

$ mocha --reporter tap 1.. If you add a number to the test, add it to the test. If you add a number to the test, add it to the testCopy the code

This is the result of the TAP format report.

The reporters parameter displays all the built-in report formats.


$ mocha --reporters
Copy the code

Using the Mochawesome module, you can generate beautiful HTML-formatted reports.

$ npm install --save-dev mochawesome $ .. /node_modules/.bin/mocha --reporter mochawesomeCopy the code

In the code above, the mocha command uses the projection-installed version, not the globally-installed version, because the mochawesome module is installed in the project.

The test results report is then generated in the Mochaawesome – Reports subdirectory.

6.3 – growl, – G

Turn on the –growl parameter to display the test results on the desktop.


$ mocha --growl
Copy the code

6.4 – watch, – w

The watch parameter is used to monitor the specified test script. Mocha is automatically run whenever the test script changes.


$ mocha --watch
Copy the code

The above command does not exit after execution. You can open a separate terminal window and modify the test script add.test.js in the Test directory, such as deleting a test case. Once saved, Mocha will run automatically again.

B – 6.5 – bail

The bail parameter specifies that if any test case fails, subsequent test cases will be stopped. This is useful for continuous integration.


$ mocha --bail
Copy the code

6.6 — grep, – g

The –grep parameter is used to search for the name of the test case (the first parameter of the IT block) and then execute only the matching test cases.

$mocha --grep "1 + 1"Copy the code

The above code only tests test cases whose names contain “1 plus 1”.

6.7 – invert, – I

The –invert parameter indicates that only unqualified test scripts are run. This parameter must be used together with the –grep parameter.

$mocha --grep "1 + 1" --invertCopy the code

7. Configuration file mocha.opts

Mocha allows you to place the configuration file mocha.opts under the test directory to write command line arguments to it. Go to the demo03 directory and run the following command.


$ mocha --recursive --reporter tap --growl
Copy the code

This command takes three arguments –recursive, — Reporter tap, and –growl.

Then, write these three parameters to the mocha.opts file in the test directory.


--reporter tap
--recursive
--growl
Copy the code

Then, executing Mocha will have the same effect as the first line.


$ mocha
Copy the code

If the test case is not stored in the test subdirectory, you can write the following in mocha.opts.


server-tests
--recursive
Copy the code

The above code specifies to run the test scripts in the Server-tests directory and its subdirectories.

ES6 test

If the test script is written in ES6, you need to transcode with Babel before running the test. Go to the demo04 directory and open the test/add.test.js file. You can see that the test case was written in ES6.

import add from '.. /src/add.js'; import chai from 'chai'; let expect = chai.expect; Function () {expect(add(1, 1)).to.be.equal(2); }); });Copy the code

ES6 transcoding, need to install Babel.


$ npm install babel-core babel-preset-es2015 --save-dev
Copy the code

Then, under the project directory, create a new. Babelrc configuration file.


{
  "presets": [ "es2015" ]
}
Copy the code

Finally, the –compilers parameter is used to specify the transcoder for the test script.


$ ../node_modules/mocha/bin/mocha --compilers js:babel-core/register
Copy the code

In the code above, the –compilers parameter is followed by a colon-delimited string with the suffix name of the file to the left and the module name used to process the file to the right. This code says that before you run the test, you need to process the.js file using the babel-core/register module. Since the transcoder here is installed in the project, the Mocha installed in the project is used; If the transcoder is installed globally, you can use global Mocha.

Here is another example of using Mocha to test CoffeeScript scripts. Before testing, convert the.coffee file to a.js file.


$ mocha --compilers coffee:coffee-script/register
Copy the code

Note that Babel does not transcode global objects such as Iterator, Generator, Promise, Map, Set, and some global Object methods such as Object.assign by default. If you want to transcode these objects, install Babel-Polyfill.


$ npm install babel-polyfill --save
Copy the code

Then, add a line to the header of your script.


import 'babel-polyfill'
Copy the code

Asynchronous testing

By default, Mocha executes at most 2000 milliseconds per test case, and if no results are received by then, an error is reported. For test cases involving asynchronous operations, this time is often insufficient and the timeout threshold needs to be specified with either the -t or –timeout parameters.

Go to the demo05 subdirectory and open the test script timeout.test.js.

It (' test should end after 5000 milliseconds ', function(done) {var x = true; var f = function() { x = false; expect(x).to.be.not.ok; done(); // Notify Mocha that the test is over}; setTimeout(f, 4000); });Copy the code

In the above test case, it takes 4000 milliseconds for the results to run. Therefore, you need to change the default timeout setting with either -t or –timeout.


$ mocha -t 5000 timeout.test.js
Copy the code

The above command specifies a timeout for the test of 5000 milliseconds.

Also, in the test case above, there is a done function. When the IT block is executed, a done argument is passed in. When the test is finished, this function must be explicitly called to tell Mocha that the test is finished. Otherwise, Mocha has no way of knowing if the test is over and will wait until a timeout error is reported. You can try deleting this line.

Mocha highlights test cases that are longer than 75 milliseconds by default. You can adjust this parameter with -s or –slow.


$ mocha -t 5000 -s 1000 timeout.test.js
Copy the code

The command above specifies to highlight test cases that take more than 1000 milliseconds.

Here is another example of an asynchronous test async.test.js.

It (' asynchronous request should return an object ', function(done){request.get ('api.github.com')
    .end(function(err, res){
      expect(res).to.be.an('object');
      done();
    });
});
Copy the code

Run the following command and you can see that the test passes.


$ mocha -t 10000 async.test.js
Copy the code

In addition, Mocha has built-in support for promises, allowing you to return a Promise and wait for its state to change before performing an assertion, rather than explicitly calling the done method. Please see promise. Test. Js.

It (' asynchronous requests should return an object ', function() {return fetch('api.github.com')
    .then(function(res) {
      return res.json();
    }).then(function(json) {
      expect(json).to.be.an('object');
    });
});
Copy the code

Test case hooks

Mocha provides four hooks for test cases in the Describe block: before(), after(), beforeEach(), and afterEach(). They are executed at the specified time.

Describe ('hooks', function() {before(function() {// before all test cases in this block}); After (function() {// execute after all test cases in this block}); BeforeEach (function() {// execute beforeEach test case of this block}); AfterEach (function() {// executes afterEach test case in this block}); // test cases });Copy the code

Enter the demo06 subdirectory and you can see the following two examples. First is the beforeEach example beforeeach.test.js.

// beforeEach.test.js describe('beforeEach example ', function() {var foo = false; beforeEach(function() { foo = true; }); It (' modify global variable should succeed ', function() {expect(foo).to.be.equal(true); }); });Copy the code

In the above code, beforeEach is executed before IT, so global variables are modified.

Another example beforeEach-async.test.js demonstrates how to use asynchronous operations in beforeEach.

// beforeEach-async.test.js describe(' asynchronous beforeEach example ', function() {var foo = false; beforeEach(function(done) { setTimeout(function() { foo = true; done(); }, 50); }); It (' global variable async should succeed ', function() {expect(foo).to.be.equal(true); }); });Copy the code

Test case management

Large projects have many test cases. Sometimes we want to run only a few of them, and use the only method. Both the Describe block and the IT block allow the only method to be called to indicate that only one test suite or test case is being run.

In the demo07 subdirectory, the test script test/add.test.js uses only.

Function () {expect(add(1, 1)).to.be.equal(2); }); It (' any number plus 0 should equal itself ', function() {expect(add(1, 0)).to.be.equal(1); });Copy the code

In the code above, only the test case with the only method runs.

✓ $mocha test/add.test.js + 1 should equal 2, 1 passing (10ms);Copy the code

In addition, there is the skip method, which means to skip a specified test suite or test case.

Function () {expect(add(1, 0)).to.be.equal(1); });Copy the code

The test case for the above code will not be executed.

Xii. Browser testing

In addition to running on the command line, Mocha can also be run in a browser.

First, use the mocha init command to generate the initialization file in the specified directory.


$ mocha init demo08
Copy the code

Running the above command generates an index.html file in the demo08 directory, along with the accompanying script and style sheet.

<! DOCTYPE html> <html> <body> <h1>Unit.js tests in the browser with Mocha</h1> <div id="mocha"></div> <script src="mocha.js"></script> <script> mocha.setup('bdd'); </script> <script src="tests.js"></script> <script> mocha.run(); </script> </body> </html>Copy the code

Then, create a new source file, add.js.


// add.js
function add(x, y) {
  return x + y;
}
Copy the code

Then add this file, along with the assertion library chai.js, to index.html.


<script>
  mocha.setup('bdd');
</script>
<script src="add.js"></script>
<script src="http://chaijs.com/chai.js"></script>
<script src="tests.js"></script>
<script>
  mocha.run();
</script>
Copy the code

Finally, write the test script in tests.js.

var expect = chai.expect; Function () {expect(add(1, 1)).to.be.equal(2); }); Function () {expect(add(1, 0)).to.be.equal(1); expect(add(0, 0)).to.be.equal(0); }); });Copy the code

Now, open index.html in your browser and see the results of the test script.

13. Generate specification files

Mocha supports generating specification files from test cases.

Go to the demo09 subdirectory and run the following command.


$ mocha --recursive -R markdown > spec.md
Copy the code

The above command generates a spec file spec.md from all the test scripts in the test directory. The -r markDown parameter specifies that the specification report is in MarkDown format.

If you want to generate the report spec.html in HTML format, use the following command.


$ mocha --recursive -R doc > spec.html
Copy the code

(after)