Tuesday, July 2, 2019

Angular app: Add unit test coverage on Sonar

We will consider here that you already have an angular application running with some unit tests based on karma / jasmine.

To see the coverage, we will need a few things :
npm install karma-coverage-istanbul-reporter --save-dev
npm install karma-sonarqube-reporter --save-dev

We will also need to find a launcher (Chrome, PhantomJs ...). We chose the second one in order not to rely on the plateform.

First things first, we will update our karma.conf.js

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('@angular-devkit/build-angular/plugins/karma'),
      require('karma-jasmine'),
      require('karma-phantomjs-launcher'),
      require('karma-coverage-istanbul-reporter'),
      require('karma-sonarqube-reporter')
    ],
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, '../coverage'),
      reports: ['lcovonly'],
      fixWebpackSourcePaths: true
    },
    sonarqubeReporter : {
      basePath: 'src/app',
      filePattern: '**/*spec.ts',
      encoding: 'utf-8',
      outputFolder: 'reports',
      reportName: () => {
        return 'unitTestsReport.xml';
      }
    },
    reporters: ['progress', 'sonarqube'],
    port: 9876,
    logLevel: config.LOG_INFO,
    browsers: ['PhantomJS'],
    singleRun: true
  });
};
The karma coverage istanbul reporter will generate the lcov.info file which contains code coverage information in an LCOV formatted file.

The karma sonarqube Reporter will generate unitTestsReport.xml which contains unit tests information (number, success, fail, elapsed time ...).

(If you want to generate html report immediatly in your workspace, you can use Karma Html Reporter).

You can now launch tests using angular-cli

$ ng test --code-coverage
02 07 2019 13:45:10.192:INFO [karma-server]: Karma v3.1.3 server started at http://0.0.0.0:9876/
02 07 2019 13:45:10.195:INFO [launcher]: Launching browsers PhantomJS with concurrency unlimited
02 07 2019 13:45:10.201:INFO [launcher]: Starting browser PhantomJS
02 07 2019 13:45:18.845:INFO [PhantomJS 2.1.1 (Windows 7.0.0)]: Connected on socket DAOh28181XJnSgGxAAAA with id 31414509
TOTAL: 21 SUCCESS

If you are using typescript, you will probably need to set the property "sourceMap" to true in the "test" section of your angular.json file. Without it, when compiling from TypeScript to JavaScript, you will get lcov error because the report contains the line numbers for the JavaScript code. (See here).

You might also encounter some problems with PhantomJs. I had those weird errors although it was working fine with Chrome.

phantomjs Attempting to configure 'style' with descriptor '{"enumerable":true,"configurable":true}'
evaluating 'b.style._clear(a.propertyName(c)) phantomjs

I had to edit the polyfill.js (use to make your application compatible on multiple browsers).
Switching the import of web-animations-js and zone.js was the solution.

It is now time to tell sonar how to handle these informations. Add a file named sonar-project.properties to your workspace.

sonar.projectKey=project-key 
sonar.projectName=project-name 
sonar.sources=src 
sonar.tests=src/app 
sonar.exclusions=**/node_modules/**,**/*.spec.ts,**/coverage/** 
sonar.coverage.exclusions=src/*.ts, src/*.js, **/*Dto.ts,**/*Enum.ts,**/*constants.ts, **/*module.ts, **/*config.ts 
sonar.test.inclusions=**/*.spec.ts 
sonar.typescript.lcov.reportPaths=coverage/lcov.info 
sonar.testExecutionReportPaths=reports/unitTestsReport.xml


To watch the result on the sonar server, run it in command line (path : sonarQubePath/bin/yourOs). It will be accessible on http:localhost:9000

Add the SonarQubeScanner to your path and then run the command sonar-scanner in the base directory of your project. It will find the sonar-project.properties and send information to the sonarQube server.

Now you can find your coverage information !



If you want to run test before pushing, you can use Husky and add test on pre-push.

  "husky": {
    "hooks": {
      "pre-push": "ng test"
    }
  }

1 comment: