Application testing
Angular CICD Continuous Integration Protractor Visual Studio Code

Headless Testing in an Angular Application

Welcome to today’s post.

Today I will discuss and show how to use headless testing within an Angular application.

In a previous post, I showed how you can implement and run unit tests of components within an Angular application, and unit testing user interface components within an Angular application. Unit tests can run unattended and run within a build pipeline. Where headless testing is most useful is where we wish to run end to end interface tests for our Angular application, and where there no testers present to carry out those tests. In this post I will first explain what headless testing is, then show how it can be configured within an Angular application. I will then show how to run a headless test and examine the output from the console to assess the results.

What is headless testing?

Headless testing is used to allow us to run the end-to-end UI tests of a web application without running it with a browser. There are some environments, such as build servers or test servers where it would not be possible to run browsers during testing.

We can unit test a backend service such as Web API without requiring a visible test runner. The results of the test are then published to a continuous integration tool and trigger a deployment to a server that is hosting the service or API. We can do likewise with an invisible UI test runner. All of this is automated, saving the test engineer time to manually run and deploy artifacts to a server environment.

One of the additional benefits of being able to run end to end tests independently without (or decoupling) the browser is to be able to run the tests from within a build test continuous integration tool.

Configuring Angular for Headless Testing

Within Angular, there is built in support for the Karma test harness to be able to launch the tests within Chrome. Within package.json, the package for the Karma Chrome launcher is shown:

"karma-chrome-launcher": "~2.2.0",

Before we can allow our Angular application to use headless testing, we must update the Karma configuration, karma.config.js to allow us to configure a headless Chrome browser and launch it (if needed) with some custom settings. In the browsers key, we add the base headless configuration ChromeHeadless and our custom headless configuration, which is will call ChromeHeadlessCustom:

module.exports = function (config) {
  config.set({

	…

    browsers: ['Chrome', 'ChromeHeadless', 'ChromeHeadlessCustom'],
    customLaunchers: {
      ChromeHeadlessCustom: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox']
      }
    },
    singleRun: false,
    restartOnFileChange: true
  });

Note: I have used the no sandbox option for the headless configuration if we are within a container-based environment, Google Chrome is unable to provide sandboxing when running in a container-based environment.

In our package.json environment we will need to add an additional script that starts testing with the headless Chrome configuration we setup in our Karma configuration:

"scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "headless-test": "ng test --watch=false --browsers=ChromeHeadlessCustom",
    "lint": "ng lint",
    "e2e": "ng e2e"
},

Note: From Angular 6 onwards, the option –single-run is no longer available in the command line. It is replaced with the option –watch=false. There is an additional option, singleRun in karma.config.js which allows the tests to be run once without continuously polling for changes:

singleRun: true, 

An additional change we need to make is with the Protractor E2E framework is to allow the headless option to be included when starting the E2E tests within Chrome. We amend chrome options within e2e\protractor.config.js as shown:

capabilities: {
    'browserName': 'chrome',
    chromeOptions: {
      args: [ "--headless", "--disable-gpu" ]
    }
},

Execution of the Headless Test

To run our headless E2E test we enter the following command:

npm run headless-test

Typical output is shown below:

28 01 2021 15:48:07.720:WARN [karma]: No captured browser, open http://localhost:9876/    
28 01 2021 15:48:07.967:INFO [HeadlessChrome 87.0.4280 (Windows 10.0.0)]: Connected on socket c-t3U2pIOqWqcruxAAAA with id 859487
LOG: 'number top books = 3'
HeadlessChrome 87.0.4280 (Windows 10.0.0): Executed 0 of 33 SUCCESS (0 secs / 0 secs)
LOG: 'number top members = 3'
	…
HeadlessChrome 87.0.4280 (Windows 10.0.0): Executed 15 of 33 SUCCESS (0 secs / 3.015 secs)
LOG: 'account users component created'
HeadlessChrome 87.0.4280 (Windows 10.0.0): Executed 16 of 33 SUCCESS (0 secs / 3.275 secs)
LOG: 'read users from API'
HeadlessChrome 87.0.4280 (Windows 10.0.0): Executed 17 of 33 SUCCESS (0 secs / 3.48 secs)
LOG: 'account users component created'
	…
LOG: 'BookNewComponent instantiated'
HeadlessChrome 87.0.4280 (Windows 10.0.0): Executed 31 of 33 SUCCESS (0 secs / 6.349 secs)
LOG: 'number of genres  = 9'
HeadlessChrome 87.0.4280 (Windows 10.0.0): Executed 31 of 33 SUCCESS (0 secs / 6.349 secs)
HeadlessChrome 87.0.4280 (Windows 10.0.0): Executed 33 of 33 SUCCESS (7.452 secs / 7.05 secs)
TOTAL: 33 SUCCESS

The same tests can be run from within a command-prompt with the same result.

To summarize, headless testing is a powerful feature within the Angular environment, which allows developers and test engineers to leverage continuous integration tools to automate test runs for our UI applications in Angular.

In a later post I will show how useful this is when I integrate this with a CI tool.

That’s all for today’s post.

I hope you found this post interesting and useful.

Social media & sharing icons powered by UltimatelySocial