appcenter-cli
Version:
Command line tool for Visual Studio App Center
176 lines (146 loc) • 6.22 kB
text/typescript
import * as pfs from "../../../util/misc/promisfied-fs";
import { XmlUtil } from "./xml-util";
import * as fs from "fs";
import * as unzipper from "unzipper";
import { DOMParser } from "xmldom";
export class NUnitXmlUtil extends XmlUtil {
async mergeXmlResults(pathToArchive: string): Promise<Document> {
const tempPath: string = await pfs.mkTempDir("appcenter-uitestreports");
let mainXml: Document = null;
const self: NUnitXmlUtil = this;
return this.getMergeXmlResultsPromise(pathToArchive, tempPath,
(fullPath: string, relativePath: string) => {
const xml: Document = new DOMParser(XmlUtil.DOMParserConfig).parseFromString(fs.readFileSync(fullPath, "utf-8"), "text/xml");
let name: string = "unknown";
const matches: RegExpMatchArray = relativePath.match("^(.*)[_-]nunit[_-]report");
if (matches && matches.length > 1) {
name = matches[1].replace(/\./gi, "_");
}
self.appendToTestNameTransformation(xml, `_${name}`);
self.removeIgnoredTransformation(xml);
self.removeEmptySuitesTransformation(xml);
if (mainXml) {
if (this.isNUnit3(xml)) {
mainXml = self.combineNUnit3(mainXml, xml);
} else {
mainXml = self.combineNUnit2(mainXml, xml);
}
} else {
mainXml = xml;
}
},
(resolve: Function) => {
resolve(mainXml);
}
);
}
public getArchiveName(): string {
return "nunit_xml_zip.zip";
}
combineNUnit2(xml1: Document, xml2: Document): Document {
this.combineResultsAttribute(xml1, xml2, "total");
this.combineResultsAttribute(xml1, xml2, "errors");
this.combineResultsAttribute(xml1, xml2, "failures");
this.combineResultsAttribute(xml1, xml2, "not-run");
this.combineResultsAttribute(xml1, xml2, "inconclusive");
this.combineResultsAttribute(xml1, xml2, "ignored");
this.combineResultsAttribute(xml1, xml2, "skipped");
this.combineResultsAttribute(xml1, xml2, "invalid");
const testSuitesParent: Element = this.collectAllElements(xml1.documentElement, "test-results")[0];
const testSuites: Element[] = this.collectChildren(xml2.documentElement, "test-suite");
testSuites.forEach((child: Element) => {
testSuitesParent.appendChild(child);
});
return xml1;
}
combineNUnit3(xml1: Document, xml2: Document): Document {
this.combineResultsAttribute(xml1, xml2, "testcasecount");
this.combineResultsAttribute(xml1, xml2, "total");
this.combineResultsAttribute(xml1, xml2, "passed");
this.combineResultsAttribute(xml1, xml2, "failed");
this.combineResultsAttribute(xml1, xml2, "inconclusive");
this.combineResultsAttribute(xml1, xml2, "skipped");
this.combineResultsAttribute(xml1, xml2, "asserts");
const testSuitesParent: Element = this.collectAllElements(xml1.documentElement, "test-run")[0];
const testSuites: Element[] = this.collectChildren(xml2.documentElement, "test-suite");
testSuites.forEach((child: Element) => {
testSuitesParent.appendChild(child);
});
return xml1;
}
appendToTestNameTransformation(xml: Document, text: string): void {
const testCases: Element[] = this.collectAllElements(xml.documentElement, "test-case");
testCases.forEach((testCase: Element) => {
const name: Attr = testCase.attributes.getNamedItem("name");
if (name) {
name.value = `${name.value}${text}`;
}
});
}
removeIgnoredTransformation(xml: Document): void {
const testResults: Element[] = this.collectAllElements(xml.documentElement, "test-results");
testResults.forEach((testResult: Element) => {
const ignoredAttr: Attr = testResult.attributes.getNamedItem("ignored");
if (ignoredAttr) {
const notRunAttr: Attr = testResult.attributes.getNamedItem("not-run");
if (notRunAttr) {
const notRun: number = Number(notRunAttr.value);
const ignored: number = Number(ignoredAttr.value);
notRunAttr.value = String(notRun - ignored);
}
ignoredAttr.value = "0";
}
});
const elements: Element[] = this.collectAllElements(xml.documentElement, "test-case");
elements.forEach((element: Element) => {
const resultAttr: Attr = element.attributes.getNamedItem("result");
if (resultAttr && resultAttr.value === "Ignored" || resultAttr.value === "Skipped") {
element.parentNode.removeChild(element);
}
});
}
removeEmptySuitesTransformation(xml: Document): void {
const elements: Element[] = this.collectAllElements(xml.documentElement, "test-suite");
elements.forEach((element: Element) => {
if (this.countChildren(element) <= 1) {
element.parentNode.removeChild(element);
}
});
}
combineResultsAttribute(xml1: Document, xml2: Document, attributeName: string) {
this.addResultsAttribute(xml1, attributeName, this.getResultsAttribute(xml2, attributeName));
}
getResultsAttribute(xml: Document, attributeName: string): number {
const testResults: Element = this.getResultsNode(xml);
if (!testResults) {
return 0;
}
const attr: Attr = testResults.attributes.getNamedItem(attributeName);
if (attr.value) {
return Number(attr.value);
}
return 0;
}
addResultsAttribute(xml: Document, attributeName: string, value: number) {
const currentValue: number = this.getResultsAttribute(xml, attributeName);
const testResults: Element = this.getResultsNode(xml);
if (!testResults) {
return;
}
const attr: Attr = testResults.attributes.getNamedItem(attributeName);
if (attr) {
attr.value = String(currentValue + value);
}
}
getResultsNode(xml: Document): Element {
let testResults: Element[] = this.collectAllElements(xml.documentElement, "test-results");
if (testResults.length === 0) {
testResults = this.collectAllElements(xml.documentElement, "test-run");
}
return testResults[0];
}
isNUnit3(xml: Document): boolean {
const testResults: Element[] = this.collectAllElements(xml.documentElement, "test-results");
return testResults.length === 0;
}
}