The homepage of James Navin

Tag Archives: webjars

I spent several hours at work recently trying to solve this problem. The solution has a few moving parts to it, so I thought I’d jot down some notes to make it easier on myself and others in the future.

The problem

At my workplace we have an established Maven/Java workflow with tooling in place for executing CI builds and deploying built artefacts to our DEV/TEST/PROD environments etc. Some time ago we adopted Webjars as a way to manage static web resources via the Maven dependency management mechanism.

As we have become more front-end heavy and as the amount of business logic in our front-end code has increased, it has become increasingly important to integrate javascript unit and e2e tests into our build processes.

After evaluating some options we settled on the Karma test runner. This is a powerful test runner that supports cross-browser testing, multiple reporting formats and the ability to ‘watch’ project files and automatically re-run tests when a change is detected (very cool!). The easiest way to get Karma running is on NodeJS, which we didn’t have set up in our environment.

How do we integrate Karma-driven tests on a project that uses Webjar dependencies so that the tests can be run locally AND as part of a Maven CI build using our existing tooling?

If you want to skip ahead, a fully working project is available on github. Take a look at the README to get started.

Some background

First, some background on the various tools and libraries used for anyone not familiar with them.

Maven – http://maven.apache.org/Maven is a dependency management and project build management system. It has become a de-facto standard for Java projects. It supports a wide variety of plugins that can be used together to perform arbitrarily complex build processes.

Webjars – http://webjars.orgWebjars is a convention for packaging client-side web libraries as JAR dependencies so they can be managed via Java-oriented tools such as Maven. They have the nice property that they can be included and managed as a project dependency in the same way that any regular JAR library can.

Karma – http://karma-runner.github.io/Karma is a test runner library for executing JS tests. The tests can be run across multiple browsers and on multiple devices.

The solution

Overview

If you don’t want to get into the details, the breakdown of the solution is as follows:

Setup webjar dependencies

Host webjars using the Jetty Maven Plugin when developing locally

Setup Karma to run locally using the hosted Webjar dependencies

Use the Maven Dependency plugin to unpack Webjar dependencies during a CI build

Create a CI-specific Karma configuration that uses the unpacked dependencies rather than the hosted ones during a CI build

Use the Frontend-Maven-Plugin to install NodeJS and Karma local to the project during a CI build and execute the Karma tests

(Optional) Add JUnit style reporting so the Karma test results can be reported on by CI tooling such as Jenkins etc.

Setup your project to use Webjars

This part is easy. Webjar dependencies can be added to your POM just as any other dependency.

The Webjars documentation has instructions for getting Webjars running on a number of platforms. For ease of setup we’ll use a Servlet 3.0 container (see next section).

Setup Jetty configuration

The easiest way to make the webjar dependencies available is via a Servlet 3.0 container such as Jetty. I used the Jetty Maven Plugin which allows you to launch a fully configured Jetty container using Maven.

Setup your Karma tests

Ideally you will be able to setup Karma to run locally on your development machine. Follow the installation instructions to get setup with NodeJS and Karma. If you can’t install Karma locally due to policy restrictions etc. you can get away without it – you will just need to execute tests via the Maven build which adds a bit of overhead.

The Karma setup instructions will get you most of the way there. Following Maven project conventions I put the karma.conf.js in src/test/webapp/js, which means you will need to set the project basePath appropriately. You will also want to reference the webjar dependencies at the container-hosted URL (e.g. http://localhost:8080/…).

Setup Karma tests to run in a CI build

The Karma tests now run locally and will helpfully watch for changes to project resources and re-run the tests (how good is that!). Unfortunately, they still require a container to host the webjars which is not really appropriate for a CI build. Your environment might support this setup on your build server, but a better solution is to remove the dependency on the container altogether during a CI build.

First, create a Karma config specific for your CI job, e.g. karma.ci.conf.js. In this config you will want to:

Reference the primary Karma config file; and

Override the config object to switch to single-run mode and stop watching files

The last thing left is to tell Karma how to resolve the unpacked dependencies. We could simply set the files property again with the new file locations, but this will result in duplication and we hate duplication. A better option is to take advantage of the fact that Karma config files are simply JavaScript and write a function to do the resolution for us:

Karma is now ready to run in a CI build. We just need to make Maven execute them at the correct time.

Invoke Karma from Maven

Karma runs on NodeJS. A simple way to get the tests running from Maven would be to execute the Karma CLI from the Maven build. However, this would require installing Node on your build server which can be difficult in some environments.

That’s where the Frontend Maven Plugin comes in. This neat plugin will install NodeJS local to the project, run NPM to install required dependencies, and then execute Karma.

If everything is working your tests should be run during the test phase of your build.

(Optional) Add a JUnit reporter

A little added extra that I find particularly useful is to configure a JUnit reporter for Karma that outputs test results in the JUnit XML format. This can be read along with your regular Java unit test results by your CI server to give aggregated test results that include your JS tests.

Summary

A Maven configuration that can setup Node+NPM+Karma as part of the build and execute the Karma tests

A working example project that illustrates everything above is available on github. Feel free to clone it and experiment with different configurations that make sense for your environment.

There are still some rough edges with this configuration that I am ironing out as development continues. These include:

You need to remember to run the Jetty server before you try to execute your local Karma tests for the first time. If you don’t you get a less-than-helpful error.

There are some issues with using Node/NPM and the Frontend Maven Plugin behind a corporate proxy server that has caused some problems for us. I haven’t gone into details here, but some workarounds have been needed to make it work nicely.

If you have thoughts or comments please post below. I’d really like to hear if/how other people have solved this (possibly arcane) problem.