How to run JavaScript QUnit Tests upon Deployment using Jenkins & PhantomJS

Check out the first part of the JavaScript Testing Series: Unit Testing Self-Invoking JavaScript Functions

Unit Testing is great. However, the real benefit of unit testing is only achieved when the tests are run before each deployment. In continuous integration (CI) it makes sense to run the tests automatically in the CI tool.

At Akanoo we are using Jenkins which can be extended by various plugins for several use cases. Unfortunately, there is no plugin for QUnit test results. So we have to utilize the existing plugin for JUnit. Two steps need to be done:

  • Find a way to run the tests in Jenkins.
  • Find a way to output the QUnit results as JUnit results.

Running QUnit Tests in Jenkins

Jenkins offers no service to open web pages upon deployment. I didn’t know of any plugin that offers such a thing. So I went out googling. I found a guide in the repository of the HTML5 boilerplate on how to set up QUnit with Jenkins that suggested to use PhantomJS with a QUnit test runner.

Following that lead, the first thing I did was to download PhantomJS and try to run my test HTML file locally. PhantomJS can only run JavaScript files, so I needed a test runner. I took a look at the one mentioned above but found it a little too bold for our needs, so I came with my own solution.

var system = require('system');
var fs = require('fs');
var page = require('webpage').create();

// argument 0 is always the file which is called (this)
if (system.args.length === 1) {
    console.log('Pass the path/to/testfile.js as argument to run the test.');
} else {
    // path is relative to where phantomjs is started
    var url = system.args[1]; // e.g. 'test/unit/tests.html'
    console.log("Opening " + url);
}, function (status) {
    console.log("Status: " + status);
    if (status === "success") {
        setTimeout(function () {
            var path = 'results.xml';
            var output = page.evaluate(function () {
                return document.output;

            fs.write(path, output, 'w');
            console.log("Wrote JUnit style output of QUnit tests into " + path);

            console.log("Tests finished. Exiting.");
        }, 3000);
    } else {
        console.log("Failure opening" + url + ". Exiting.");

What does the runner? It takes an argument with the path to the HTML QUnit test file that is to be opened by PhantomJS. If the argument is missing, we can use console.log() to print the result into the console running PhantomJS. The main part of the script opens the page. If the given file doesn’t exist an error message is logged and PhantomJS terminated. If the file can be opened the JavaScript variable document.output of the test page is evaluated and written into a file called results.xml. The evaluation is done after a timeout of three seconds – the time the tests never exceeded on my local machine.

Output QUnit Results in JUnit Format

In the next step we need to make sure the QUnit results can be interpreted by the Jenkins JUnit plugin. Luckily, there is already a plugin for QUnit to produce the results in a JUnit-style XML report. I installed the plugin and configured it to write the results in the document.output variable that we’ve already seen in the PhantomJS runner above.

The current setup is running fine on my local machine: PhantomJS is installed, can be started via shell to execute the runner script, opening the QUnit test HTML file and saving the JUnit-style report into results.xml.

Creating the Jenkins Pipeline

Let’s make sure the job is also running in Jenkins. At Akanoo, Jenkins lies inside a docker image, so I edited the Dockerfile to download and unpack PhantomJS. Use the correct version (32bit or 64bit) — I first used 32bit on a 64bit machine and wondered why it didn’t work. Make sure to add PhantomJS to your PATH variable.

Jenkins allows by default to define multiple build steps for one build. But we want to achieve that the full build is terminated as soon as one step fails. Jenkins offers the Pipeline plugin to define multiple stages of a build. So I installed the pipeline and the JUnit plugin and restarted Jenkins.

I have configured several stages in the pipeline:

  1. Checkout the latest version of code from Git.
  2. Run the tests in PhantomJS, archive the test results and report results to the JUnit plugin.
  3. Build, if the previous step didn’t fail.

To make the build fail if an error in the unit tests occured, we can utilize a try-catch-block. The Groovy script in the pipeline also allows to run shell scripts which we need to run PhantomJS. I came up with the following script:

node {
    stage('Version Control') {
        // checkout the latest version from Git
    stage('Test') {
        try {
            // run PhantomJS
            sh 'cd ${JENKINS_HOME}/path/to/unit/tests && phantomjs phantomjs-runner.js tests.html'
            // move result file into workspace
            sh 'mv ${JENKINS_HOME}/path/to/unit/tests/results.xml ${JENKINS_HOME}/workspace/${JOB_NAME}'
            // archive test results with relative path from ${JENKINS_HOME}/workspace
            step([$class: 'JUnitResultArchiver', testResults: '**results.xml'])
            // report to JUnit with relative path from ${JENKINS_HOME}/workspace
            junit '**results.xml'
        } catch(err) {
            throw err
    stage('Build') {
        // I would build now if the test didn't fail

Let’s discuss the script line-by-line. At first, we have the Version Control stage. I assume you know how to checkout from Git. You may also omit this stage if the script is stored on the same machine as Jenkins.

In the Test stage a shell script executes PhantomJS with two parameters: the phantomjs-runner.js file we discussed above and the QUnit HTML test file. The results of the test are stored in a file called results.xml in the same folder the tests lie in. In the next line we move it into the Jenkins workspace of the current job. The step command is used to store the test results using the JUnitResultArchiver to be able to analyse the results of all tests later. We also send the results to the JUnit plugin to check for errors. This step will throw an exception if errors are found that is caught by the try-catch-block and re-thrown to stop the build before starting the Build step.

In the Build step the actual build would run. This step depends on what you want to achieve. In our case we run a Groovy script.


We managed to configure a Jenkins build pipeline that checkouts the current version from Git (or any other version control system), runs the QUnit tests in a PhantomJS headless browser, returns the test results in JUnit-style format, archives the results and only builds if the tests were successful.

It took me a couple of hours to figure out the single steps and bring everything together. I hope you found this useful. If you have any questions or ideas for optimization, please leave a comment below.

Published by

Bendix Sältz

Bendix Sältz works as a JavaScript developer on our tracking library, leads the team to do the technical integrations of our tracking tag into our customer's online shops and is project manager for the dashboards we offer our clients to analyse their performance. For questions you can reach out in the comments below.