newman-reporter-junitfull
Version:
A Newman JUnit Reporter providing full reports (without aggregation of results)
174 lines (139 loc) • 5.79 kB
JavaScript
var _ = require('lodash'),
xml = require('xmlbuilder'),
moment = require('moment'),
JunitFullReporter;
// JUnit Reporter based on XSD specified by Publish Test Results task for Azure Pipeline / TFS 2018 / TFS 2017 and TFS 2015
// Source: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/test/publish-test-results?view=vsts&tabs=yaml
// XSD: https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd
const SEPARATOR = ' / ';
/**
* Resolves the parent qualified name for the provided item
*
* @param {PostmanItem|PostmanItemGroup} item The item for which to resolve the full name
* @param {?String} [separator=SEP] The separator symbol to join path name entries with
* @returns {String} The full name of the provided item, including prepended parent item names
* @private
*/
function getParentName (item, separator) {
if (_.isEmpty(item) || !_.isFunction(item.parent) || !_.isFunction(item.forEachParent)) {
return;
}
var chain = [];
item.forEachParent(function (parent) {
chain.unshift(parent.name || parent.id);
});
return chain.join(_.isString(separator) ? separator : SEPARATOR);
}
/**
* A function that creates raw XML to be written to Newman JUnit reports.
*
* @param {Object} newman - The collection run object, with a event handler setter, used to enable event wise reporting.
* @param {Object} reporterOptions - A set of JUnit reporter run options.
* @param {String=} reporterOptions.export - Optional custom path to create the XML report at.
* @returns {*}
*/
JunitFullReporter = function (newman, reporterOptions, options) {
newman.on('beforeDone', function () {
var executions = _.get(newman, 'summary.run.executions'),
globalValues = _.get(newman, 'summary.globals.values.members', []),
environmentValues = _.get(newman, 'summary.environment.values.members', []);
var date = moment(new Date()).local().format('YYYY-MM-DDTHH:mm:ss.SSS');
if (!executions) {
return;
}
global = xml.create('testsuites', { version: '1.0', encoding: 'UTF-8' });
// Process executions (testsuites)
_.forEach(executions, function (execution) {
var testsuite = global.ele('testsuite');
var failures = 0, errors = 0;
var propertyValues = _.merge(environmentValues, globalValues);
testsuite.att('id', (execution.cursor.iteration * execution.cursor.length) + execution.cursor.position);
// Hostname
var protocol = _.get(execution, 'request.url.protocol', 'https') + '://';
var hostName = _.get(execution, 'request.url.host', 'localhost');
testsuite.att('hostname', protocol + hostName.join('.'));
// Package
testsuite.att('package', getParentName(execution.item));
// Name
testsuite.att('name', execution.item.name);
// Tests
if (execution.assertions) {
testsuite.att('tests', execution.assertions.length);
}
else {
testsuite.att('tests', 0);
}
// Failures
testsuite.att('failures', failures);
// Errors
testsuite.att('errors', errors);
// Timestamp
testsuite.att('timestamp', date);
// Time
testsuite.att('time', (_.get(execution, 'response.responseTime') / 1000 || 0).toFixed(3));
// Timestamp (add time)
date = moment(date).add(_.get(execution, 'response.responseTime'), 'ms').local().format('YYYY-MM-DDTHH:mm:ss.SSS');
// Process properties
if (propertyValues && propertyValues.length) {
properties = testsuite.ele('properties');
_.forEach(propertyValues, function (propertyItem) {
var property = properties.ele('property');
property.att('name', propertyItem.key);
property.att('value', propertyItem.value);
});
}
// Process assertions (testcases)
_.forEach(['prerequestScript', 'assertions', 'testScript'], function (property) {
_.forEach(execution[property], function (testExecution) {
var testcase = testsuite.ele('testcase');
// Classname
var className = [];
className.push(_.get(testcase.up(), 'attributes.package.value'));
className.push(_.get(testcase.up(), 'attributes.name.value'));
testcase.att('classname', className.join(SEPARATOR));
if (property === 'assertions') {
// Name
testcase.att('name', testExecution.assertion);
// Time (testsuite time divided by number of assertions)
testcase.att('time', (_.get(testcase.up(), 'attributes.time.value') / execution.assertions.length || 0).toFixed(3));
} else {
// Name
testcase.att('name', property === 'testScript' ? 'Tests' : 'Pre-request Script');
}
// Errors / Failures
var errorItem = testExecution.error;
if (errorItem) {
var result;
if (property !== 'assertions') {
// Error
++errors;
result = testcase.ele('error');
if (errorItem.stacktrace) {
result.dat(errorItem.stacktrace);
}
} else {
// Failure
++failures;
result = testcase.ele('failure');
result.dat(errorItem.stack);
}
result.att('type', errorItem.name);
result.att('message', errorItem.message);
}
});
});
});
newman.exports.push({
name: 'junit-reporter-full',
default: 'newman-run-report-full.xml',
path: reporterOptions.export,
content: global.end({
pretty: true,
indent: ' ',
newline: '\n',
allowEmpty: false
})
});
});
};
module.exports = JunitFullReporter;