Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

karma-sonarqube-execution-reporter

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

karma-sonarqube-execution-reporter - npm Package Compare versions

Comparing version 0.0.2 to 0.1.0

16

CHANGELOG.md

@@ -13,1 +13,17 @@ # Changelog

* Removed 27 vulnerabilities (18 low, 8 high, 1 critical)
## 0.1.0 (2018-11-22)
### Features
* `File path` is path to spec file in default
* Parsing key-words in spec files:
* `describe()`
* `describe ()`
* `describe.only()`
* `describe.only ()`
### Code changes
* Extracted nested functions.
* Added new unit-tests for different `describe()` key-word combinantions.

152

index.js

@@ -6,34 +6,30 @@ const path = require('path');

const SonarQubeUnitReporter = function (baseReporterDecorator, config, logger, helper, formatError) {
const SonarQubeExecutionReporter = function(baseReporterDecorator, config, logger, helper, formatError) {
const log = logger.create('reporter.sonarqubeUnit');
const reporterConfig = config.sonarQubeUnitReporter || {};
const sonarQubeVersion = reporterConfig.sonarQubeVersion || 'LATEST';
const pkgName = reporterConfig.suite || '';
const outputFile = reporterConfig.outputFile;
let outputDir = reporterConfig.outputDir;
let useBrowserName = reporterConfig.useBrowserName;
// Get configuration
const repConf = config.sonarQubeExecutionReporter || {};
const sonarQubeVersion = repConf.sonarQubeVersion || 'LATEST';
const pkgName = repConf.suite || '';
const outputFile = repConf.outputFile;
const outputDir = helper.normalizeWinPath(path.resolve(config.basePath, repConf.outputDir || '.')) + path.sep;
const useBrowserName = (!repConf.useBrowserName) ? false : true;
let filenameFormatter = reporterConfig.filenameFormatter || null;
const testnameFormatter = reporterConfig.testnameFormatter || null;
const testPath = repConf.testPath || './';
const testPaths = repConf.testPaths || [testPath];
const testFilePattern = repConf.testFilePattern || '.spec.(ts|js)';
const filesForDescriptions = fileUtil.getFilesForDescriptions(testPaths, testFilePattern);
// Init data
let suites;
let pendingFileWritings = 0;
let fileWritingFinished = function () {};
let fileWritingFinished = () => null;
const allMessages = [];
if (outputDir == null) {
outputDir = '.';
}
outputDir = helper.normalizeWinPath(path.resolve(config.basePath, outputDir)) + path.sep;
if (typeof useBrowserName === 'undefined') {
useBrowserName = true;
}
baseReporterDecorator(this);
this.adapters = [
function (msg) {
function(msg) {
allMessages.push(msg);

@@ -43,3 +39,9 @@ }

const initliazeXmlForBrowser = function (browser) {
// Helpers functions
const transformDescribeToPath = function(nextPath, _result) {
return filesForDescriptions[nextPath];
};
const initliazeXmlForBrowser = function(browser) {
let tagName;

@@ -61,3 +63,3 @@ switch (sonarQubeVersion) {

const writeXmlForBrowser = function (browser) {
const writeXmlForBrowser = function(browser) {
const safeBrowserName = browser.name.replace(/ /g, '_');

@@ -95,24 +97,30 @@ let newOutputFile;

const getClassName = function (browser, result) {
const getClassName = function(browser, result) {
const browserName = browser.name.replace(/ /g, '_').replace(/\./g, '_') + '.';
return (useBrowserName ? browserName : '') + (pkgName ? pkgName + '/' : '') + result.suite[0];
};
this.onRunStart = function (browsers) {
const getTestName = function(result) {
let desc = result.description;
for (let i = result.suite.length - 1; i >= 0; i--) {
desc = result.suite[i] + ' ' + desc;
}
return desc;
};
// Karma methods override
const karmaOnRunStart = function() {
suites = Object.create(null);
// TODO(vojta): remove once we don't care about Karma 0.10
browsers.forEach(initliazeXmlForBrowser);
};
this.onBrowserStart = function (browser) {
const karmaOnBrowserStart = function(browser) {
initliazeXmlForBrowser(browser);
};
this.onBrowserComplete = function (browser) {
const karmaOnBrowserComplete = function(browser) {
const suite = suites[browser.id];
const result = browser.lastResult;
if (!suite || !result) {
return; // don't die if browser didn't start
return;
}

@@ -123,3 +131,3 @@

this.onRunComplete = function () {
const karmaOnRunComplete = function() {
suites = null;

@@ -129,18 +137,11 @@ allMessages.length = 0;

this.specSuccess = this.specSkipped = this.specFailure = function (browser, result) {
const preMapped = getClassName(browser, result).replace(/\\/g, '/');
let nextPath = preMapped;
if (filenameFormatter !== null) {
nextPath = filenameFormatter(nextPath, result);
if (preMapped !== nextPath) {
log.debug('Transformed File name "' + preMapped + '" -> "' + nextPath + '"');
} else {
log.debug('Name not transformed for File "' + preMapped + '"');
}
}
const karmaSpecDone = function(browser, result) {
const specDescribe = getClassName(browser, result).replace(/\\/g, '/');
const nextPath = transformDescribeToPath(specDescribe, result);
log.debug('Transformed File name "' + specDescribe + '" -> "' + nextPath + '"');
let lastFilePath;
const fileNodes = suites[browser.id];
let lastFilePath;
const numberOfFileNodes = fileNodes.children.length;
const numberOfFileNodes = fileNodes.children.length;
if (numberOfFileNodes > 0) {

@@ -158,39 +159,19 @@ lastFilePath = fileNodes.children[numberOfFileNodes - 1].attributes.path.value;

}
lastFilePath = nextPath;
const appendToThisNode = suites[browser.id].children[suites[browser.id].children.length - 1];
const testname = getTestName(result);
const testCase = appendToThisNode.ele('testCase', { name: testname, duration: (result.time || 1) });
function getDescription (result) {
let desc = result.description;
for (let i = result.suite.length - 1; i >= 0; i--) {
desc = result.suite[i] + ' ' + desc;
}
return desc;
}
const testname = getDescription(result);
let testnameFormatted = testname;
if (testnameFormatter !== null) {
testnameFormatted = testnameFormatter(testname, result);
if (testnameFormatted && testnameFormatted !== testname) {
log.debug('Transformed test name "' + testname + '" -> "' + testnameFormatted + '"');
} else {
testnameFormatted = testname;
log.debug('Name not transformed for test "' + testnameFormatted + '"');
}
}
const testCase = appendToThisNode.ele('testCase', {name: testnameFormatted, duration: (result.time || 1)});
if (result.skipped) {
testCase.ele('skipped', {message: 'Skipped'});
testCase.ele('skipped', { message: 'Skipped' });
}
if (!result.success) {
testCase.ele('failure', {message: 'Error'}, formatError(result.log.join('\n\n')));
testCase.ele('failure', { message: 'Error' }, formatError(result.log.join('\n\n')));
}
};
// wait for writing all the xml files, before exiting
this.onExit = function (done) {
const karmaOnExit = function(done) {
if (pendingFileWritings) {

@@ -203,23 +184,18 @@ fileWritingFinished = done;

// look for jasmine test files in the specified path
const overrideTestDescription = reporterConfig.overrideTestDescription || false;
const testPath = reporterConfig.testPath || './';
const testPaths = reporterConfig.testPaths || [testPath];
const testFilePattern = reporterConfig.testFilePattern || '(.spec.ts|.spec.js)';
const filesForDescriptions = fileUtil.getFilesForDescriptions(testPaths, testFilePattern);
function defaultFilenameFormatter (nextPath, _result) {
return filesForDescriptions[nextPath];
}
if (overrideTestDescription) {
filenameFormatter = defaultFilenameFormatter;
}
// Bind karma functions
this.onRunStart = karmaOnRunStart;
this.onBrowserStart = karmaOnBrowserStart;
this.onBrowserComplete = karmaOnBrowserComplete;
this.onRunComplete = karmaOnRunComplete;
this.specSuccess = karmaSpecDone;
this.specSkipped = karmaSpecDone;
this.specFailure = karmaSpecDone;
this.onExit = karmaOnExit;
};
SonarQubeUnitReporter.$inject = ['baseReporterDecorator', 'config', 'logger', 'helper', 'formatError'];
SonarQubeExecutionReporter.$inject = ['baseReporterDecorator', 'config', 'logger', 'helper', 'formatError'];
// PUBLISH DI MODULE
module.exports = {
'reporter:sonarqubeUnit': ['type', SonarQubeUnitReporter]
'reporter:sonarqubeUnit': ['type', SonarQubeExecutionReporter]
};
{
"name": "karma-sonarqube-execution-reporter",
"version": "0.0.2",
"version": "0.1.0",
"description": "A Karma plugin. Report execution results in sonar-unit-tests xml format.",

@@ -32,6 +32,5 @@ "license": "MIT",

"peerDependencies": {
"karma": ">=0.9"
"karma": ">=2.0"
},
"dependencies": {
"karma": "^3.1.1",
"xmlbuilder": "^10.1.1"

@@ -38,0 +37,0 @@ },

@@ -1,2 +0,2 @@

### karma-sonarqube-execution-reporter
# karma-sonarqube-execution-reporter

@@ -6,3 +6,3 @@ [![NpmLicense](https://img.shields.io/npm/l/karma-sonarqube-execution-reporter.svg)](https://opensource.org/licenses/MIT) [![npm](https://img.shields.io/npm/dt/karma-sonarqube-execution-reporter.svg)](https://npmjs.com/package/karma-sonarqube-execution-reporter) [![NpmVersion](https://img.shields.io/npm/v/karma-sonarqube-execution-reporter.svg)](https://npmjs.com/package/karma-sonarqube-execution-reporter)

##### Motivation
## Motivation

@@ -13,123 +13,47 @@ This solution is based on https://github.com/tornaia/karma-sonarqube-unit-reporter

##### How to get
## How to get
Available on npmjs.org
Just run `npm install --save-dev karma-sonarqube-unit-reporter` in your project directory.
Package is also available on npmjs.org
https://www.npmjs.com/package/https://github.com/lisrec/karma-sonarqube-execution-reporter
##### How to use
## How to use
Sample karma.conf.ci.js
```xml
'use strict';
1. Import plugin to karma.conf.js in `plugins` section:
var path = require('path');
var conf = require('./gulp/conf');
var _ = require('lodash');
var wiredep = require('wiredep');
var pathSrcHtml = [
path.join(conf.paths.src, '/**/*.html'),
path.join(conf.paths.src_test, '/**/*.html')
];
function listFiles() {
var wiredepOptions = _.extend({}, conf.wiredep, {
dependencies: true,
devDependencies: true
});
return wiredep(wiredepOptions).js
.concat([
path.join(conf.paths.src, '/app/**/*.module.js'),
path.join(conf.paths.src, '/app/**/*.js'),
path.join(conf.paths.src, '/**/*.spec.js'),
path.join(conf.paths.src, '/**/*.mock.js'),
path.join(conf.paths.src_test, '/app/**/*.module.js'),
path.join(conf.paths.src_test, '/app/**/*.js'),
path.join(conf.paths.src_test, '/**/*.spec.js'),
path.join(conf.paths.src_test, '/**/*.mock.js')
])
.concat(pathSrcHtml);
```js
module.exports = function (config) {
config.set({
plugins: [
require('karma-sonarqube-execution-reporter')
]
})
}
```
module.exports = function(config) {
2. Add basic configuration to karma.conf.js in `config.set` section:
var configuration = {
files: listFiles(),
singleRun: true,
colors: false,
autoWatch: false,
ngHtml2JsPreprocessor: {
stripPrefix: conf.paths.src + '/',
moduleName: 'TODO_PUT_HERE_YOUR_MODULE_NAME'
},
logLevel: 'WARN',
frameworks: ['jasmine', 'angular-filesort'],
angularFilesort: {
whitelist: [path.join(conf.paths.src, '/**/!(*.html|*.spec|*.mock).js'), path.join(conf.paths.src_test, '/**/!(*.html|*.spec|*.mock).js')]
},
browsers: ['PhantomJS'],
sonarQubeUnitReporter: {
```js
module.exports = function (config) {
config.set({
sonarQubeExecutionReporter: {
sonarQubeVersion: 'LATEST',
outputFile: 'reports/ut_report.xml',
useBrowserName: false
testPaths: ['./src/app'],
testFilePattern: '.spec.ts',
outputDir: './coverage',
outputFile: 'ut_report.xml'
},
plugins: [
'karma-phantomjs-launcher',
'karma-angular-filesort',
'karma-coverage',
'karma-jasmine',
'karma-ng-html2js-preprocessor',
'karma-sonarqube-unit-reporter'
],
coverageReporter: {
type : 'lcov',
dir : 'reports',
subdir : 'coverage'
},
reporters: ['progress', 'sonarqubeUnit', 'coverage'],
preprocessors: {
'src/**/*.js': ['coverage'],
'test/**/*.js': ['coverage']
}
};
config.set(configuration);
};
})
}
```
By default, the description of the jasmine tests used as the path attribute in the generated xml. If this is not the case with your tests, you can use the following options to automagically find the right path values. It is the recommended way to use this plugin but to be backward compatible it is not enabled by default.
```
sonarQubeUnitReporter: {
sonarQubeVersion: 'LATEST',
outputFile: 'reports/ut_report.xml',
overrideTestDescription: true,
testPaths: ['./test', './moreTests'],
testFilePattern: '.spec.js',
useBrowserName: false
},
```
##### Prerequisites for development
* NodeJS 8.0.0 https://nodejs.org/download/release/v8.0.0/
##### Build
* npm install
* npm build
## Avaible options - descriptions [TODO]
### sonarQubeVersion
### suite
### outputFile
### outputDir
### useBrowserName
### testPath
### testPaths
### testFilePattern
const path = require('path');
const fs = require('fs');
module.exports = {
getFilesForDescriptions: getFilesForDescriptions
};
function getFilesForDescriptions (startPaths, filter) {
const ret = {};
const findDescribeInText = function(textToSearch) {
const keyWords = [
'describe(',
'describe (',
'describe.only(',
'describe.only (',
];
startPaths.forEach((startPathItem) => {
const files = findFilesInDir(startPathItem, filter);
files.forEach(findDescriptionInFile);
});
for(const idx in keyWords) {
function findDescriptionInFile (item, _index) {
try {
let fileText = fs.readFileSync(item, 'utf8');
let position = 0;
while (position !== -1) {
let describe;
position = fileText.indexOf('describe(');
if (position !== -1) {
const delimeter = fileText[position + 9];
const descriptionEnd = fileText.indexOf(delimeter, position + 10) + 1;
describe = fileText.substring(position + 10, descriptionEnd - 1);
describe = describe.replace(/\\\\/g, '/');
item = item.replace(/\\\\/g, '/').replace(/\\/g, '/');
ret[describe] = item;
position = 0;
fileText = fileText.substring(descriptionEnd);
}
}
} catch (e) {
// eslint-disable-next-line no-console
console.error('Error:', e.stack);
const pos = textToSearch.indexOf(keyWords[idx]);
if (pos !== -1) {
return {
position: pos,
length: keyWords[idx].length
};
}
}
return ret;
}
return {
position: -1,
length: 0
};
};
function findFilesInDir (startPath, filter) {
let results = [];
const findFilesInDir = function(startPath, filter) {

@@ -52,15 +39,64 @@ if (!fs.existsSync(startPath)) {

let results = [];
const files = fs.readdirSync(startPath);
const filterRegex = new RegExp(filter);
for (let i = 0; i < files.length; i++) {
const filename = path.join(startPath, files[i]);
const stat = fs.lstatSync(filename);
if (stat.isDirectory()) {
if (filename !== 'node_modules') {
results = results.concat(findFilesInDir(filename, filter));
}
} else if (filename.endsWith(filter)) {
if (stat.isDirectory() && filename !== 'node_modules') {
results = results.concat(findFilesInDir(filename, filter));
} else if (filterRegex.test(filename)) {
results.push(filename);
}
}
return results;
}
};
const findDescriptionInFile = (respArray) => (item, _index) => {
try {
let fileText = fs.readFileSync(item, 'utf8');
let position = 0;
while (position !== -1) {
let describe;
const findDescribe = findDescribeInText(fileText);
position = findDescribe.position;
if (position !== -1) {
const startDescribePosition = position + findDescribe.length;
const delimeter = fileText[startDescribePosition];
const descriptionEnd = fileText.indexOf(delimeter, startDescribePosition + 1) + 1;
describe = fileText.substring(startDescribePosition + 1, descriptionEnd - 1);
describe = describe.replace(/\\\\/g, '/');
item = item.replace(/\\\\/g, '/').replace(/\\/g, '/');
fileText = fileText.substring(descriptionEnd);
respArray[describe] = item;
position = 0;
}
}
} catch (e) {
// eslint-disable-next-line no-console
console.error('Error:', e.stack);
}
};
const getFilesForDescriptions = function(startPaths, filter) {
const ret = {};
startPaths.forEach((startPathItem) => {
const files = findFilesInDir(startPathItem, filter);
files.forEach(findDescriptionInFile(ret));
});
return ret;
};
module.exports = { getFilesForDescriptions };

@@ -58,2 +58,24 @@ /* eslint-disable no-undef */

});
it('spaces in describe key-word', () => {
const filesForDescriptions = fileUtil.getFilesForDescriptions(['test/resources/spaces_multiple_files_multiple_descriptions'], '.spec.js');
const expectedPath1 = 'test/resources/spaces_multiple_files_multiple_descriptions/first_test.spec.js';
const expectedPath2 = 'test/resources/spaces_multiple_files_multiple_descriptions/second_test.spec.js';
const expected = {
'first test first description': expectedPath1,
'first test second description': expectedPath1,
'first test third description': expectedPath1,
'first test fourth description': expectedPath1,
'second test first description': expectedPath2,
'second test second description': expectedPath2,
'second test third description': expectedPath2,
'second test fourth description': expectedPath2
};
expect(filesForDescriptions).toEqual(expected);
});
});
/* eslint-disable no-undef */
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc