Karma is a well known framework-agnostic test runner. It’s the glue between your JavaScript tests and your test results.

Because Karma doesn’t care what test framework, assertion library, or browser you use, configuration can be a bit of a headache. You have to specify everything.

Most examples I’ve seen use PhantomJS as a headless browser, and it works ok. But on my current project, we have 4,700+ JavaScript tests written with Jasmine. When I run those tests manually through Chrome using the Jasmine stock HTML test runner, the tests run in just over 15 seconds.  When I run those same tests from the command line or the build server using Karma and PhantomJS, the tests run in about 1.5 minutes – much slower.

I was looking for something faster that would work well both locally and on the build server, and the new-ish Chrome headless browser sounded promising. After getting it set up and working, the Karma tests with Chrome headless as the browser now run in under 10 seconds. Yay!

Here’s a step-by-step to getting it set up with the minimum configuration.

Installation

To install, first make sure you’ve got Node installed and then run:

npm install karma --save-dev

This installs karma for this project. Then:

npm install karma-cli -g

This installs the karma-cli globally for this computer. Next:

npm install karma-jasmine karma-chrome-launcher jasmine-core --save-dev

This installs common plugins we'll need for this project: karma-jasmine, karma-chrome-launcher and jasmine-core.

Next, we will install Puppeteer, an API for Chrome’s headless browser. If you are not running your JavaScript tests on your build server, you can skip this step. I was able to get my local Chrome headless browser running without this, but I needed this installed for my build server, Visual Studio Team Services (VSTS).

npm install puppeteer --save-dev

Once puppeteer is installed for this project, it's time to configure things.

Configuration

You need to specify all the settings for Karma because it doesn’t know anything about your project.  It’s like the opposite of zero-config - it’s infinite-config.

Recognizing this, the Karma team came up with a bunch of simple questions to get most of what you need added to your config file.  From the command line, run:

karma init karma.conf.js

Pick jasmine for the testing framework, no for RequireJS (unless you need that), Chrome for the browser (we’ll adjust this later), and src/**/*.js and tests/**/*-tests.js for the source and test files (unless you prefer a different folder/filename pattern), and yes that we’ll let the watcher keep an eye on file changes. 

This is what mine looked like:

karma-conf-js

Next, open package.json in the project root and scripts section if you don’t already have one at the top level.

  "scripts": {
    "test": "karma start"
  },

This addition let’s us run the tests from the command line with npm test or karma start. This is very helpful for build servers, like VSTS, which know about Node and npm, but not about Karma. Running npm test as an npm task on VSTS works nicely.

Write a sample test

We won’t know if it’s working until we write a test and see it fail and then see it pass.  Let’s do that now.

Add a new file under /tests named sample-tests.js. This file should get picked up by our glob pattern in karma.conf.js. Add this code to it:

describe("Testing Karma with Chrome headless", () => {
  
    it("Should work if configuration is correct", () => {
      expect(false).toBeTruthy();
    }); 
    
});

You would never write this kind of test for a real project, but we just want to know if we've got everything working. This test should fail. Let's run it and see. From the command line, enter:

karma start

You should see a failing test like this.

failing test

You can use CTRL-C to break from the watch if you need to. Change the test so the assert is:

expect(true).toBeTruthy();

and save. As soon as you save the changes in the test file, the watcher should re-run the tests and you should see this.

passing test

If you don’t have a passing test this point, go back and see if you missed a step or download from the GitHub repository and try running from that code.

Chrome Headless

When the tests run, Karma creates a web server, opens Chrome, and runs the tests using the Chrome browser. You can see it running. But we want the headless Chrome browser for speed and to keep that extra browser out of the way.

Use CTRL-C to cancel the watch Karma is running so we can kick it off again when we’ve made our changes. Open karma.conf.js and find the browsers section.  Change it to:

browsers: ['ChromeHeadless'],

This is the token used to specify the headless (not visible) version of Chrome. There are a lot more browsers you can choose from.

Next, find the singleRun section and change it to:

singleRun: true,

and save. This is needed for your build server, or at least if your build server is VSTS.

Re-run with karma start. You should get similar results, with a passing test, but now it says the browser is HeadlessChrome. Also, the test stops and returns to the command prompt when completed instead of staying in watch mode.

chrome headless

I don’t really care for the watch running all the time on tests, as I prefer to run my tests manually, so I usually turn

autoWatch: false,

in karma.conf.js. I also don't like a lot of chatter in my test output, so I also set

logLevel: config.LOG_ERROR,

Now when I run the tests, I get just the last line from above. That's more like it!

final

All the code for this post can be found on GitHub.