Automating Karma and headless Chrome with Puppeteer

If you want to configure karma to use headless Chrome in a completely automated way without a global install of Chrome, this post is for you.

Google recently released Puppeteer, a node library that provides a high-level API to control headless Chrome over the DevTools Protocol. This alone is already pretty awesome. But there’s a hidden gem in this package: an internal module that downloads and installs Chromium locally.

We can use this module to overcome one of the issues we find when trying to replace the PhantomJS with headless Chrome: The fact that Chrome needs to be installed globally. This is a headache, specially if you’re trying to run your tests in a Continuous Integration environment and want to have every dependency contained in your project.

So enough talk, and let’s get started.

First install and save puppeteer and karma-chrome-launcher as a dev dependency:

npm install --save-dev puppeteer karma-chrome-launcher

Now, I might have lied a little bit. We’re not going to use Chrome for this. We’re going to use Chromium. Why Chromium and not Chrome? Because Google Chrome requires you to accept a License Agreement on install, and that requires administration privileges which would defeat the whole purpose of having a local installation. In terms of running your tests, this shouldn’t have any relevant difference.

Just place the following code in your karma.conf.js file:

const ChromiumRevision = require('puppeteer/package.json').puppeteer.chromium_revision
const Downloader = require('puppeteer/utils/ChromiumDownloader')
const revisionInfo = Downloader.revisionInfo(Downloader.currentPlatform(), ChromiumRevision)

process.env.CHROME_BIN = revisionInfo.executablePath

module.exports = function(config) {
config.set({
browsers: ['ChromeHeadless']
})
}

Fill in the rest of your karma configuration, and you should be ready to go.

Is there a cleaner way?

This is an undocumented API and this solution is considered a hack because it relies on an internal API that can change at any moment without notice. Puppeteer 0.11.0 will introduce an official and documented way to get Chromium’s executable path: puppeteer.executablePath(). Check the project’s documentation for more details.

With this new puppeteer method, the code will become much simpler:

process.env.CHROME_BIN = require('puppeteer').executablePath()
module.exports = function(config) {
config.set({
browsers: ['ChromeHeadless']
})
}

And that’s it. Let me know in the comments if you have found a better way to do this.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.