Npm Script Karma Start Single Vs Continuous
SonarQube (formerly Sonar) has become a standard code quality tool for Java applications. With recent releases, it has become easier to analyse code other than Java, even all within the same project. This means that you can now bring code quality analysis to your JavaScript code, too. In this blog post, we show you how.
Overview
Our project is built with Maven. To manage our frontend build process, we use gulp via the frontend-maven-plugin.
We configure the Karma test runner to output JUnit and LCOV reports. From gulp, we run Karma to execute our JavaScript tests, and then do a little post-processing on the LCOV report so that SonarQube can understand it.
We run SonarQube itself as part of our continuous integration process with Jenkins. Our Jenkins job configures SonarQube with which JavaScript files to include and exclude (we don't want to analyse third-party libraries, for example) and paths to the coverage reports.
Prerequisites
We make the following assumptions:
- You are already using Maven to build your project.
- You already have a SonarQube instance set up.
- You already have a continuous integration server such as Jenkins set up, with the appropriate SonarQube CI plugin installed.
- You are already testing your JavaScript code. The test framework you choose (Jasmine, Mocha, etc.) is up to you.
No particular folder structure is required, but you will probably be working with something similar to the below.
Ok? Then let's get started!
Node and npm
gulp and Karma are both based on Node.js, so we need to install Node to run them. We will use the package manager npm to install Node packages. (Note: after we are done, the frontend-maven-plugin will take care of this process for others working on our project, but to set everything up in the first place, it is easier if we install Node and npm ourselves.)
Head over to the Node.js downloads page and download the installer for your system. Run the installer to install Node together with npm.
Now we need to prepare our project to use it with npm. In essence, this just means creating a package.json
file. This file holds metadata related to the project, including its dependencies. Later, other developers can install all the required packages from this file with thenpm install
command. We can create a more detailed package.json
file through the interactive prompt npm init
, but as name and version are the only required fields, you can start by just creating the file based on the following contents:
{ "name": "frontend-project", "version": "0.0.1" }
Done? Great! Now we can install Karma. From the root of your frontend project, execute the following at the command line.
npm install --save-dev karma
You should also install packages and plugins for your test framework at this point. For Mocha with Chai and Sinon, for example:
npm install --save-dev mocha karma-mocha karma-sinon-chai
We also want to go ahead and install the required plugins for generating our unit test and coverage reports:
npm install --save-dev karma-coverage karma-junit-reporter
The --save-dev
flag tells npm to save the name and version of each downloaded package to the devDependencies
section of package.json
. Have a look at your package.json
file now. You should find the above packages listed there along with a semantic version number.
You'll also have noticed by this point that you have a new directory called node_modules
where all your Node packages live. You should exclude this directory from version control.
Karma
Now that Karma is installed, we need to configure it. It's a good idea to create two config files for Karma: one which is used in conjunction with Karma's watch mode for Test-Driven Development, and another which is based upon this but is modified slightly for use with Continuous Integration.
Karma offers an interactive option for generating configuration files:
./node_modules/karma/bin/karma init
Follow the prompts to configure Karma for TDD in your project. Make sure you get your test framework(s) in there.
When you are finished, Karma will tell you where it has saved the configuration file. Open karma.conf.js
and have a look at the configuration. It contains comments that explain each setting.
If the config file is not where you would like it, you can move it and tell Karma the new location later (just adjust the basePath
setting if you do so). We're going to move ours under src/test/js/
(changing the value of basePath
to '../../..'
).
If you haven't already done so, now is also a good time to make sure you add your Karma config files to the excludes
section of karma.conf.js
. As our CI config file will be called karma.conf.ci.js
, use the wildcard character to capture both files, e.g. src/test/js/karma.conf*.js
.
Now, create a new file in the same directory called karma.conf.ci.js
. Add the following contents.
var baseConfig = require('./karma.conf.js'); module.exports = function (config) { // Load base config baseConfig(config); // Override base config config.set({ singleRun: true, colors: false, autoWatch: false, reporters: ['progress', 'junit', 'coverage'], preprocessors: { 'src/main/webapp/resources/js/**/*.js': ['coverage'] }, browsers: ['PhantomJS'], junitReporter: { outputFile: 'reports/junit/TESTS-xunit.xml' }, coverageReporter: { type: 'lcov', dir: 'reports', subdir: 'coverage' } }); };
Here we are telling Karma to run just once, without autoWatch, and without colours in the output (which sometimes cause problems in continuous integration). Moving down, we specify that we want to use the JUnit and Coverage reporters alongside the standard Progress reporter. Further, we add preprocessing of our JavaScript source files for the Coverage reporter, and restrict the browsers used to the headless PhantomJS only. Finally, we specify that the JUnit test report should be named TESTS-xunit.xml
and output under reports/junit
while the LCOV report should go under reports/coverage
.
The name of the JUnit test report is important: this naming is required for SonarQube to recognise the report as being of type xUnit. For the reports, you can create whatever directory structure you want. It is a good idea to exclude the directories from version control, however.
At this point, you should be able to execute Karma from the command line to run your tests and generate your JUnit and LCOV reports. (This is definitely rather unwieldy, but fear not, we won't be running Karma this way for long!)
./node_modules/karma/bin/karma start src/test/js/karma.conf.ci.js
Reports there? Great!
There is just one problem: the paths generated in the LCOV report are wrong. They begin with the current directory (SF:.
) where they should instead name the project folder, e.g. SF:frontend-project
. We can fix this pretty easily with gulp though, which is what we'll do next.
gulp
gulp is a very powerful streaming build system based on Node.js. It can transform all aspects of your frontend build process, but here we will focus on using it to run our JavaScript tests and generate coverage reports with Karma.
Install gulp via:
npm install --save-dev gulp
To use gulp, you need to create a gulpfile.js
in the root of your project. Create the file and add the following code to it.
var gulp = require('gulp'); var karma = require('karma').server; gulp.task('test', function () { karma.start({ configFile: __dirname + '/src/test/js/karma.conf.ci.js' }); });
This describes a gulp task called test
, which will start the Karma server, run the tests according to the configuration in src/test/js/karma.conf.ci.js
, and stop. This is exactly what we did when we ran Karma from the command line in the previous section.
So, all going well, running ./node_modules/gulp/bin/gulp.js test
will run our tests and produce our reports in the expected directories. Try it out now!
Now we can move on and fix our path problem by creating another gulp task to perform some post-processing on the report with help from the gulp-replace plugin.
Install the plugin via
npm install --save-dev gulp-replace
and then update your gulpfile to define gulp-replace
and a task to do the post-processing, and then call the post-processing task as a callback after we are finished running Karma.
var gulp = require('gulp'); var karma = require('karma').server; var replace = require('gulp-replace'); var postprocessLCOV = function() { return gulp.src('reports/coverage/lcov.info') .pipe(replace('SF:.', 'SF:frontend-project')) .pipe(gulp.dest('reports/coverage')); }; gulp.task('test', function () { karma.start({ configFile: __dirname + '/src/test/js/karma.conf.ci.js' }, postprocessLCOV); });
Running ./node_modules/gulp/bin/gulp.js test
now should result in a LCOV report that SonarQube can understand.
Maven
Now, this is all very well for running our tests from the command line, but how do we integrate this into our Maven workflow? This is where the frontend-maven-plugin comes in.
Instead of trying to manage the frontend build process itself, the frontend-maven-plugin gets out of the way and lets a more suitable tool do the work. The plugin has been around for about a year, starting out with Karma and Grunt. Back in January I contributed the support for gulp.
To use this plugin, we first need to add it to our Maven project. Add the following code to the pom.xml
in your frontend project.
<plugins> <plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>0.0.16</version> ... </plugin> ... </plugins>
Now we can configure the plugin to automatically install Node and npm and then run our gulp test
command.
Install Node and npm
The following execution installs Node and npm locally on the target system. Here you can specify the versions of Node and npm to install. (See the README for more details.)
<execution> <id>install node and npm</id> <goals> <goal>install-node-and-npm</goal> </goals> <configuration> <nodeVersion>v0.10.32</nodeVersion> <npmVersion>1.4.28</npmVersion> </configuration> </execution>
Install dependencies
The following execution runs npm install
to install all the dependencies listed in your package.json
. (See the README for more options.)
<execution> <id>npm install</id> <goals> <goal>npm</goal> </goals> </execution>
Run gulp
The following execution runs thegulp test
command during the test
phase. (See the README for more options.)
<execution> <id>gulp build</id> <goals> <goal>gulp</goal> </goals> <phase>test</phase> <configuration> <arguments>test</arguments> </configuration> </execution>
Running mvn clean install
should now install Node and npm (if required), install all the required packages via npm install
and then run Karma and the report post-processing via gulp test
.
Note: since the frontend-maven-plugin installs Node and npm locally to a node
directory, you should also exclude this directory from version control.
SonarQube
Create a SonarQube project for your frontend project.
Jenkins
If not already existing, create a Maven-based Jenkins job for your frontend project, and set the main build step to do a mvn clean install
.
As a Post Step, choose "Invoke Standalone Sonar Analysis". Select your SonarQube instance for the "Sonar Installation", and add the following to the "Project properties" section (adjusting the values for your project and its corresponding SonarQube project). Further properties can be found in the SonarQube documentation.
Note: it is also possible to define the SonarQube properties within your pom.xml
.
# required metadata sonar.projectKey=frontend-project sonar.projectName=My-Frontend-Project sonar.projectVersion=1.0.0-SNAPSHOT # path to source directories (required) sonar.sources=frontend-project/src/main/webapp sonar.tests=frontend-project/src/test/js # excludes sonar.exclusions=frontend-project/src/main/webapp/js/lib/**/* # coverage reporting sonar.javascript.lcov.reportPath=frontend-project/reports/coverage/lcov.info sonar.surefire.reportsPath=frontend-project/reports/junit
This tells Jenkins everything it needs to know about the integration with SonarQube.
Note: by not setting a sonar.language
option, it defaults to "multi-language". This means that HTML, CSS and so on will also be analysed by SonarQube. If this is not desired, set the language option explicitly to JavaScript:
sonar.language=js
Run the Jenkins job, and voilà! You should now see the "Unit Tests Coverage" widget on your SonarQube project page.
Happy analysing and enjoy watching your coverage numbers climb!
wildeswalortromers1993.blogspot.com
Source: https://blog.akquinet.de/2014/11/25/js-test-coverage/
0 Response to "Npm Script Karma Start Single Vs Continuous"
Post a Comment