Sunday, September 1, 2013

How to execute the maven-karma-plugin in a CloudBees Jenkins build job (by installing NodeJs and Karma)

I recently faced the task of getting my new JavaScript unit test suite implemented using Karma to execute as part of a Maven build. The maven-karma-plugin was the obvious choice and worked like a charm on my own machine. A few tricks was however necessary to make it work in the Jenkins Maven build job executed on CloudBees. Many thanks to blogs mentioned in the bottom and CloudBees support.

I added a script, which installs NodeJS and Karma if not already installed. This was done by adding a Pre build step of type 'Execute Shell'. Notice that I am also installing phantomjs to execute the tests using a headless browser.

# install nodejs, if using cloudbees (and if not already installed)
curl -s -o use-node https://repository-cloudbees.forge.cloudbees.com/distributions/ci-addons/node/use-node
NODE_VERSION=0.10.13 source ./use-node

ARCH=`uname -m`
node_name=node-${NODE_VERSION}-${ARCH}

# install phantomjs, karma
[ -d /scratch/jenkins/addons/node/$node_name/lib/node_modules/phantomjs ] || npm install -g phantomjs
[ -d /scratch/jenkins/addons/node/$node_name/lib/node_modules/karma ] || npm install -g karma
[ -d /scratch/jenkins/addons/node/$node_name/lib/node_modules/karma-junit-reporter ] || npm install -g karma-junit-reporter
[ -d /scratch/jenkins/addons/node/$node_name/lib/node_modules/karma-phantomjs-launcher ] || npm install -g karma-phantomjs-launcher

Note: I also had to add karma-junit-reporter and the karma-phantomjs-launcher plugins to the Karma configuration (karma.conf.js). My plugin configuration looked like this: 

plugins : [ 'karma-jasmine', 'karma-chrome-launcher', 'karma-firefox-launcher', 'karma-junit-reporter', 'karma-phantomjs-launcher' ]

Now the tricky part was that the system path configured in a pre build step was not available in the main build step. I learned that entried in the $HOME/bin folder would be available in the main build job, and I therefore added the following to the bottom of the script (in the pre build step):

[ -d $HOME/bin ] || mkdir $HOME/bin
[ -f $HOME/bin/karma ] || ln -s /scratch/jenkins/addons/node/$node_name/bin/karma $HOME/bin/karma
[ -f $HOME/bin/node ] || ln -s /scratch/jenkins/addons/node/$node_name/bin/node $HOME/bin/node

Next was to execute the maven-karma-plugin. As I had a Maven build job, there was no possibility to configure a file pattern matching the Karma unit test reports. Jenkins would initially therefore not collect the reports and include them in the unit test output. I solved this by first configuring Karma (karma.conf.js) to place the reports in the target/surefire-reports folder:

junitReporter : {
outputFile : 'target/surefire-reports/karmaUnit.xml'
},

and next configuring the maven-karma-plugin to execute just before unit tests in the Maven phase process-test-classes:

<plugin>
  <groupId>com.kelveden</groupId>
  <artifactId>maven-karma-plugin</artifactId>
  <version>1.3</version>
  <configuration>
    <configFile>${basedir}/src/test/resources/config/karma.conf.js</configFile>
    <browsers>PhantomJS</browsers>
  </configuration>
  <executions>
    <execution>
      <id>karma</id>
      <goals>
        <goal>start</goal>
      </goals>
      <!-- execute karma before test phase to let Jenkins collect the target/surefire-reports/karmaUnit.xml -->
      <phase>process-test-classes</phase>
    </execution>
  </executions>
</plugin>

Voila. Karma unit tests was now executed on my Jenkins build server in CloudBees and JavaScript unit test reports are available through the Web interface.

I've found inspiration in these: