Tuesday, May 30, 2017

Going Headless without headache

You're done with a first beta of your angular 4 app.
Thanks to Test Your Angular Services and Test your Angular component, you get a good test suite 🤗. It runs ok with a npm test on your local dev environment. Now, is time to automate it and have it run against a CI server: be Travis, Jenkins, choose your weapon. But most probably you will need to run you test headlessly.

Until recently the only way to go is to use PhantomJS, a "headless" browser that can be run via a command line and is primarily used to test websites without the need to completely render a page.

Since Chrome 59 (still in beta), you can now use Chrome headless! In this post we'll see how to go headless: the classical way with PhamtomJS and then we'll peek a boo into Chrome Headless. You may want to wait for official release of 59 (it should be expected to roll out very soon in May/June this year).

Getting started with angular-cli

Let's use angular-cli latest release (v1.0.6 at the time of writing), make sure you have install it in [1].
npm install -g @angular/cli  // [1]
ng new MyHeadlessProject // [2]
cd MyHeadlessProject
npm test // [3]
In [2], create a new project, let's call it MyHeadlessProject.
In [3], run your test. You can see by default the test run in watch mode. If you explore karma.conf.js:
module.exports = function (config) {
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],  // [1]
    singleRun: false       // [2]
If you switch [2] to false, you can go for a single run.
To be headless you would have had to change Chrome for PhantomJS.

Go headless with PhamtomJS

First, install the phantomjs browser and its karma launcher with:
npm i phantomjs karma-phantomjs-launcher --save-dev
Next step is to change the the karma configuration:
browsers: ['PhantomJS', 'PhantomJS_custom'],
customLaunchers: {
 'PhantomJS_custom': {
    base: 'PhantomJS',
    options: {
      windowName: 'my-window',
      settings: {
        webSecurityEnabled: false
    flags: ['--load-images=true'],
    debug: true
phantomjsLauncher: {
  exitOnResourceError: true
singleRun: true
and don't forgot to import them at the beginning of the file:
plugins: [
Running it you got the error:
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
  TypeError: undefined is not an object (evaluating '((Object)).assign.apply')
  at webpack:///~/@angular/common/@angular/common.es5.js:3091:0 <- src/test.ts:23952
As per this angular-cli issue, go to polyfills.js and uncomment
import 'core-js/es6/object';
import 'core-js/es6/array';
Rerun, tada !
It works!
... Until you run into a next polyfill error. PhantomJS is not the latest, even worse, it's getting deprecated. Even PhantomJS main maintainer Vitali is stepping down as a maintainer recommending to switch to chrome headless. It's always cumbersome to have a polyfilll need just for your automated test suite, let's peek a boo into Headless Chrome.

Chrome headless

First of all, you either need to have Chrome beta installed or have ChromeCanary.
On Mac:
brew cask install google-chrome-canary
Next step is to change the the karma configuration:
browsers: ['ChromeNoSandboxHeadless'],
customLaunchers: {
  ChromeNoSandboxHeadless: {
    base: 'ChromeCanary',
    flags: [
      // See https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
      // Without a remote debugging port, Google Chrome exits immediately.
      ' --remote-debugging-port=9222',
and don't forgot to import them at the beginning of the file:
plugins: [
Rerun, tada! No need to have any polyfill.

What's next?

In this post you saw how to run your test suite headlessly to fit your test automation CI needs. You can get the full source code in github for PhantomJs in this branch, and for Chrome Headless with Canary in this branch. Have fun and try it on your project!

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.