Skip to content

Commit 7580903

Browse files
authored
Dump XML test results (microsoft#24034)
1 parent 61a2949 commit 7580903

File tree

3 files changed

+55
-10
lines changed

3 files changed

+55
-10
lines changed

src/harness/parallel/host.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ namespace Harness.Parallel.Host {
127127
let passingFiles = 0;
128128
let failingFiles = 0;
129129
let errorResults: ErrorInfo[] = [];
130+
let passingResults: { name: string[] }[] = [];
130131
let totalPassing = 0;
131132
const startTime = Date.now();
132133

@@ -198,9 +199,11 @@ namespace Harness.Parallel.Host {
198199
totalPassing += data.payload.passing;
199200
if (data.payload.errors.length) {
200201
errorResults = errorResults.concat(data.payload.errors);
202+
passingResults = passingResults.concat(data.payload.passes);
201203
failingFiles++;
202204
}
203205
else {
206+
passingResults = passingResults.concat(data.payload.passes);
204207
passingFiles++;
205208
}
206209
newPerfData[hashName(data.payload.runner, data.payload.file)] = data.payload.duration;
@@ -367,21 +370,55 @@ namespace Harness.Parallel.Host {
367370

368371
IO.writeFile(perfdataFileName(configOption), JSON.stringify(newPerfData, null, 4)); // tslint:disable-line:no-null-keyword
369372

370-
process.exit(errorResults.length);
373+
if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser && process.env.CI === "true") {
374+
const xunitReport = new xunit({ on: ts.noop, once: ts.noop }, { reporterOptions: { output: "./TEST-results.xml" } });
375+
xunitReport.stats = reporter.stats;
376+
xunitReport.failures = reporter.failures;
377+
const rootAttrs: {[index: string]: any} = {
378+
name: "Tests",
379+
tests: stats.tests,
380+
failures: stats.failures,
381+
errors: stats.failures,
382+
skipped: stats.tests - stats.failures - stats.passes,
383+
timestamp: (new Date()).toUTCString(),
384+
time: (stats.duration / 1000) || 0
385+
};
386+
xunitReport.write(`<?xml version="1.0" encoding="UTF-8"?>` + "\n");
387+
xunitReport.write(`<testsuite ${Object.keys(rootAttrs).map(k => `${k}="${escape("" + rootAttrs[k])}"`).join(" ")}>`);
388+
[...failures, ...ts.map(passingResults, makeMochaTest)].forEach(t => {
389+
xunitReport.test(t);
390+
});
391+
xunitReport.write("</testsuite>");
392+
xunitReport.done(failures, (f: any[]) => {
393+
process.exit(f.length);
394+
});
395+
}
396+
else {
397+
process.exit(failures.length);
398+
}
399+
371400
}
372401

373-
function makeMochaTest(test: ErrorInfo) {
402+
function makeMochaTest(test: ErrorInfo | TestInfo) {
374403
return {
404+
state: (test as ErrorInfo).error ? "failed" : "passed",
405+
parent: {
406+
fullTitle: () => {
407+
return test.name.slice(0, test.name.length - 1).join(" ");
408+
}
409+
},
410+
title: test.name[test.name.length - 1],
375411
fullTitle: () => {
376412
return test.name.join(" ");
377413
},
378414
titlePath: () => {
379415
return test.name;
380416
},
381-
err: {
382-
message: test.error,
383-
stack: test.stack
384-
}
417+
isPending: () => false,
418+
err: (test as ErrorInfo).error ? {
419+
message: (test as ErrorInfo).error,
420+
stack: (test as ErrorInfo).stack
421+
} : undefined
385422
};
386423
}
387424

@@ -392,6 +429,7 @@ namespace Harness.Parallel.Host {
392429

393430
let mocha: any;
394431
let base: any;
432+
let xunit: any;
395433
let color: any;
396434
let cursor: any;
397435
let readline: any;
@@ -434,6 +472,7 @@ namespace Harness.Parallel.Host {
434472
function initializeProgressBarsDependencies() {
435473
mocha = require("mocha");
436474
base = mocha.reporters.Base;
475+
xunit = mocha.reporters.xunit;
437476
color = base.color;
438477
cursor = base.cursor;
439478
readline = require("readline");

src/harness/parallel/shared.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ namespace Harness.Parallel {
77
export type ParallelHostMessage = ParallelTestMessage | ParallelCloseMessage | ParallelBatchMessage;
88

99
export type ParallelErrorMessage = { type: "error", payload: { error: string, stack: string, name?: string[] } } | never;
10-
export type ErrorInfo = ParallelErrorMessage["payload"] & { name: string[] };
11-
export type ParallelResultMessage = { type: "result", payload: { passing: number, errors: ErrorInfo[], duration: number, runner: TestRunnerKind | "unittest", file: string } } | never;
10+
export type TestInfo = { name: string[] } | never;
11+
export type ErrorInfo = ParallelErrorMessage["payload"] & TestInfo;
12+
export type ParallelResultMessage = { type: "result", payload: { passing: number, errors: ErrorInfo[], passes: TestInfo[], duration: number, runner: TestRunnerKind | "unittest", file: string } } | never;
1213
export type ParallelBatchProgressMessage = { type: "progress", payload: ParallelResultMessage["payload"] } | never;
1314
export type ParallelTimeoutChangeMessage = { type: "timeout", payload: { duration: number | "reset" } } | never;
1415
export type ParallelClientMessage = ParallelErrorMessage | ParallelResultMessage | ParallelBatchProgressMessage | ParallelTimeoutChangeMessage;

src/harness/parallel/worker.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace Harness.Parallel.Worker {
22
let errors: ErrorInfo[] = [];
3+
let passes: TestInfo[] = [];
34
let passing = 0;
45

56
type MochaCallback = (this: Mocha.ISuiteCallbackContext, done: MochaDone) => void;
@@ -9,12 +10,13 @@ namespace Harness.Parallel.Worker {
910

1011
function resetShimHarnessAndExecute(runner: RunnerBase) {
1112
errors = [];
13+
passes = [];
1214
passing = 0;
1315
testList.length = 0;
1416
const start = +(new Date());
1517
runner.initializeTests();
1618
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
17-
return { errors, passing, duration: +(new Date()) - start };
19+
return { errors, passes, passing, duration: +(new Date()) - start };
1820
}
1921

2022

@@ -152,6 +154,7 @@ namespace Harness.Parallel.Worker {
152154
try {
153155
// TODO: If we ever start using async test completions, polyfill promise return handling
154156
callback.call(fakeContext);
157+
passes.push({ name: [...namestack] });
155158
}
156159
catch (error) {
157160
errors.push({ error: error.message, stack: error.stack, name: [...namestack] });
@@ -178,6 +181,7 @@ namespace Harness.Parallel.Worker {
178181
errors.push({ error: err.toString(), stack: "", name: [...namestack] });
179182
}
180183
else {
184+
passes.push({ name: [...namestack] });
181185
passing++;
182186
}
183187
completed = true;
@@ -294,11 +298,12 @@ namespace Harness.Parallel.Worker {
294298
}
295299
if (unitTests[name]) {
296300
errors = [];
301+
passes = [];
297302
passing = 0;
298303
const start = +(new Date());
299304
executeSuiteCallback(name, unitTests[name]);
300305
delete unitTests[name];
301-
return { file: name, runner: unittest, errors, passing, duration: +(new Date()) - start };
306+
return { file: name, runner: unittest, errors, passes, passing, duration: +(new Date()) - start };
302307
}
303308
throw new Error(`Unit test with name "${name}" was asked to be run, but such a test does not exist!`);
304309
}

0 commit comments

Comments
 (0)