Testing An Angular CLI Project in a Headless Environment

npm install --save-dev karma-phantomjs-launcher
module.exports = function(config) {
config.set({
...
plugins: [
...
require('karma-phantomjs-launcher'),
...
],
browsers: ['PhantomJS'],
...
})
}
apt-get install xvfb firefox dbus-x11
xvfb-run firefox
npm install --save-dev karma-firefox-launcher
module.exports = function(config) {
config.set({
...
plugins: [
...
require('karma-firefox-launcher'),
...
],
browsers: ['Firefox'],
...
})
}
...
"scripts": {
...
"test:ci": "ng test --browser=Firefox --code-coverage=true --single-run=true",
"test:xvfb": "xvfb-run npm run test:ci",
...
}
...
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' apt-get update apt-get install google-chrome
xvfb-run google-chrome --no-sandbox --disable-gpu
module.exports = function(config) {
config.set({
...
plugins: [
...
require('karma-chrome-launcher'),
...
],
browsers: ['Chrome'],
customLaunchers: {
Headless_Chrome: {
base: 'Chrome',
flags: [
'--no-sandbox',
'--disable-gpu'
]
}
...
})
}
...
"scripts": {
...
"test:ci": "ng test --browser=Headless_Chrome --code-coverage=true --single-run=true",
"test:xvfb": "xvfb-run npm run test:ci",
...
}
...
export CHROME_BIN=/usr/bin/google-chrome
exports.config = {
...
capabilities: {
'browserName': 'chrome',
'chromeOptions': {
'args': [
'--no-sandbox',
'--disable-gpu'
]
}
},
...
}
...
"scripts": {
...
"e2e:xvfb": "xvfb-run npm run e2e",
...
}
...

Conclusion

Using a very simple project generated from the Angular CLI I have been able to run all the tests, both unit and e2e tests, on a headless build agent using Xvfb. Using Xvfb is a very versatile solution as I am not restricted to using just one browser, I can theoretically use any browser that will run in a UNIX environment.

module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-firefox-launcher'),
require('karma-phantomjs-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
browsers: ['Chrome'],
customLaunchers: {
Headless_Firefox: {
base: 'Firefox',
flags: []
},
Headless_Chrome: {
base: 'Chrome',
flags: [
'--no-sandbox',
'--disable-gpu'
]
}
},
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
files: [
{
pattern: './src/test.ts',
included: true,
watched: false
}
],
preprocessors: {
'./src/test.ts': ['@angular/cli']
},
mime: {
'text/x-typescript': ['ts', 'tsx']
},
coverageIstanbulReporter: {
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['progress', 'coverage-istanbul']
: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
singleRun: true
});
};
{
"name": "bwe-web-app",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build:prod": "ng build --target=production",
"test": "ng test",
"test:ci": "ng test --browser=Headless_Chrome --code-coverage=true --single-run=true",
"test:xvfb": "xvfb-run npm run test:ci",
"lint": "ng lint",
"e2e": "ng e2e",
"e2e:xvfb": "xvfb-run npm run e2e",
},
"private": true,
"dependencies": {
"@angular/common": "^2.4.0",
"@angular/compiler": "^2.4.0",
"@angular/core": "^2.4.0",
"@angular/forms": "^2.4.0",
"@angular/http": "^2.4.0",
"@angular/platform-browser": "^2.4.0",
"@angular/platform-browser-dynamic": "^2.4.0",
"@angular/router": "^3.4.0",
"core-js": "^2.4.1",
"intl": "^1.2.5",
"rxjs": "^5.1.0",
"zone.js": "^0.7.6"
},
"devDependencies": {
"@angular/cli": "1.0.0-rc.1",
"@angular/compiler-cli": "^2.4.0",
"@types/jasmine": "2.5.38",
"@types/node": "~6.0.60",
"codelyzer": "~2.0.0",
"jasmine-core": "~2.5.2",
"jasmine-spec-reporter": "~3.2.0",
"karma": "~1.4.1",
"karma-chrome-launcher": "^2.0.0",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^0.2.0",
"karma-es6-shim": "^1.0.0",
"karma-firefox-launcher": "^1.0.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-phantomjs-launcher": "^1.0.2",
"karma-typescript-preprocessor": "^0.3.1",
"protractor": "~5.1.0",
"ts-node": "~2.0.0",
"tslint": "~4.4.2",
"typescript": "~2.0.0"
}
}
const { SpecReporter } = require('jasmine-spec-reporter');

exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome',
'chromeOptions': {
'args': [
'--no-sandbox',
'--disable-gpu'
]
}
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
},
onPrepare() {
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
}
FROM jetbrains/teamcity-minimal-agent

RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt install -y \
dbus-x11 \
firefox \
google-chrome-stable \
nodejs \
npm \
wget \
xvfb \
&& npm install -g \
tslint \

ENV CHROME_BIN /usr/bin/google-chrome

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store