appcenter-cli
Version:
Command line tool for Visual Studio App Center
145 lines (144 loc) • 6.95 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JUnitXmlUtil = void 0;
const pfs = require("../../../util/misc/promisfied-fs");
const xml_util_1 = require("./xml-util");
const fs = require("fs");
const xmldom_1 = require("@xmldom/xmldom");
class JUnitXmlUtil extends xml_util_1.XmlUtil {
mergeXmlResults(pathToArchive) {
return __awaiter(this, void 0, void 0, function* () {
const tempPath = yield pfs.mkTempDir("appcenter-junittestreports");
let mainXml = this.getEmptyXmlDocument();
const self = this;
return this.getMergeXmlResultsPromise(pathToArchive, tempPath, (fullPath, relativePath) => {
const xml = new xmldom_1.DOMParser(xml_util_1.XmlUtil.DOMParserConfig).parseFromString(fs.readFileSync(fullPath, "utf-8"), "text/xml");
let name = "unknown";
const matches = relativePath.match("^(.*)_TEST.*");
if (matches && matches.length > 1) {
name = matches[1].replace(/\./gi, "_");
}
self.appendToTestNameTransformation(xml, name);
self.removeIgnoredTransformation(xml);
mainXml = self.combine(mainXml, xml);
}, (resolve) => {
resolve(mainXml);
});
});
}
getArchiveName() {
return "junit_xml_zip.zip";
}
combine(xml1, xml2) {
const testSuitesElement = this.collectAllElements(xml1.documentElement, "testsuites")[0];
const xml1testSuites = this.collectChildren(xml1.documentElement, "testsuite");
const xml2TestSuites = this.collectChildren(xml2.documentElement, "testsuite");
xml2TestSuites.forEach((xml2TestSuite) => {
let needToAddNewTestSuite = true;
// Skip test suite without test cases
if (this.collectAllElements(xml2TestSuite, "testcase").length === 0) {
return;
}
// Combine all test cases in one test suite with the same class name
const testSuiteName = xml2TestSuite.attributes.getNamedItem("name").value;
xml1testSuites.every((xml1TestSuite) => {
const suiteNameAttr = xml1TestSuite.attributes.getNamedItem("name");
if (!suiteNameAttr || suiteNameAttr.value !== testSuiteName) {
// Take the next test suite
return true;
}
// Combine test suite attributes
this.combineAllAttributes(xml1TestSuite, xml2TestSuite);
const testCases = this.collectChildren(xml2TestSuite, "testcase");
testCases.forEach((testCase) => {
xml1TestSuite.appendChild(testCase);
});
needToAddNewTestSuite = false;
// Stop processing
return false;
});
if (needToAddNewTestSuite) {
testSuitesElement.appendChild(xml2TestSuite);
}
// Add test suite info to summary
this.combineAllAttributes(testSuitesElement, xml2TestSuite);
});
return xml1;
}
getEmptyXmlDocument() {
return new xmldom_1.DOMParser().parseFromString('<?xml version="1.0" encoding="UTF-8"?>\
<testsuites tests="0" failures="0" time="0" errors="0" skipped="0"></testsuites>', "text/xml");
}
appendToTestNameTransformation(xml, text) {
const testCases = this.collectAllElements(xml.documentElement, "testcase");
testCases.forEach((testCase) => {
const name = testCase.attributes.getNamedItem("name");
if (name) {
name.value = `${name.value}${text}`;
}
});
}
removeIgnoredTransformation(xml) {
const testCases = this.collectAllElements(xml.documentElement, "testcase");
testCases.forEach((testCase) => {
if (this.collectAllElements(testCase, "skipped").length === 0) {
return;
}
const parent = testCase.parentNode;
parent.removeChild(testCase);
const testCaseTime = Number(testCase.attributes.getNamedItem("time").value);
const timeAttr = parent.attributes.getNamedItem("time");
if (timeAttr && timeAttr.value) {
const time = Number(timeAttr.value) - testCaseTime;
timeAttr.value = String(Math.round(time * 1000) / 1000);
}
const skippedAttr = parent.attributes.getNamedItem("skipped");
if (skippedAttr && skippedAttr.value) {
skippedAttr.value = String(Number(skippedAttr.value) - 1);
}
const testsAttr = parent.attributes.getNamedItem("tests");
if (testsAttr && testsAttr.value) {
testsAttr.value = String(Number(testsAttr.value) - 1);
}
});
}
removeEmptySuitesTransformation(xml) {
const testSuites = this.collectAllElements(xml.documentElement, "testsuite");
testSuites.forEach((testSuite) => {
if (this.collectAllElements(testSuite, "testcase").length === 0) {
testSuite.parentElement.removeChild(testSuite);
xml.removeChild(testSuite);
}
});
}
combineAllAttributes(element1, element2) {
this.combineAttributes(element1, element2, "tests");
this.combineAttributes(element1, element2, "failures");
this.combineAttributes(element1, element2, "time");
this.combineAttributes(element1, element2, "errors");
this.combineAttributes(element1, element2, "skipped");
}
combineAttributes(element1, element2, attributeName) {
const attr1 = element1.attributes.getNamedItem(attributeName);
const attr2 = element2.attributes.getNamedItem(attributeName);
if (!attr1 || !attr1.value) {
return;
}
if (!attr2 || !attr2.value) {
return;
}
const attr1Value = Number(attr1.value);
const attr2Value = Number(attr2.value);
attr1.value = String(Math.round((attr1Value + attr2Value) * 1000) / 1000);
}
}
exports.JUnitXmlUtil = JUnitXmlUtil;