Skip to content

Commit

Permalink
Merge pull request #572 from owenniblock/feature/nunit3-xml-report-su…
Browse files Browse the repository at this point in the history
…pport

Add support for NUnit3 XML reports from UITest
  • Loading branch information
owenniblock authored Apr 30, 2019
2 parents e817dea + 4bcfd46 commit af594fe
Show file tree
Hide file tree
Showing 8 changed files with 3,998 additions and 26 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@
"autorest": "^2.0.4283",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"gulp": "^4.0.0",
"gulp": "^4.0.1",
"gulp-clean": "^0.3.2",
"gulp-sourcemaps": "^2.6.4",
"gulp-typescript": "^3.2.4",
"gulp-typescript": "^5.0.1",
"libxmljs": "^0.18.8",
"mocha": "^5.2.0",
"mock-require": "^2.0.2",
Expand Down
84 changes: 63 additions & 21 deletions src/commands/test/lib/nunit-xml-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ export class NUnitXmlUtil extends XmlUtil {
self.removeEmptySuitesTransformation(xml);

if (mainXml) {
mainXml = self.combine(mainXml, xml);
if (this.isNUnit3(xml)) {
mainXml = self.combineNUnit3(mainXml, xml);
} else {
mainXml = self.combineNUnit2(mainXml, xml);
}
} else {
mainXml = xml;
}
Expand All @@ -42,15 +46,15 @@ export class NUnitXmlUtil extends XmlUtil {
return "nunit_xml_zip.zip";
}

combine(xml1: Document, xml2: Document): Document {
this.combineTestResultsAttribute(xml1, xml2, "total");
this.combineTestResultsAttribute(xml1, xml2, "errors");
this.combineTestResultsAttribute(xml1, xml2, "failures");
this.combineTestResultsAttribute(xml1, xml2, "not-run");
this.combineTestResultsAttribute(xml1, xml2, "inconclusive");
this.combineTestResultsAttribute(xml1, xml2, "ignored");
this.combineTestResultsAttribute(xml1, xml2, "skipped");
this.combineTestResultsAttribute(xml1, xml2, "invalid");
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");
Expand All @@ -62,6 +66,25 @@ export class NUnitXmlUtil extends XmlUtil {
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) => {
Expand Down Expand Up @@ -90,7 +113,7 @@ export class NUnitXmlUtil extends XmlUtil {
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") {
if (resultAttr && resultAttr.value === "Ignored" || resultAttr.value === "Skipped") {
element.parentNode.removeChild(element);
}
});
Expand All @@ -105,29 +128,48 @@ export class NUnitXmlUtil extends XmlUtil {
});
}

combineTestResultsAttribute(xml1: Document, xml2: Document, attributeName: string) {
this.addTestResultsAttribute(xml1, attributeName, this.getTestResultsAttribute(xml2, attributeName));
combineResultsAttribute(xml1: Document, xml2: Document, attributeName: string) {
this.addResultsAttribute(xml1, attributeName, this.getResultsAttribute(xml2, attributeName));
}

getTestResultsAttribute(xml: Document, attributeName: string): number {
const testResults: Element[] = this.collectAllElements(xml.documentElement, "test-results");
if (testResults.length === 0) {
getResultsAttribute(xml: Document, attributeName: string): number {
const testResults: Element = this.getResultsNode(xml);
if (!testResults) {
return 0;
}

const attr: Attr = testResults[0].attributes.getNamedItem(attributeName);
const attr: Attr = testResults.attributes.getNamedItem(attributeName);
if (attr.value) {
return Number(attr.value);
}
return 0;
}

addTestResultsAttribute(xml: Document, attributeName: string, value: number) {
const currentValue: number = this.getTestResultsAttribute(xml, attributeName);
const testResults: Element[] = this.collectAllElements(xml.documentElement, "test-results");
const attr: Attr = testResults[0].attributes.getNamedItem(attributeName);
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;
}
}
3,887 changes: 3,887 additions & 0 deletions test/commands/test/resources/nunit3_report.xml

Large diffs are not rendered by default.

Binary file added test/commands/test/resources/nunit3_xml_zip.zip
Binary file not shown.
47 changes: 45 additions & 2 deletions test/commands/test/util/nunit-xml-util-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { expect } from "chai";
import { DOMParser, XMLSerializer } from "xmldom";
import * as xmlLib from "libxmljs";
import * as path from "path";
import * as fs from "fs";
import { NUnitXmlUtil } from "../../../../src/commands/test/lib/nunit-xml-util";
import { XmlUtil } from "../../../../src/commands/test/lib/xml-util";

describe("nunit xml util", function () {
const strXml: string =
Expand Down Expand Up @@ -132,10 +134,51 @@ describe("nunit xml util", function () {
expect(xmlUtil.countChildren(null)).to.eql(0);
});

it("should combine xmls correctly", async () => {
it("should should identify nunit2 xml correctly", async () => {

// If
const pathToArchive: string = path.join(__dirname, "../resources/nunit_xml_zip.zip");
const pathToArchive: string = path.join(__dirname, "../resources/nunit2_report.xml");
const xml: Document = new DOMParser(XmlUtil.DOMParserConfig).parseFromString(fs.readFileSync(pathToArchive, "utf-8"), "text/xml");

// When
const isNUnit3: boolean = xmlUtil.isNUnit3(xml);

// Doesn't throw exception
expect(isNUnit3).to.eql(false);
});

it("should should identify nunit3 xml correctly", async () => {

// If
const pathToArchive: string = path.join(__dirname, "../resources/nunit3_report.xml");
const xml: Document = new DOMParser(XmlUtil.DOMParserConfig).parseFromString(fs.readFileSync(pathToArchive, "utf-8"), "text/xml");

// When
const isNUnit3: boolean = xmlUtil.isNUnit3(xml);

// Doesn't throw exception
expect(isNUnit3).to.eql(true);
});

it("should combine nunit2 xmls correctly", async () => {

// If
const pathToArchive: string = path.join(__dirname, "../resources/nunit2_xml_zip.zip");

// When
const xml: Document = await xmlUtil.mergeXmlResults(pathToArchive);

// Then
const finalStrXml: string = new XMLSerializer().serializeToString(xml);

// Doesn't throw exception
xmlLib.parseXml(finalStrXml);
});

it("should combine nunit3 xmls correctly", async () => {

// If
const pathToArchive: string = path.join(__dirname, "../resources/nunit3_xml_zip.zip");

// When
const xml: Document = await xmlUtil.mergeXmlResults(pathToArchive);
Expand Down
2 changes: 1 addition & 1 deletion test/commands/test/util/xml-util-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { validXmlFile } from "../../../../src/commands/test/lib/xml-util";
describe("xml util", function () {

it("should return positive validation result for the correct xml file", async () => {
const pathToXml: string = path.join(__dirname, "../resources/nunit_report.xml");
const pathToXml: string = path.join(__dirname, "../resources/nunit2_report.xml");

const isValid: boolean = validXmlFile(pathToXml);

Expand Down

0 comments on commit af594fe

Please sign in to comment.