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

 
 
  • Gérald Barré
 

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 explanation

Karma allows testing 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.

JavaScript
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.

JavaScript
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 plugins for starting browsers. You can install Karma, the plugins, mocha and chai using npm:

Shell
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 launchers 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:

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

Here's the content of mainSpec.js:

JavaScript
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:

JavaScript
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:

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

You can now run the tests using npm test

Shell
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.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub