Test JavaScript code using Karma, Mocha, Chai and headless browsers

Web applications use more and more JavaScript. As for the back-end code, you must test it. However, testing front-end code is not as simple as testing back-end code. Indeed, you have to test it on multiple browsers (Chrome, Edge, Firefox, Safari, etc.) and their different versions. This means you need to test your code on at least 10 browsers to be sure your code will works as expected.

In this post, I'll show how to use Karma to run tests, and Mocha and Chai to write them.

Quick explaination

Karma allows to test your code on real browsers and real devices such as phones, tablets. It starts the browsers and runs the tests on them.

Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.

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

Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.

assert.equal(foo, 'bar');

To sum up, Karma runs mocha on multiple browsers. The assertions of the tests are written using chai.

Installation

Karma comes with multiple plugins. There are plugins for using test frameworks, and plugings for starting browsers. You can install Karma, the plugins, mocha and chai using npm:

npm i --save-dev karma karma-mocha karma-chai
npm i --save-dev karma-chrome-launcher karma-firefox-launcher karma-ie-launcher
npm i --save-dev mocha chai

You'll find the list of launcher on GitHub: Karma launchers

Then, create a function, a test, and the karma configuration. The structure of your application should look like:

MyProject
├── src
│   └── main.js
├── test
│   └── mainSpec.js
├── package.json
└── karma.conf.js

Here's the content of main.js:

function endsWith(str, suffix) {
	return str.indexOf(suffix, str.length - suffix.length) !== -1;
}

Here's the content of mainSpec.js:

describe('main', function () {
    describe('#endsWith()', function () {
        it('should return true when the value ends with the suffix', function () {
            assert.equal(true, endsWith("abcd", "cd"));
        });

        it('should return false when the value does not end with the suffix', function () {
            assert.equal(false, endsWith("abcd", "cde"));
        });
    });
});

Then, you must configure karma. Create a file karma.config.js with the following content:

module.exports = function (config) {
    config.set({
        frameworks: ['mocha', 'chai'],
        files: [
            'src/**/*.js',
            'test/**/*.js'
        ],
        reporters: ['progress'],
        port: 9876,  // karma web server port
        colors: true,
        logLevel: config.LOG_INFO,
        browsers: ['ChromeHeadless', 'Firefox', 'FirefoxDeveloper', 'FirefoxNightly', 'IE'],
        autoWatch: false,
        concurrency: Infinity,
        customLaunchers: {
            FirefoxHeadless: {
                base: 'Firefox',
                flags: ['-headless'],
            },
        },
    })
}

By default, the karma-firefox doesn't register the headless version of the browser, so I add it manually in the customLaunchers section.

Finally, add the test script in packages.json:

{
  "name": "my-project",
  "version": "0.0.0",
  "devDependencies": {
      // code omited for brevity
  },
  "scripts": {
    "test": "karma start --single-run --browsers ChromeHeadless,FirefoxHeadless,IE karma.conf.js"
  }
}

You can now run the tests using npm test

npm test

Conclusion

Your test environment is now set up. You can add lots of tests for your front-end code. Karma and Mocha have lots of functionalities. In this post, we just cover the surface. Be sure to read the documentation to explore the possibilities of these solutions.

Leave a reply