Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/2 Fixes/6990.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for the new JUnit XML format used by pytest 5.1+.
29 changes: 27 additions & 2 deletions src/client/testing/common/xUnitParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ export class XUnitParser implements IXUnitParser {
) {
const data = await this.fs.readFile(outputXmlFile);

const parserResult = await parseXML(data) as { testsuite: TestSuiteResult };
updateTests(tests, parserResult.testsuite);
const parserResult = await parseXML(data);
const junitResults = getJunitResults(parserResult);
if (junitResults) {
updateTests(tests, junitResults);
}
}
}

Expand All @@ -80,6 +83,28 @@ async function parseXML(data: string): Promise<any> {
});
}

// Return the actual test results from the given data.
// tslint:disable-next-line:no-any
function getJunitResults(parserResult: any): TestSuiteResult | undefined {
// This is the newer JUnit XML format (e.g. pytest 5.1 and later).
const fullResults = parserResult as { testsuites: { testsuite: TestSuiteResult[] }};
if (!fullResults.testsuites) {
return (parserResult as { testsuite: TestSuiteResult }).testsuite;
}

const junitSuites = fullResults.testsuites.testsuite;
if (!Array.isArray(junitSuites)) {
throw Error('bad JUnit XML data');
}
if (junitSuites.length === 0) {
return;
}
if (junitSuites.length > 1) {
throw Error('got multiple XML results');
}
return junitSuites[0];
}

// Update "tests" with the given results.
function updateTests(
tests: Tests,
Expand Down
38 changes: 37 additions & 1 deletion src/test/testing/common/xUnitParser.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ suite('Testing - parse JUnit XML file', () => {
node.line = line;
}

test('success with single passing test', async () => {
test('legacy - success with single passing test', async () => {
const tests = createDeclaratively(`
./
test_spam.py
Expand Down Expand Up @@ -72,6 +72,42 @@ suite('Testing - parse JUnit XML file', () => {
fs.verifyAll();
});

test('success with single passing test', async () => {
const tests = createDeclaratively(`
./
test_spam.py
<Tests>
test_spam
`);
const expected = createDeclaratively(`
./
test_spam.py
<Tests>
test_spam P 0.001
`);
fixResult(
expected.testFunctions[0].testFunction,
'test_spam.py',
3
);
const filename = 'x/y/z/results.xml';
fs.setup(f => f.readFile(filename))
.returns(() => Promise.resolve(`
<?xml version="1.0" encoding="utf-8"?>
<testsuites>
<testsuite errors="0" failures="0" hostname="vm-dev-linux-desktop" name="pytest" skipped="0" tests="1" time="0.011" timestamp="2019-09-05T17:17:35.868863">
<testcase classname="test_spam.Tests" file="test_spam.py" line="3" name="test_spam" time="0.001">
</testcase>
</testsuite>
</testsuites>
`));

await parser.updateResultsFromXmlLogFile(tests, filename);

expect(tests).to.deep.equal(expected);
fs.verifyAll();
});

test('no discovered tests', async () => {
const tests: Tests = createEmptyResults();
const expected: Tests = createEmptyResults();
Expand Down