Integrating Karma 0.8 tests in Maven with Sonar(Cube) test coverage
NOTE: this blog post was written for version 0.8 of the Karma test runner. An updated blog post for the new Karma 0.10 can be found here.
For my current project we are using Maven to build our AngularJS application. Furthermore we use Sonar (recently renamed to SonarCube) to monitor our code standards / best practices and unit test coverage. In this blog post we describe how to integrate the Karma (Testacular) test runner with Maven and how to add your AngularJS (or any JavaScript) application to SonarQube.
Basic integration of the Karma test runner in Maven
When I initially integrated the Karma test runner with Maven I used the Maven AntRun plugin because there was no Karma plugin for Maven at that moment. Luckily integrating Karma into Maven becomes much easier using the official maven-karma-plugin:
com.kelveden
maven-karma-plugin
1.3
start
PhantomJS
dots
false
false
In the
- Instead of using the browsers specified in the Karma configuration file we want to use the "headless" browser "PhantomJS" in order not to spawn any browser windows during our Maven build.
- To allow the Karma progress to be properly send its output to a log file we use "dots" for progress reporting instead of the standard percentage that's being updated.
- Since colors are also not possible in a log file we also disable the use of colors.
- Finally we explicitly turn off "autowatch" because we are executing a "single run" in Karma (which is the default behavior when using the Karma Maven plugin) and want to prevent the following unwanted message:
config - autoWatch set to false, because of singleRun
Generating HTML unit test coverage reports
To generate HTML unit test coverage reports while running the Karma test runner we will have to modify the "karma.conf.js" Karma configuration file:
- To pre-process the source files to allow test coverage reporting;
this process of altering the sources is also known as instrumentation. - To contain an additional "coverageReporter" section to specify that we want HTML reporting and the location of the generated reports
preprocessors = {
// ...
'js/*.js': 'coverage' // (1)
};
coverageReporter = { // (2)
type : 'html',
dir : 'target/karma-coverage'
}
NOTE: this blog post uses the (old) pre-0.10 configuration file format of the Karma test runner. However when using version 0.10 all snippets (and sample application) should still be working. In order to generate the unit test coverage you will have to append ",coverage" to the <reporters>
in the Maven POM:
com.kelveden
maven-karma-plugin
dots,coverage
The pre-processing of JavaScript source files dramatically alters the code, causing the line / column numbers of the altered code to no longer match the original ones. Therefore the stack traces of exceptions that occur while testing will also use those altered line / column numbers. Instead of always pre-processing the sources we could disable it at default by commenting it out:
preprocessors = {
// ...
// WARNING: every "coverage" preprocessor line MUST be commented-out
// and will instead be "uncommented" while generating the
// "target/karma-cobertura.conf.js" file in the Maven POM
// 'js/*.js': 'coverage'
};
Instead we use the Maven AntRun Plugin to generate a additional file "target/karma-coverage-html.conf.js" with those lines uncommented:
org.apache.maven.plugins
maven-antrun-plugin
1.7
karma-coverage-html.conf.js
initialize
run
After running (at least) a mvn initialize
a separate "target/karma-coverage-html.conf.js" file is generated to be used for HTML test coverage reporting while using Karma (outside the Maven build) on the command-line or from within Webstorm / IntelliJ IDEA. The generated Karma configuration file differs from the original Karma configuration file in that:
- the "
basePath = '';
" line is altered to "basePath = '..';
" to let Karma know that all paths are relative to "..
" (since the generated "karma-coverage-html.conf.js" is located in "target" whereas all paths in the Karma configuration file are still relative to the directory in which "karma.conf.js" is located) - each earlier commented-out "
// '...': 'coverage'
" line is stripped from its comment (therefore enabling the pre-processing of the sources)
In order to use the generated "target/karma-coverage-html.conf.js" Karma configuration file you will need to add a <configFile>
element to the configuration of the Maven Karma Plugin:
com.kelveden
maven-karma-plugin
${basedir}/target/karma-coverage-html.conf.js
NOTE: Later in this blog post we will modify our Maven POM to generate an additional Karma configuration file for LCOV test coverage reporting and configure the <configFile>
element of the configuration of the Maven Karma Plugin to use it.
Basic integration with SonarCube (no unit test coverage yet)
For a basic integration of your JavaScript code in SonarCube you will have to specify:
- That this particular Maven module is using the JavaScript language (instead of the default Java)
- That all sources in
lib/**
(containing JavaScript libraries) should be ignored. - That SonarCube should reuse existing reports for dynamic analysis
- That information about the executed unit tests can found in "target/surefire-reports"
- The source directory containing our JavaScript source-code.
- The "test" source directory containing our JavaScript (i.e. Jasmine) unit tests.
- That the Karma test runner should create a JUnit style XML report (containing information about the executed JavaScript unit tests)
js
lib/**
reuseReports
target/surefire-reports
${basedir}/js
${basedir}/test
com.kelveden
maven-karma-plugin
dots,junit,coverage
Additionally, in order for Karma "junit" reporter to work we will have to specify in the "karma.conf.js" file where the JUnit XML report should be generated:
// ...
junitReporter = {
outputFile: 'target/surefire-reports/TEST-karma.xml'
};
// ...
NOTE: as it turns out the JavaScript plugin of SonarCube (as of version 1.5) no longer supports importing "unit test execution reports". More information can be found here (see answer of "Ronald") and here.
Integrating unit test coverage with SonarCube
In order to integrate unit test coverage with SonarCube we will need to used LCOV reporting (instead of HTML). For this we need to add an additional <execution>
section to our Maven AntRun Plugin configuration to generate an additional file "target/karma-coverage-lcov.conf.js" in which we also modify the Karma configuration to (only) output LCOV test coverage reporting:
org.apache.maven.plugins
maven-antrun-plugin
1.7
karma-coverage-lcov.conf.js
initialize
run
The generated "target/karma-coverage-lcov.conf.js" file differs from the original Karma configuration file in that:
- the "
basePath = '';
" line is altered to "basePath = '..';
" - each earlier commented-out "
// '...': 'coverage'
" line is stripped from its comment - the "
type : 'html',
" line is altered to "type : 'lcovonly',
" to let Karma generate LCOV coverage reporting (for consumption by SonarCube) instead of HTML coverage reporting.
In order to use the generated Karma configuration file you will need to modify the (earlier added) <configFile>
element in the configuration of the Maven Karma Plugin:
com.kelveden
maven-karma-plugin
${basedir}/target/karma-coverage-lcov.conf.js
Then we need to tell SonarCube where to find the LCOV unit test coverage report:
target/karma-coverage/PhantomJS 1.8 (Windows)/lcov.info
NOTE: later in this blog post we present a more future proof to specify the location of the LCOV file that doesn't depend on the browser version in its path (like in this case "1.8" of "PhantomJS" on "Windows"). Configuring <sonar.javascript.lcov.reportPath>
isn't enough to make SonarCube properly process the LCOV file. To successfully let SonarCube process the generated LCOV file we will add an additional <execution>
section to the configuration of the Maven AntRun plugin that:
- Copies the generated "lcov.info" file from the "target/karma-coverage/PhantomJS*/" directory to the "target" directory; this allows us to change the
<sonar.javascript.lcov.reportPath>
property totarget/lcov.info
NOTE: for correct LCOV processing, ensure the latest SonarCube JavaScript plugin (1.4) is installed.
org.apache.maven.plugins
maven-antrun-plugin
1.7
copy-lcov-file-to-target
test
run
${skipTests}
Sample application
To demonstrate the integration of the Karma test runner in Maven and SonarCube I forked AngularJS sample application called "ng-directive-testing" in GitHub. After running a "mvn clean install sonar:sonar" (either from command-line or through Jenkins) you will see the following dashboard in SonarCube:
References
- xseignard / karmaSonar (GitHub): sample application that uses SonarCube Runner to integrate a JavaScript module including test coverage. The sample application contains an useful UNIX shell script that fixes the file paths in the LCOV file.
- Analysing JS test results generated by Karma: contains a useful reply telling about the "karmaSonar" sample application on GitHub and its script that fixes the LCOV file.
- Javascript analysis from sonar runner and reusing reports: lengthy discussion thread about how to integrate using the Sonar Runner with some additional background info