Glad Chinda Full-stack web developer learning new hacks one day at a time. Web technology enthusiast. Hacking stuffs @theflutterwave.

A quick and complete guide to Mocha testing

18 min read 5149

Learn how to write and run tests for your JavaScript programs using Mocha

Building software that is predictable, less error-prone and resilient to changes is something every software developer should learn to do. Test-driven development (TDD) is one of the major ways this can be achieved. Test-driven development, in a nutshell, usually requires:

  1. Writing tests for the required software functionality

  2. Run the tests for the software functionality

  3. Implement the software functionality

  4. Fix bugs and refactor until all tests pass

  5. Repeat the cycle for new functionality

Just as with other programming languages, JavaScript has several tools and frameworks that make test-driven development possible on Node.js and also in the browser, such as: Jest, Jasmine, Mocha, QUnit, Karma, Cypress, and several others.

In this article, you will be taken through a quick but extensive guide on how Mocha can be used for testing software functionality written in JavaScript. You will learn how to write your own test suites and how to run the tests with Mocha.

Getting started with Mocha

Mocha is a JavaScript test runner that runs both on Node.js and in the browser. It provides functionality for testing both synchronous and asynchronous code with a very simple and similar interface.

Before you continue, you need to have Mocha installed either globally on your local machine or as a dependency for your project. Here is how it can be installed using the Node Package Manager(NPM).

Global Installation

npm i --global mocha

As a development dependency for your project

npm i --save-dev mocha

Installing Mocha globally on your local machine makes the mocha CLI binary available for use in your command-line terminal. Hence you can run tests with Mocha on your terminal as follows:

We made a custom demo for .
No really. Click here to check it out.

mocha

However, if you only installed Mocha as a development dependency for your project, then you can access the mocha binary from the node_modules directory of your project as follows:

./node_modules/mocha/bin/mocha

To complete your Mocha setup, you will have to write a unit test for a very simple functionality and configure a script to run the test using Mocha.

Mocha automatically looks for tests inside the test directory of your project. Hence, you should go ahead and create this directory in your project root.

mkdir test

Next, modify the “test” script in your package.json to run tests using Mocha. Here is what it should look like:

/* package.json */

{
  "scripts": {
    "test": "mocha"
  }
}

With this setup, you can simply run the tests in your project using this simple command:

npm test

Writing tests

At the moment, you have everything set up for running your tests with Mocha but you don’t have any tests to run yet. The next step will be to start writing tests for the desired functionalities of your software.

Assertion library

Writing tests often requires using an assertion library. Mocha does not discriminate whatever assertion library you choose to use. If you are using Mocha in a Node.js environment, you can use the built-in assert module as your assertion library. However, there are more extensive assertion libraries you can make use of such as Chai, Expect.js, Should.js.

For all the tests in this guide, Chai will be used as the assertion library of choice. Go ahead and install Chai as a dependency for your project as follows:

npm i --save-dev chai

Chai provides the following assertion styles:

  1. Assert style
var assert = require('chai').assert;
var numbers = [1, 2, 3, 4, 5];

assert.isArray(numbers, 'is array of numbers');
assert.include(numbers, 2, 'array contains 2');
assert.lengthOf(numbers, 5, 'array contains 5 numbers');

2. Expect style

var expect = require('chai').expect;
var numbers = [1, 2, 3, 4, 5];

expect(numbers).to.be.an('array').that.includes(2);
expect(numbers).to.have.lengthOf(5);

3. Should style

var should = require('chai').should();
var numbers = [1, 2, 3, 4, 5];

numbers.should.be.an('array').that.includes(2);
numbers.should.have.lengthOf(5);

You can learn more about the assertions and assertion styles Chai provides from this documentation.

Mocha interfaces

Mocha provides a variety of interfaces for defining test suites, hooks and individual tests, namely: BDD, TDD, Exports, QUnit and Require.

For this guide, the BDD style-interface will be used for defining and writing the tests. However, you can check the comparison between the available Mocha style-interfaces in this documentation.

Here is what a test suite defined using the BDD interface looks like:

// begin a test suite of one or more tests
describe('#sum()', function() {

  // add a test hook
  beforeEach(function() {
    // ...some logic before each test is run
  })
  
  // test a functionality
  it('should add numbers', function() {
    // add an assertion
    expect(sum(1, 2, 3, 4, 5)).to.equal(15);
  })
  
  // ...some more tests
  
})

Writing your first test suite

It’s time for you to write your first test suite and run the tests with Mocha. Here is the software requirement to be implemented.

A sum() function that has the following behavior:

  1. Can accept any number of arguments

  2. Requires all arguments to be numbers and throws an error if any is not a number

  3. Computes and returns the sum of its arguments provided all are numbers

  4. Returns 0 if no argument is passed

Fitting with best practice, first define the test suite with tests for the required functionalities.

Create a new sum.js file in the test directory of your project and add the following code snippet to it:

/* test/sum.js */

var sum = require('../sum');
var expect = require('chai').expect;

describe('#sum()', function() {

  context('without arguments', function() {
    it('should return 0', function() {
      expect(sum()).to.equal(0)
    })
  })
  
  context('with number arguments', function() {
    it('should return sum of arguments', function() {
      expect(sum(1, 2, 3, 4, 5)).to.equal(15)
    })
    
    it('should return argument when only one argument is passed', function() {
      expect(sum(5)).to.equal(5)
    })
  })
  
  context('with non-number arguments', function() {
    it('should throw error', function() {
      expect(function() {
        sum(1, 2, '3', [4], 5)
      }).to.throw(TypeError, 'sum() expects only numbers.')
    })
  })
  
})

Notice that the sum module was required in the test file though it has not been created yet. Also notice that the sum() call is wrapped in a function to test that an error is thrown when non-number arguments are passed. This is a requirement of the .throw() assertion as specified in the Chai assertions documentation.

Next, go ahead and implement the functionality for the sum() function as a module export, run the tests and ensure that all the tests pass.

Create a new sum.js file in the root directory of your project containing the following code snippet:

/* sum.js */

module.exports = function() {

  // Convert arguments object to an array
  var args = Array.prototype.slice.call(arguments);
  
  // Throw error if arguments contain non-finite number values
  if (!args.every(Number.isFinite)) {
    throw new TypeError('sum() expects only numbers.')
  }
  
  // Return the sum of the arguments
  return args.reduce(function(a, b) {
    return a + b
  }, 0);
  
}

You can run the tests now on your terminal by running the “test” script defined earlier:

npm test

You should get an output that looks like the following:

Running the first test

Testing asynchronous code

The tests you have written so far are for functionalities involving code that is executed synchronously. However, most Node.js applications require a lot of asynchronous code. Mocha also makes it easy to test asynchronous code with a very similar syntax. Any of the following methods can be used for testing asynchronous code with Mocha:

  1. Using a callback function

  2. Using promises (for environments that support for promises)

  3. Using async / await (for environments that support async functions)

1. Using a callback function

The function passed as second argument to it() can be passed an optional callback function as its first argument. When this callback function is passed, Mocha knows that the test is for asynchronous functionality. Conventionally, the callback function is named done, but you are at liberty to use any identifier you choose.

it('test expectation', function(done) {
// test asynchronous code
// call done() to terminate test and proceed to the next test
}

There are a few things to note about the done callback:

  1. The done() callback must be called for Mocha to terminate the test and proceed to the next test, otherwise the test keeps running until the timeout reaches.

  2. The done() callback should not be called more than once within an it() function block. Calling it multiple times will throw an error.

  3. The done() callback is a Node-style callback, hence it can take an Error instance (err) as its first argument.

  4. Calling the done() callback with an Error instance causes the test to fail with the given error.

Before you proceed, here is a simple module that exports an asynchronous md5() function for computing the MD5 hash of a string.

Create a new md5.js file in the root directory of your project and add the following content to it:

/* md5.js */

var crypto = require('crypto');

module.exports = function(string, callback) {
  var withCallback = typeof callback === 'function';
  
  try {
  
    var hash = crypto.createHash('md5')
      .update(string)
      .digest('hex');
      
    withCallback && callback(null, hash);
    
  } catch (e) {
    if (withCallback) callback(e);
    else throw e;
  }
}

The following code snippet contains a simple test for this asynchronous function using a callback function.

Create a new md5.js file in the test directory of your project and add the following content to it:

/* test/md5.js */

var md5 = require('../md5');
var expect = require('chai').expect;

describe('#md5()', function() {

  context('with string argument', function() {
    it('should compute MD5 hash', function(done) {
    
      md5('Glad Chinda', function(err, hash) {
        // call the done() callback with the error if any
        // to terminate the test with an error
        if (err) return done(err);
        
        // add some assertions
        expect(hash)
          .to.be.a('string')
          .that.matches(/^[a-f0-9]{32}$/)
          .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');
          
        // finally call the done() callback
        // to terminate the test
        done();
      })
      
    })
  })
  
  context('with non-string argument', function() {
    it('should throw an error', function(done) {
    
      md5(12345, function(err, hash) {
        // call the done() callback with the error if any
        // to terminate the test
        if (err) {
        
          // add an assertion to check the error
          expect(function() { throw err })
            .to.throw(TypeError, 'Data must be a string or a buffer');
            
          // finally call the done() callback
          // to terminate the test and return
          return done();
          
        }
        
        // call the done() callback
        // to terminate the test
        done();
      })
      
    })
  })
  
})

If you run the tests now on your terminal, you will get an output that looks like the following:

Testing async code using callback function

2. Using promises

If you are developing in an environment with support for promises, it’s likely that most of the asynchronous operations will be based on promises. Mocha also makes it possible for you to test asynchronous code that uses promises.

Whenever you return a promise from the function passed to it(), Mocha knows that the functionality to be tested is asynchronous, and so it waits for the promise to be fulfilled before proceeding to the next test.

From Mocha v3.0.0 and newer, calling the done() callback when a promise is returned will result in an exception, since this is not allowed. However, in older versions of Mocha, the call is ignored.

In order to test asynchronous code that uses promises, you will create another version of the md5 module that is based on promises.

Create a new promise-md5.js file in the root directory of your project with the following content:

/* promise-md5.js */

const md5 = require('./md5');

module.exports = (string) => new Promise(
  (resolve, reject) => {
    md5(string, (err, hash) => {
      return err ? reject(err) : resolve(hash)
    })
  }
)

The following code snippet contains a simple test suite for the promise-md5 module. Create a new promise-md5.js file in the test directory of your project and add the following content to it:

/* test/promise-md5.js */

var promiseMd5 = require('../promise-md5');
var expect = require('chai').expect;

describe('#promiseMd5()', function() {

  context('with string argument', function() {
    it('should compute MD5 hash', function() {
    
      return promiseMd5('Glad Chinda')
        .then(function(hash) {
          // add some assertions
          expect(hash)
            .to.be.a('string')
            .that.matches(/^[a-f0-9]{32}$/)
            .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');
        })
        
    })
  })
  
  context('with non-string argument', function() {
    it('should throw an error', function() {
    
      return promiseMd5(12345)
        .catch(function(err) {
          // add an assertion to check the error
          expect(function() { throw err })
            .to.throw(TypeError, 'Data must be a string or a buffer');
        })
        
    })
  })
  
})

Now go ahead and run the test with this slightly modified test command:

npm test -- -f promiseMd5

This command uses -— to pipe the command options and arguments to the underlying mocha CLI binary. The -f flag instructs Mocha to run only tests that contain the given string, which in this case is promiseMd5.

Here is what the output should look like:

Testing async code using promises

3. Using async / await

For environments that support the more recent async / await syntax, Mocha also supports passing async functions as second argument to it(). Hence, the previous promise-md5.js tests can be rewritten as follows:

/* test/promise-md5.js */

var promiseMd5 = require('../promise-md5');
var expect = require('chai').expect;

describe('#promiseMd5()', function() {

  context('with string argument', function() {
    it('should compute MD5 hash', async function() {
    
      // use await to wait until the promise is fulfilled
      var hash = await promiseMd5('Glad Chinda');
      
      // add some assertions
      expect(hash)
        .to.be.a('string')
        .that.matches(/^[a-f0-9]{32}$/)
        .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');
    })
    
  })
  
  context('with non-string argument', function() {
    it('should throw an error', async function() {
    
      await promiseMd5(12345).catch(function(err) {
        // add an assertion to check the error
        expect(function() { throw err })
          .to.throw(TypeError, 'Data must be a string or a buffer');
       })
       
    })
  })
  
})

Utilizing test hooks

Mocha makes provision for creating test hooks. Hooks are basically logic that have been configured to run before or after tests. They are useful for setting up preconditions for tests or cleaning up resources after tests. With the default BDD interface, Mocha provides four hooks:

  1. before() — Runs once before the first test case in the block

  2. beforeEach() — Runs before each test case

  3. afterEach() — Runs after each test case

  4. after() — Runs once after the last test case in the block

Depending on the hooks that apply to a given test suite, the hooks are run together with the tests in the suite in a definite sequence as illustrated below:

before() -> beforeEach() -> test() -> afterEach() -> after()

Creating hooks

Each hook basically takes a callback function as argument. The callback function contains logic to be executed when the hook is triggered. The logic can be either synchronous or asynchronous just as it is with regular test cases.

describe('some module', function() {

  beforeEach(function() {
    // some logic to run before each test
    // logic can be sync or async
  })
  
})

Hooks can also take an optional description as first argument which makes it easier to track errors. However, if a named function is passed as argument to a hook, the name of the function is used as description if no explicit description was passed.

describe('some module', function() {

  // HOOK WITH NAMED FUNCTION
  beforeEach(function createSession() {
    // beforeEach:createSession
  })
  
  // HOOK WITH DESCRIPTION
  beforeEach('create a user session', function() {
    // beforeEach:create a user session
  })
  
})

The root suite

Whenever a hook is defined outside a definite describe() block, the hook becomes a root-level hook. Root-level hooks apply to all test files regardless of where they are defined. This is because Mocha implicitly creates a describe() block, called the root suite.

Hence in the following code snippet, the afterEach() hook will be triggered after every test in every file.

var tests = 1;

// Will run after every test in every file
afterEach(function() {
  console.log('Test #' + (tests++));
})

Sometimes, you may want to perform an asynchronous operation before running any of your test suites. Mocha allows you to delay the root suite by running the mocha binary with the --delay option. For your project’s test command, it will look like this:

npm test -- --delay

Running this command instructs Mocha to attach a special run() callback function to the global context. Calling the run() function will instruct Mocha to run all the test suites that have been described. Hence, run() can be called after the asynchronous operation is completed in order to run the tests.

For example, add the following code snippet to any of the test files you created earlier (it must never be inside an it() block):

// Delay running the tests until after 5s
setTimeout(function() {
  run()
}, 5000);

Now run the tests with the following command:

npm test -- --delay

Notice that the tests are delayed for 5 seconds and then they run. However, if the run() method is never called, the tests will never run. Here is what the output should look like:

Running delayed tests

Testing Isn’t Enough – Ensure Your App Functions as Expected

LogRocket is a front-end logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. https://logrocket.com/signup/

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.

Controlling tests

Whenever a callback function is not passed as second argument to it(), the test case is marked as pending, which indicates that the test is yet to be written. Pending tests are not failed tests and they are included in the test results.

describe('#flattenArray()', function() {
  // a pending test
  it('should flatten array');
})
Pending test

Including and excluding tests

You can also specify test suites and test cases that should or should not be run. Mocha provides two helpful methods: only() and skip(), for controlling exclusive and inclusive behavior of test suites and test cases.

Use the describe.skip() method to prevent the tests in a suite from running and the describe.only() method to ensure that the tests in a suite run.

// Tests in this suite will run
describe.only('#flattenArray()', function() {
  it('should flatten array', function() {});
})

// Tests in this suite will not run
describe('#mergeArray()', function() {
  it('should merge two arrays', function() {});
})

The same also applies to test cases using it(). It is possible to skip a test at runtime by calling this.skip() inside the callback function passed to it(). This makes it possible to dynamically skip a test based on some condition.
Calling this.skip() effectively aborts the test. Hence, it is considered best practice to avoid executing further instructions after a call to this.skip(). Every test that is skipped at runtime using this.skip() will be marked as a pending test.

describe.only('#flattenArray()', function() {
  // This test will run
  it.only('should flatten array', function() {});
  
  // This test will not run
  it('should recursively flatten array', function() {});
})

describe.only('#mergeArray()', function() {

  // This test is skipped at runtime for production environment
  // In production, it will not run and will be marked as pending
  
  it('should merge two arrays', function() {
    if (process.env.NODE_ENV === 'production') {
      return this.skip();
    }
  });
  
})
Skipping test at runtime

You can use .only() and .skip() multiple times to select a set of suites and tests to run. However, you must note the following:

  1. Nested suites will still be executed

  2. Hooks will still be executed if present

  3. Tests will have precedence

Retrying tests

Mocha provides a functionality for specifying the number of times a failed test can be retried. This is not recommended for unit tests, but it can be useful when writing end-to-end tests (where some external resources may not be available for some reason).

Mocha provides a this.retries() function that allows you specify the number of times a failed test can be retried. For each retry, Mocha re-runs the beforeEach() and afterEach() hooks but not the before() and after() hooks.

The following code snippet shows a simple example that uses the Cypress test runner to visit a webpage. If the server responds with a status code other than 2xx, possibly because of slow network or bad internet connection, the test is marked as failed.

describe('test medium site', function() {

  // all failed tests in this suite will only be retried 2 times
  this.retries(2);
  
  it('should load medium homepage', function() {
    // can only retry this test 5 times
    this.retries(5);
    
    cy.visit('https://medium.com');
  })
  
})

With this.retries(5), the test is allowed to be retried a maximum of 5 times before it can be marked as failed.

Slow tests

Mocha allows you to define the amount of time that should elapse before tests are considered as being slow. The this.slow() method is available for this purpose. The number passed to this.slow() represents the amount of time in milliseconds.

describe('slow test', function() {

  // Tests will be considered slow after 1 second elapses
  this.slow(1000);
  
  // Completes after the specified 1 second elapses
  it('should be complete in a second', function(done) {
    setTimeout(done, 1500);
  })
  
  // Completes immediately
  it('should be complete instantly', function() {})
  
})
Managing slow tests

Notice the red (1506ms) indicator used to mark the slow test. The test is considered slow because it took more than the specified 1 second (1000ms) to run completely.

Timeouts

By default, Mocha will timeout for any test that takes more than 2 seconds (2000ms) to run completely. When a timeout happens, the test is marked as failed and a timeout error is thrown.

Test timeout

However, Mocha provides a this.timeout() method for specifying the amount of time that should elapse before a timeout happens for a given test suite, hook or test case. The number passed to this.timeout() represents the amount of time in milliseconds.

The timeout can be configured differently at different levels (suite, hook and test levels):

describe('some time-consuming operation', function() {

  // set a 5 seconds timeout for this suite
  this.timeout(5000);
  
  before('some long setup', function(done) {
    // set a hook-level timeout
    this.timeout(2500);
    
    setTimeout(done, 2250);
  })
  
  it('should take less than 200ms', function(done) {
    // set a test-level timeout
    this.timeout(200);
    
    setTimeout(done, 150);
  })
  
})

Note that, calling this.timeout() with 0 disables timeout completely.

describe('some time-consuming operation', function() {

  // disable timeout for this suite
  this.timeout(0);
  
  // test that takes a long time to complete
  it('should take a long time', function(done) {
    setTimeout(done, 10000);
  })
  
})

Mocha CLI options

So far, you have been exposed to all the tooling that Mocha makes available for writing tests. However, there are still lots of utilities you can leverage on when using Mocha, and a couple of these utilities are only available to you when using the mocha CLI binary.

To get the list of available options you can apply to mocha, run the following command:

mocha -h

From your project you can use this command instead:

npm test -- -h

Watching test files

The -w, --watch flag instructs Mocha to watch for changes in test files and re-run the tests. This is very useful for writing tests while in development.

mocha --watch

Async and bail

The -A, --async-only flag forces all tests to require a callback function or return a promise, thereby behaving asynchronously. Tests that don’t specify a callback function or return a promise will be marked as failed.

mocha --async-only

The -b, --bail flag forces Mocha to bail after the first test failure.

mocha --bail

Handling timeouts and slow tests

The -t, --timeout <ms> option allows you to set the timeout for your test cases. Mocha uses a default of 2 seconds. You can set the timeout by specifying the number of milliseconds or a value with an s suffix to specify the time in seconds.

mocha -t 3000

is equivalent to:

mocha --timeout 3s

To disable timeouts entirely, you can use --no-timeouts which is equivalent to --timeout 0:

mocha --no-timeouts

Mocha also allows you to set the threshold for slow running tests by using the -s, --slow <ms> option. The default threshold is 75ms. As you saw earlier, Mocha uses this threshold value to highlight tests that are taking too long to run.

mocha --slow 100

Running matching tests

The -g, --grep <pattern> flag instructs Mocha to run tests and test suites that match a particular pattern (regular expression), which is internally converted to a RegExp.

The -f, --fgrep <string> flag, as stated earlier, instructs Mocha to run only tests and test suites that contain the specified string.

The following command will run all tests and test suites that contain the string ‘array’.

mocha -f array

Including files and modules

The -r, --require <module> flag allows you to require modules/libraries that you use in your test files such as assertion libraries instead of manually invoking require() in your code. This works for modules like should.js. However, to access the module’s exports, you will have to require the module in your code.

mocha --require should

The --file <file> flag allows you to add one or more files you want to be included first in your test suite. These files may contain some form of setup logic required for your tests. The --file flag can be used multiple times to include multiple files.

Mocha interface and reporter

As stated earlier, Mocha provides several interfaces for writing tests. The default is the BDD interface, which is what is being used throughout this guide. The -u, --ui <name> allows you to specify another interface to use.

mocha --ui exports

The -R, --reporter <name> flag allows you to specify the reporter you prefer for displaying the test results. The default reporter is spec, which is what is being used throughout this guide. Mocha also allows you to specify third-party reporters using this flag.

mocha -R list

Mocha in the browser

The Mocha test runner can also be used in the browser. Every release of Mocha contains builds of ./mocha.css and ./mocha.js for use in the browser. Here is a simple setup to run Mocha tests on the browser.

Set up the public files

Create a new public directory in the root of your project. Next, create a new file named index.html in the just created public directory and add the following content to it:


<!-- public/index.html -->

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Mocha Tests</title>
  
  <!-- Include Mocha CSS styles -->
  <link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet">
</head>

<body>
  <div id="mocha"></div>
  
  <!-- Add the Chai assertion library -->
  <script src="http://chaijs.com/chai.js"></script>
  
  <!-- Add the Mocha test library -->
  <script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
  
  <script>
    // Set chai.expect as a global variable
    var expect = chai.expect;
    
    // Setup Mocha to use the BDD interface
    mocha.setup('bdd');
  </script>
  
  <!-- Import the sum function -->
  <script src="/sum.js"></script>
  
  <!-- Import the tests for the sum function -->
  <script src="/sum.test.js"></script>
  
  <script>
    // Run the tests with Mocha
    mocha.run();
  </script>
    
</body>
</html>

Here, notice that the static CSS and JS files for Mocha and the Chai assertion library have been imported into the page. The element serves as the mount point for displaying the test results.

In setting up Chai, chai.expect is mapped to a global variable named expect so that it can be used in the test scripts for making assertions.

Mocha is setup to use the BDD interface by calling mocha.setup(‘bdd’). The tests are run using the mocha.run() method.

Next go ahead and create a new sum.js file inside the public directory you created earlier and add the following content to it:

/* public/sum.js */

function sum() {
  // Convert arguments object to array
  var args = Array.prototype.slice.call(arguments);
  
  // Throw error if arguments contain non-finite number values
  if (!args.every(Number.isFinite)) {
    throw new TypeError('sum() expects only numbers.')
  }
  
  // Return the sum of the arguments
  return args.reduce(function(a, b) {
    return a + b
  }, 0);
}

Next, create a new sum.test.js file in the public directory with the following content:

/* public/sum.test.js */

describe('#sum()', function() {
  context('without arguments', function() {
  
    it('should return 0', function() {
      expect(sum()).to.equal(0)
    })
    
  })
  
  context('with number arguments', function() {
  
    it('should return sum of arguments', function() {
      expect(sum(1, 2, 3, 4, 5)).to.equal(15)
    })
    
    it('should return argument when only one argument is passed', function() {
      expect(sum(5)).to.equal(5)
    })
    
  })
  
  context('with non-number arguments', function() {
  
    it('should throw error', function() {
      expect(function() {
        sum(1, 2, '3', [4], 5)
      }).to.throw(TypeError, 'sum() expects only numbers.')
    })
    
  })
})

Setup a simple server

Next, optionally setup a simple server to serve the public files. For this demo, live-server will be used. Go ahead and install it as a dependency for your project as follows:

npm install --save-dev live-server

Modify the “scripts” section of your package.json file to include a script for serving the public files and running the Mocha tests in the browser. It should look like this:

/* package.json */

{
  "scripts": {
    "test": "mocha",
    "test:browser": "live-server --port=9000 --mount=/:public"
  }
}

Here a “test:browser” script has been added, to start the live server on port 9000 and to serve the files from the public directory.

Finally, run the new script as follows:

npm run test:browser

This should start the server on port 9000 and launch a browser tab for you. The test output on the browser should look like the following screenshot:

Mocha Browser Testing

Conclusion

In this guide, you’ve been taken through the basics of Mocha testing on Node.js and also in the browser. You have also learnt how to write and run tests for your JavaScript programs.

Although this guide is quite extensive, you can always refer to the Mocha documentation for aspects not covered by this guide.

Clap & Follow

If you found this article insightful, feel free to give some rounds of applause if you don’t mind.

You can also follow me on Medium (Glad Chinda) for more insightful articles you may find helpful. You can also follow me on Twitter (@gladchinda).

Enjoy testing…

200’s only : Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. .

Glad Chinda Full-stack web developer learning new hacks one day at a time. Web technology enthusiast. Hacking stuffs @theflutterwave.

Leave a Reply