@tztz/karma-sonarqube-unit-reporter
Version:
A Karma plugin. Report results in sonar-unit-tests xml format.
232 lines (192 loc) • 6.87 kB
JavaScript
var path = require('path')
var fs = require('fs')
var builder = require('xmlbuilder')
var fileUtil = require('./src/file-util.js')
var SonarQubeUnitReporter = function(baseReporterDecorator, config, logger, helper, formatError) {
var log = logger.create('reporter.sonarqubeUnit')
var reporterConfig = config.sonarQubeUnitReporter || {}
var sonarQubeVersion = reporterConfig.sonarQubeVersion || 'LATEST'
var pkgName = reporterConfig.suite || ''
var outputDir = reporterConfig.outputDir
var outputFile = reporterConfig.outputFile
var useBrowserName = reporterConfig.useBrowserName
var filenameFormatter = reporterConfig.filenameFormatter || null
var testnameFormatter = reporterConfig.testnameFormatter || null
var suites
var pendingFileWritings = 0
var fileWritingFinished = function() {}
var 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) {
allMessages.push(msg)
},
]
var initliazeXmlForBrowser = function(browser) {
var tagName
switch (sonarQubeVersion) {
case '5.x':
tagName = 'unitTest'
break
default:
tagName = 'testExecutions'
}
var parentTag = (suites[browser.id] = builder.create(
tagName,
{ version: '1.0', encoding: 'UTF-8', standalone: true },
{ pubID: null, sysID: null },
{
allowSurrogateChars: false,
skipNullAttributes: false,
headless: true,
ignoreDecorators: false,
separateArrayItems: false,
noDoubleEncoding: false,
stringify: {},
}
))
parentTag.att('version', '1')
}
var writeXmlForBrowser = function(browser) {
var safeBrowserName = browser.name.replace(/ /g, '_')
var newOutputFile
if (outputFile != null) {
var dir = useBrowserName ? path.join(outputDir, safeBrowserName) : outputDir
newOutputFile = path.join(dir, outputFile)
} else if (useBrowserName) {
newOutputFile = path.join(outputDir, 'ut_report-' + safeBrowserName + '.xml')
} else {
newOutputFile = path.join(outputDir, 'ut_report.xml')
}
var xmlToOutput = suites[browser.id]
if (!xmlToOutput) {
return // don't die if browser didn't start
}
pendingFileWritings++
helper.mkdirIfNotExists(path.dirname(newOutputFile), function() {
fs.writeFile(newOutputFile, xmlToOutput.end({ pretty: true }), function(err) {
if (err) {
log.warn('Cannot write JUnit xml\n\t' + err.message)
} else {
log.debug('JUnit results written to "%s".', newOutputFile)
}
if (!--pendingFileWritings) {
fileWritingFinished()
}
})
})
}
var getClassName = function(browser, result) {
var browserName = browser.name.replace(/ /g, '_').replace(/\./g, '_') + '.'
return (useBrowserName ? browserName : '') + (pkgName ? pkgName + '/' : '') + result.suite[0]
}
this.onRunStart = function(browsers) {
suites = Object.create(null)
// TODO(vojta): remove once we don't care about Karma 0.10
browsers.forEach(initliazeXmlForBrowser)
}
this.onBrowserStart = function(browser) {
initliazeXmlForBrowser(browser)
}
this.onBrowserComplete = function(browser) {
var suite = suites[browser.id]
var result = browser.lastResult
if (!suite || !result) {
return // don't die if browser didn't start
}
writeXmlForBrowser(browser)
}
this.onRunComplete = function() {
suites = null
allMessages.length = 0
}
this.specSuccess = this.specSkipped = this.specFailure = function(browser, result) {
var preMapped = getClassName(browser, result).replace(/\\/g, '/')
var 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 + '"')
}
}
var fileNodes = suites[browser.id]
var lastFilePath
var numberOfFileNodes = fileNodes.children.length
if (numberOfFileNodes > 0) {
lastFilePath = fileNodes.children[numberOfFileNodes - 1].attributes.getNamedItem('path').value
if (lastFilePath !== nextPath) {
suites[browser.id].ele('file', {
path: nextPath,
})
}
} else {
suites[browser.id].ele('file', {
path: nextPath,
})
}
lastFilePath = nextPath
var appendToThisNode = suites[browser.id].children[suites[browser.id].children.length - 1]
function getDescription(result) {
var desc = result.description
for (var i = result.suite.length - 1; i >= 0; i--) {
desc = result.suite[i] + ' ' + desc
}
return desc
}
var testname = getDescription(result)
var 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 + '"')
}
}
var testCase = appendToThisNode.ele('testCase', {
name: testnameFormatted,
duration: result.time || 1,
})
if (result.skipped) {
testCase.ele('skipped', { message: 'Skipped' })
}
if (!result.success) {
testCase.ele('failure', { message: 'Error' }, formatError(result.log.join('\n\n')))
}
}
// wait for writing all the xml files, before exiting
this.onExit = function(done) {
if (pendingFileWritings) {
fileWritingFinished = done
} else {
done()
}
}
// look for jasmine test files in the specified path
var overrideTestDescription = reporterConfig.overrideTestDescription || false
var testPath = reporterConfig.testPath || './'
var testPaths = reporterConfig.testPaths || [testPath]
var testFilePattern = reporterConfig.testFilePattern || '(.spec.ts|.spec.js)'
var filesForDescriptions = fileUtil.getFilesForDescriptions(testPaths, testFilePattern)
function defaultFilenameFormatter(nextPath, result) {
return filesForDescriptions[nextPath]
}
if (overrideTestDescription) {
filenameFormatter = defaultFilenameFormatter
}
}
SonarQubeUnitReporter.$inject = ['baseReporterDecorator', 'config', 'logger', 'helper', 'formatError']
// PUBLISH DI MODULE
module.exports = {
'reporter:sonarqubeUnit': ['type', SonarQubeUnitReporter],
}