Karma and Jasmine can be used to write tests for front end applications and can also be configured to write tests for vanilla JS. If you have worked on angular JS then you must be aware of karma tests. In this article I’ll show you how to tweak karma to setup unit tests with karma and jasmine for vanilla JS (which may or may not manipulate the DOM), and run those tests and setup coverage in gitlab CI.
Setting up tests with Jasmine
- For the setup make a directory and name it karma-jasmine
- In the directory add three files: index.html WebSDK.js WebSDK.test.js
- In WebSDK.js copy this small snippet of code:
function WebSDK() {
this.args = {
param: 'param'
};
}
WebSDK.prototype.setArgs = function(args) {
this.args = args;
}
WebSDK.prototype.getArgs = function() {
return this.args;
}
- As you can see the WebSDK object has two methods setArgs and getArgs. We will be writing unit tests for these methods.
- Let’s write tests in WebSDK.test.js:
describe('WebSDK: Unit tests', () => {
let webSDK;
beforeEach(() => {
webSDK = new WebSDK();
})
it('setArgs should set webSDK args', () => {
webSDK.setArgs({
param: 'test'
})
expect(webSDK.args.param).toBe('test');
})
it('getArgs should get webSDK args', () => {
const args = webSDK.getArgs();
expect(args.param).toBe('param');
})
})
- Now in you index.html file you have to load the jasmine cdns and the WebSDK files to run the tests. Copy the code below in your index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Testing with Jasmine</title>
<link
rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine.min.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine-html.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/boot.min.js"></script>
<script src="WebSDK.js"></script>
<script src="WebSDK.test.js"></script>
</head>
<body></body>
</html>
- Now when you open index.html in chrome you will see something like this:
- Your jasmine test setup is complete! In the next section we will setup our tests with Karma & Jasmine.
Setting up tests with Karma and Jasmine
- In your karma-jasmine directory run npm init -y
- To install karma dependencies run:
npm i karma karma-chrome-launcher karma-jasmine karma-jasmine-html-reporter karma-spec-reporter
- Now that you have installed all the dependencies you need to add a configuration file for your tests, namely: `karma.conf.js`. For now paste this config in your karma.conf.js file:
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
{ pattern: 'WebSDK.js', watched: false },
'*.test.js'
],
exclude: [],
preprocessors: {},
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-spec-reporter'),
require('karma-jasmine-html-reporter'),
],
reporters: ['spec', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_DISABLE,
autoWatch: true,
browsers: ['Chrome'],
client: {
clearContext: false,
},
singleRun: false,
concurrency: Infinity,
});
};
As you can see in the config above our tests will run in Chrome browser on port 9876. The files parameter of the config specifies the files that you need to test as shown in the config. You can also use it to import cdn scripts like:
- To run the tests use this command: node_modules/.bin/karma start karma.conf.js
- Browser output:
Terminal output:
Setting up test coverage with karma
- add a file karma.cov.conf.js in the directory and paste this config:
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
{ pattern: 'WebSDK.js', watched: false },
'*.test.js'
],
exclude: [],
preprocessors: {
'WebSDK.js': ['coverage'],
},
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-spec-reporter'),
require('karma-jasmine-html-reporter'),
require('karma-coverage')
],
reporters: ['spec', 'kjhtml', 'progress', 'coverage'],
port: 9878,
colors: true,
logLevel: config.LOG_DISABLE,
autoWatch: true,
browsers: ['Chrome'],
client: {
clearContext: false,
},
singleRun: false,
concurrency: Infinity,
coverageReporter: {
type: 'html',
dir: 'coverage/',
check: {
global: {
statements: 50,
branches: 50,
functions: 50,
lines: 50,
},
},
}
});
};
As you can see coverage config is quite similar to the test config, the only difference is a change in port, coverageReporter, karma-coverage plugin and the preprocessors key. Please note that to get coverage for a file you should add it in preprocessors param like it has been added in the config above.
- To run, use the command: `node_modules/.bin/karma start karma.cov.conf.js`
- The coverage status will be written in the coverage directory, open it to view the results. Example:
Karma config to run tests in Headless chrome
- Please paste the config below in karma.cov.conf.js:
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
{ pattern: 'WebSDK.js', watched: false },
'*.test.js'
],
exclude: [],
preprocessors: {
'WebSDK.js': ['coverage'],
},
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-spec-reporter'),
require('karma-jasmine-html-reporter'),
require('karma-coverage')
],
reporters: ['spec', 'kjhtml', 'progress', 'coverage'],
port: 9878,
colors: true,
logLevel: config.LOG_DISABLE,
autoWatch: true,
browsers: ['Chrome', 'ChromeHeadless'],
client: {
clearContext: false,
},
customLaunchers:{
HeadlessChrome:{
base: 'ChromeHeadless',
flags: [
"--no-sandbox",
]
}
},
singleRun: true,
concurrency: Infinity,
coverageReporter: {
type: 'html',
dir: 'coverage/',
check: {
global: {
statements: 50,
branches: 50,
functions: 50,
lines: 50,
},
},
}
});
};
Please update your package.json scripts like:
“test”: “node_modules/.bin/karma start karma.conf.js”,
“test:coverage”: “node_modules/.bin/karma start karma.cov.conf.js --browsers ChromeHeadless”
Setting up tests and coverage in Gitlab CI
I’m going to use Docker for creating an environment similar to GitLab and building a base image to use in our Gitlab runner. Hence you need to have Docker installed on your machine and be familiar with Docker. You need to have a Docker Hub or any other Docker registry account so you can push your image for using in Gitlab.
I tried to run the tests with a node image as a base layer but the tests failed because karma tests require a browser to function. Hence we need to provide a browser in our container environment. To do that I pushed an image to dockerhub with Chrome installed.
Dockerfile:
FROM node:14.6.0RUN apt-get update -qqy \
&& apt-get -qqy install xvfb \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/*RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
&& apt-get update -qqy \
&& apt-get -qqy install google-chrome-stable \
&& rm /etc/apt/sources.list.d/google-chrome.list \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/* \
&& sed -i 's/"$HERE\/chrome"/xvfb-run "$HERE\/chrome" --no-sandbox/g' /opt/google/chrome/google-chrome
Commands used to push image to dockerhub:
docker build -t node-chrome:v2 .
docker tag node-chrome:v1 kartikkhk/node-chrome:v2
docker push kartikkhk/node-chrome:v2
Now we just need to add a .gitlab-ci.yml file to run our tests and check coverage in gitlab CI!
.gitlab-ci.yml:
image: kartikkhk/node-chrome:v2stages:
- testsdk:tests:
stage: test
before_script:
- npm install --silent
script:
- npm run test:coverage