From 63bc2159292274a72dba471bcbab4396c88fd0f8 Mon Sep 17 00:00:00 2001 From: bryan cook <3217452+bryanbcook@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:52:30 -0500 Subject: [PATCH 1/5] Added failing tests --- tests/parser.junit.spec.js | 4 ++++ tests/parser.mstest.spec.js | 4 ++++ tests/parser.nunit.spec.js | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/parser.junit.spec.js b/tests/parser.junit.spec.js index ae5add7..be4ff2c 100644 --- a/tests/parser.junit.spec.js +++ b/tests/parser.junit.spec.js @@ -571,4 +571,8 @@ describe('Parser - JUnit', () => { assert.equal(result.suites[0].cases[0].meta_data.get("key1"), "override-value1"); }); + it('parse system.out to locate attachments', () => { + assert.fail(); + }); + }); \ No newline at end of file diff --git a/tests/parser.mstest.spec.js b/tests/parser.mstest.spec.js index d19b15a..08ab4a1 100644 --- a/tests/parser.mstest.spec.js +++ b/tests/parser.mstest.spec.js @@ -62,4 +62,8 @@ describe('Parser - MSTest', () => { assert.equal(testCaseWithCategories.meta_data.get("Categories"), "FixtureCategory,MockCategory"); }); + it('Should include ResultFiles as test case attachments', () => { + assert.fail(); + }); + }); \ No newline at end of file diff --git a/tests/parser.nunit.spec.js b/tests/parser.nunit.spec.js index 5cd079e..020d29e 100644 --- a/tests/parser.nunit.spec.js +++ b/tests/parser.nunit.spec.js @@ -230,8 +230,11 @@ describe('Parser - NUnit', () => { assert.equal(testCaseWithMultipleCategories.get("Categories"), "FixtureCategory,MockCategory"); assert.equal(testCaseWithMultipleCategories.has("FixtureCategory"), true); assert.equal(testCaseWithMultipleCategories.has("MockCategory"), true); - }) + }); + it('Should include attachments associated to test-case', () => { + assert.fail(); + }); }); From d7aa2ec0fc3dcf305b2013a25869f934c4a55935 Mon Sep 17 00:00:00 2001 From: bryan cook <3217452+bryanbcook@users.noreply.github.com> Date: Tue, 27 Feb 2024 18:18:55 -0500 Subject: [PATCH 2/5] add 'attachments' to model and fix impacted tests --- src/models/TestAttachment.d.ts | 8 ++++ src/models/TestAttachment.js | 10 +++++ src/models/TestCase.d.ts | 2 + src/models/TestCase.js | 1 + tests/parser.cucumber.spec.js | 4 ++ tests/parser.junit.spec.js | 21 +++++++++-- tests/parser.mocha.spec.js | 17 ++++++++- tests/parser.testng.spec.js | 68 +++++++++++++++++++++++++++++----- tests/parser.xunit.spec.js | 8 ++++ 9 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 src/models/TestAttachment.d.ts create mode 100644 src/models/TestAttachment.js diff --git a/src/models/TestAttachment.d.ts b/src/models/TestAttachment.d.ts new file mode 100644 index 0000000..aa77a26 --- /dev/null +++ b/src/models/TestAttachment.d.ts @@ -0,0 +1,8 @@ +declare class TestAttachment { + name: string; + path: string; +} + +declare namespace TestAttachment { } + +export = TestAttachment; \ No newline at end of file diff --git a/src/models/TestAttachment.js b/src/models/TestAttachment.js new file mode 100644 index 0000000..254b400 --- /dev/null +++ b/src/models/TestAttachment.js @@ -0,0 +1,10 @@ +class TestAttachment { + + constructor() { + this.name = ''; + this.path = ''; + } + +} + +module.exports = TestAttachment; \ No newline at end of file diff --git a/src/models/TestCase.d.ts b/src/models/TestCase.d.ts index 0215e34..67f16e6 100644 --- a/src/models/TestCase.d.ts +++ b/src/models/TestCase.d.ts @@ -1,4 +1,5 @@ import * as TestStep from './TestStep'; +import * as TestAttachment from './TestAttachment'; declare class TestCase { name: string; @@ -12,6 +13,7 @@ declare class TestCase { failure: string; stack_trace: string; steps: TestStep[]; + attachments: TestAttachment[]; meta_data: Map; setFailure: SetFailureFunction diff --git a/src/models/TestCase.js b/src/models/TestCase.js index be6f3db..87b7d58 100644 --- a/src/models/TestCase.js +++ b/src/models/TestCase.js @@ -15,6 +15,7 @@ class TestCase { this.failure = ''; this.stack_trace = ''; this.steps = []; + this.attachments = []; this.meta_data = new Map(); } diff --git a/tests/parser.cucumber.spec.js b/tests/parser.cucumber.spec.js index 4321f6b..b0c41c8 100644 --- a/tests/parser.cucumber.spec.js +++ b/tests/parser.cucumber.spec.js @@ -33,6 +33,7 @@ describe('Parser - Cucumber Json', () => { meta_data: newMap({ tags: "blue,slow", suite: "1234", tagsRaw: "@blue,@slow" }), cases: [ { + attachments: [], duration: 1.59, errors: 0, failed: 0, @@ -97,6 +98,7 @@ describe('Parser - Cucumber Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 2.56, errors: 0, failed: 0, @@ -112,6 +114,7 @@ describe('Parser - Cucumber Json', () => { total: 0 }, { + attachments: [], duration: 0.28, errors: 0, failed: 0, @@ -141,6 +144,7 @@ describe('Parser - Cucumber Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 0.52, errors: 0, failed: 0, diff --git a/tests/parser.junit.spec.js b/tests/parser.junit.spec.js index be4ff2c..5e2ced8 100644 --- a/tests/parser.junit.spec.js +++ b/tests/parser.junit.spec.js @@ -33,6 +33,7 @@ describe('Parser - JUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 10000, errors: 0, failed: 0, @@ -80,6 +81,7 @@ describe('Parser - JUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 10000, errors: 0, failed: 0, @@ -127,6 +129,7 @@ describe('Parser - JUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 10000, errors: 0, failed: 0, @@ -174,6 +177,7 @@ describe('Parser - JUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 10000, errors: 0, failed: 0, @@ -203,6 +207,7 @@ describe('Parser - JUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 10000, errors: 0, failed: 0, @@ -250,6 +255,7 @@ describe('Parser - JUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 10000, errors: 0, failed: 0, @@ -279,6 +285,7 @@ describe('Parser - JUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 10000, errors: 0, failed: 0, @@ -326,6 +333,7 @@ describe('Parser - JUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 807, errors: 0, failed: 0, @@ -370,9 +378,10 @@ describe('Parser - JUnit', () => { "skipped": 0, "duration": 446, "status": "FAIL", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "Sectors - Verify 'Residential' is in list", "total": 0, @@ -388,6 +397,7 @@ describe('Parser - JUnit', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "Sectors EndPoint - returns a JSON response", "total": 0, @@ -414,9 +424,10 @@ describe('Parser - JUnit', () => { "skipped": 0, "duration": 634, "status": "PASS", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "Market Asset(id-387) response - data is as expected", "total": 0, @@ -461,9 +472,10 @@ describe('Parser - JUnit', () => { "skipped": 1, "duration": 870.6800000000001, "status": "FAIL", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "TestD", "total": 0, @@ -479,6 +491,7 @@ describe('Parser - JUnit', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "TestC", "total": 0, @@ -494,6 +507,7 @@ describe('Parser - JUnit', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "InconclusiveTest", "total": 0, @@ -509,6 +523,7 @@ describe('Parser - JUnit', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "Ignored", "total": 0, diff --git a/tests/parser.mocha.spec.js b/tests/parser.mocha.spec.js index 63b00ba..3ca96e2 100644 --- a/tests/parser.mocha.spec.js +++ b/tests/parser.mocha.spec.js @@ -33,6 +33,7 @@ describe('Parser - Mocha Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -97,6 +98,7 @@ describe('Parser - Mocha Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -112,6 +114,7 @@ describe('Parser - Mocha Json', () => { total: 0 }, { + attachments: [], duration: 0, errors: 0, failed: 0, @@ -158,6 +161,7 @@ describe('Parser - Mocha Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 3, errors: 0, failed: 0, @@ -173,6 +177,7 @@ describe('Parser - Mocha Json', () => { total: 0 }, { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -202,6 +207,7 @@ describe('Parser - Mocha Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -259,7 +265,7 @@ describe('Parser - Mocha Json', () => { }); }); -describe('Parser - Mocha Awesmome Json', () => { +describe('Parser - Mocha Awesome Json', () => { const testDataPath = "tests/data/mocha/awesome"; it('single suite with single test', () => { @@ -289,6 +295,7 @@ describe('Parser - Mocha Awesmome Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -353,6 +360,7 @@ describe('Parser - Mocha Awesmome Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -368,6 +376,7 @@ describe('Parser - Mocha Awesmome Json', () => { total: 0 }, { + attachments: [], duration: 0, errors: 0, failed: 0, @@ -415,6 +424,7 @@ describe('Parser - Mocha Awesmome Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 3, errors: 0, failed: 0, @@ -430,6 +440,7 @@ describe('Parser - Mocha Awesmome Json', () => { total: 0 }, { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -459,6 +470,7 @@ describe('Parser - Mocha Awesmome Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -506,6 +518,7 @@ describe('Parser - Mocha Awesmome Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 3, errors: 0, failed: 0, @@ -521,6 +534,7 @@ describe('Parser - Mocha Awesmome Json', () => { total: 0 }, { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -550,6 +564,7 @@ describe('Parser - Mocha Awesmome Json', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1, errors: 0, failed: 0, diff --git a/tests/parser.testng.spec.js b/tests/parser.testng.spec.js index 89bb2c1..0bd9ecc 100644 --- a/tests/parser.testng.spec.js +++ b/tests/parser.testng.spec.js @@ -31,6 +31,7 @@ describe('Parser - TestNG', () => { meta_data: new Map(), cases: [ { + attachments: [], id: '', name: 'c2', total: 0, @@ -46,6 +47,7 @@ describe('Parser - TestNG', () => { steps: [] }, { + attachments: [], id: '', name: 'c3', total: 0, @@ -61,6 +63,7 @@ describe('Parser - TestNG', () => { steps: [] }, { + attachments: [], id: '', name: 'c1', total: 0, @@ -76,6 +79,7 @@ describe('Parser - TestNG', () => { steps: [] }, { + attachments: [], id: '', name: 'c4', total: 0, @@ -120,9 +124,10 @@ describe('Parser - TestNG', () => { "skipped": 0, "duration": 202082, "status": "FAIL", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "GU", "total": 0, @@ -138,6 +143,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP", "total": 0, @@ -153,6 +159,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP", "total": 0, @@ -168,6 +175,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP_WA", "total": 0, @@ -183,6 +191,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "CB", "total": 0, @@ -209,9 +218,10 @@ describe('Parser - TestNG', () => { "skipped": 1, "duration": 545598, "status": "FAIL", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "GU", "total": 0, @@ -227,6 +237,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP", "total": 0, @@ -242,6 +253,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP", "total": 0, @@ -257,6 +269,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP_WA", "total": 0, @@ -272,6 +285,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "CB", "total": 0, @@ -316,9 +330,10 @@ describe('Parser - TestNG', () => { "skipped": 0, "duration": 2000, "status": "PASS", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "c2", "total": 0, @@ -334,6 +349,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c3", "total": 0, @@ -349,6 +365,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c1", "total": 0, @@ -364,6 +381,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c4", "total": 0, @@ -408,9 +426,10 @@ describe('Parser - TestNG', () => { "skipped": 0, "duration": 2000, "status": "PASS", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "c2", "total": 0, @@ -426,6 +445,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c3", "total": 0, @@ -441,6 +461,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c1", "total": 0, @@ -456,6 +477,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c4", "total": 0, @@ -482,9 +504,10 @@ describe('Parser - TestNG', () => { "skipped": 0, "duration": 2000, "status": "PASS", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "c2", "total": 0, @@ -500,6 +523,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c3", "total": 0, @@ -515,6 +539,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c1", "total": 0, @@ -530,6 +555,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c4", "total": 0, @@ -574,9 +600,10 @@ describe('Parser - TestNG', () => { "skipped": 0, "duration": 1164451, "status": "FAIL", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "GU", "total": 0, @@ -592,6 +619,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "PC", "total": 0, @@ -607,6 +635,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "PC", "total": 0, @@ -622,6 +651,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "CB", "total": 0, @@ -648,9 +678,10 @@ describe('Parser - TestNG', () => { "skipped": 0, "duration": 714100, "status": "FAIL", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "GU", "total": 0, @@ -666,6 +697,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "PC", "total": 0, @@ -681,6 +713,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "PC", "total": 0, @@ -696,6 +729,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "CB", "total": 0, @@ -740,9 +774,10 @@ describe('Parser - TestNG', () => { "skipped": 0, "duration": 202082, "status": "FAIL", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "GU", "total": 0, @@ -758,6 +793,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP", "total": 0, @@ -773,6 +809,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP", "total": 0, @@ -788,6 +825,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP_WA", "total": 0, @@ -803,6 +841,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "CB", "total": 0, @@ -829,9 +868,10 @@ describe('Parser - TestNG', () => { "skipped": 1, "duration": 545598, "status": "FAIL", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "GU", "total": 0, @@ -847,6 +887,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP", "total": 0, @@ -862,6 +903,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP", "total": 0, @@ -877,6 +919,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "SBP_WA", "total": 0, @@ -892,6 +935,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "CB", "total": 0, @@ -918,9 +962,10 @@ describe('Parser - TestNG', () => { "skipped": 0, "duration": 2000, "status": "PASS", - meta_data: new Map(), + "meta_data": new Map(), "cases": [ { + "attachments": [], "id": "", "name": "c2", "total": 0, @@ -936,6 +981,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c3", "total": 0, @@ -951,6 +997,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c1", "total": 0, @@ -966,6 +1013,7 @@ describe('Parser - TestNG', () => { "steps": [] }, { + "attachments": [], "id": "", "name": "c4", "total": 0, diff --git a/tests/parser.xunit.spec.js b/tests/parser.xunit.spec.js index 29eca69..4dbca40 100644 --- a/tests/parser.xunit.spec.js +++ b/tests/parser.xunit.spec.js @@ -33,6 +33,7 @@ describe('Parser - XUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 86006.5, errors: 0, failed: 0, @@ -79,6 +80,7 @@ describe('Parser - XUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1, errors: 0, failed: 0, @@ -124,6 +126,7 @@ describe('Parser - XUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 84201.1799, errors: 0, failed: 0, @@ -139,6 +142,7 @@ describe('Parser - XUnit', () => { total: 0 }, { + attachments: [], duration: 218.6713, errors: 0, failed: 0, @@ -168,6 +172,7 @@ describe('Parser - XUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 1411.6188, errors: 0, failed: 0, @@ -183,6 +188,7 @@ describe('Parser - XUnit', () => { total: 0 }, { + attachments: [], duration: 1791.1067, errors: 0, failed: 0, @@ -212,6 +218,7 @@ describe('Parser - XUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 84195.474, errors: 0, failed: 0, @@ -241,6 +248,7 @@ describe('Parser - XUnit', () => { meta_data: new Map(), cases: [ { + attachments: [], duration: 86006.7435, errors: 0, failed: 0, From b611b5a93651df3ba6ed9cc3796027fe1318b202 Mon Sep 17 00:00:00 2001 From: bryan cook <3217452+bryanbcook@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:10:56 -0500 Subject: [PATCH 3/5] junit implementation for attachments --- src/parsers/junit.js | 33 +++++++++++++++++++++- src/parsers/junit.result.d.ts | 3 +- tests/data/junit/test-case-attachments.xml | 29 +++++++++++++++++++ tests/parser.junit.spec.js | 17 ++++++++++- 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 tests/data/junit/test-case-attachments.xml diff --git a/src/parsers/junit.js b/src/parsers/junit.js index 0d39c68..7a4995c 100644 --- a/src/parsers/junit.js +++ b/src/parsers/junit.js @@ -3,12 +3,15 @@ const { getJsonFromXMLFile } = require('../helpers/helper'); const TestResult = require('../models/TestResult'); const TestSuite = require('../models/TestSuite'); const TestCase = require('../models/TestCase'); +const TestAttachment = require('../models/TestAttachment'); +const { Test } = require('mocha'); function getTestCase(rawCase) { const test_case = new TestCase(); test_case.name = rawCase["@_name"]; test_case.duration = rawCase["@_time"] * 1000; - setMetaData(rawCase.properties, test_case); + setAttachments(rawCase, test_case); + setMetaData(rawCase.properties, test_case); if (rawCase.failure && rawCase.failure.length > 0) { test_case.status = 'FAIL'; test_case.setFailure(rawCase.failure[0]["@_message"]); @@ -59,6 +62,34 @@ function setMetaData(properties, test_element) { } } +/** + * @param {import('./junit.result').JUnitTestCase} rawCase + * @param {TestCase} test_element + */ +function setAttachments(rawCase, test_element) { + if (rawCase['system.out']) { + const systemOut = rawCase['system.out']; + + // junit attachments plug syntax is [[ATTACHMENT|/absolute/path/to/file.png]] + const regex = new RegExp('\\[\\[ATTACHMENT\\|([^\\]]+)\\]\\]', 'g'); + + while ((m = regex.exec(systemOut)) !== null) { + // avoid infinite loops with zero-width matches + if (m.index === regex.lastIndex) { + regex.lastIndex++; + } + + let filePath = m[1].trim(); + + if (filePath.length > 0) { + const attachment = new TestAttachment(); + attachment.path = filePath; + test_element.attachments.push(attachment); + } + } + } +} + /** * @param {TestResult} result */ diff --git a/src/parsers/junit.result.d.ts b/src/parsers/junit.result.d.ts index 6a4d326..ac3c9ee 100644 --- a/src/parsers/junit.result.d.ts +++ b/src/parsers/junit.result.d.ts @@ -19,9 +19,10 @@ export type JUnitTestCase = { '@_id': string; '@_name': string; '@_time': number; + 'system.out': string; } -export type TestSuite = { +export type JUnitTestSuite = { properties?: JUnitProperties; testcase: JUnitTestCase[]; '@_id': string; diff --git a/tests/data/junit/test-case-attachments.xml b/tests/data/junit/test-case-attachments.xml new file mode 100644 index 0000000..fa08def --- /dev/null +++ b/tests/data/junit/test-case-attachments.xml @@ -0,0 +1,29 @@ + + + + + + [[ATTACHMENT|/path/to/attachment.png]] + + + + + + [[ATTACHMENT|/path/to/attachment1.png]] +Other output +[[ATTACHMENT|/path/to/attachment2.png]] + + + + + + + + + + [[ATTACHMENT| ]] + + + + + \ No newline at end of file diff --git a/tests/parser.junit.spec.js b/tests/parser.junit.spec.js index 5e2ced8..d7bee05 100644 --- a/tests/parser.junit.spec.js +++ b/tests/parser.junit.spec.js @@ -587,7 +587,22 @@ describe('Parser - JUnit', () => { }); it('parse system.out to locate attachments', () => { - assert.fail(); + const result = parse({ type: 'junit', files: ['tests/data/junit/test-case-attachments.xml'] }); + + // test case with 1 attachment + assert.equal(result.suites[0].cases[0].attachments.length, 1); + assert.equal(result.suites[0].cases[0].attachments[0].path, '/path/to/attachment.png'); + + // test case with multiple attachments + assert.equal(result.suites[0].cases[1].attachments.length, 2); + assert.equal(result.suites[0].cases[1].attachments[0].path, '/path/to/attachment1.png'); + assert.equal(result.suites[0].cases[1].attachments[1].path, '/path/to/attachment2.png'); + + // test case with no attachments + assert.equal(result.suites[0].cases[2].attachments.length, 0); + + // test case with empty or malformed attachment output + assert.equal(result.suites[0].cases[3].attachments.length, 0); }); }); \ No newline at end of file From 00375974aeba09c33c8e0835a78659d3a60b29a3 Mon Sep 17 00:00:00 2001 From: bryan cook <3217452+bryanbcook@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:00:39 -0500 Subject: [PATCH 4/5] mstest implementation for attachments --- src/helpers/helper.js | 5 ++-- src/parsers/mstest.js | 41 +++++++++++++++++++++++++++++-- tests/data/mstest/testresults.trx | 32 +++++++++++++++++++++++- tests/parser.mstest.spec.js | 28 ++++++++++++++++++--- 4 files changed, 97 insertions(+), 9 deletions(-) diff --git a/src/helpers/helper.js b/src/helpers/helper.js index fd95631..50ff951 100644 --- a/src/helpers/helper.js +++ b/src/helpers/helper.js @@ -33,9 +33,10 @@ const FORCED_ARRAY_KEYS = [ "testng-results.suite.test.class.test-method", "testng-results.suite.test.class.test-method.exception", "TestRun.Results.UnitTestResult", + "TestRun.Results.UnitTestResult.ResultFiles.ResultFile", "TestRun.TestDefinitions.UnitTest", - "TestRun.TestDefinitions.UnitTest.TestCategory.TestCategoryItem", - "TestRun.TestDefinitions.UnitTest.Properties.Property" + "TestRun.TestDefinitions.UnitTest.Properties.Property", + "TestRun.TestDefinitions.UnitTest.TestCategory.TestCategoryItem" ]; const configured_parser = new XMLParser({ diff --git a/src/parsers/mstest.js b/src/parsers/mstest.js index b38a2ab..7c282fa 100644 --- a/src/parsers/mstest.js +++ b/src/parsers/mstest.js @@ -1,8 +1,10 @@ const { getJsonFromXMLFile } = require('../helpers/helper'); +const path = require('path'); const TestResult = require('../models/TestResult'); const TestSuite = require('../models/TestSuite'); const TestCase = require('../models/TestCase'); +const TestAttachment = require('../models/TestAttachment'); const RESULT_MAP = { Passed: "PASS", @@ -39,6 +41,27 @@ function populateMetaData(rawElement, map) { } } +function populateAttachments(rawResultElement, attachments, testRunName) { + + // attachments are in /TestRun/Results/UnitTestResult/ResultFiles/ResultFile[@path] + if (rawResultElement.ResultFiles && rawResultElement.ResultFiles.ResultFile) { + let executionId = rawResultElement["@_executionId"]; + let rawAttachments = rawResultElement.ResultFiles.ResultFile; + for (let i = 0; i < rawAttachments.length; i++) { + let filePath = rawAttachments[i]["@_path"]; + if (filePath) { + + // file path is relative to testresults.trx + // stored in .//in//path + + let attachment = new TestAttachment(); + attachment.path = path.join(testRunName, "In", executionId, ...(filePath.split(/[\\/]/g))); + attachments.push(attachment); + } + } + } +} + function getTestResultDuration(rawTestResult) { // durations are represented in a timeformat with 7 digit microsecond precision // TODO: introduce d3-time-format after https://github.com/test-results-reporter/parser/issues/42 is fixed. @@ -68,7 +91,16 @@ function getTestSuiteName(testCase) { return testCase.name.substring(0, index); } -function getTestCase(rawTestResult, definitionMap) { +function getTestRunName(rawTestRun) { + // testrun.name contains '@', spaces and ':' + let name = rawTestRun["@_name"]; + if (name) { + return name.replace(/[ @:]/g, '_'); + } + return ''; +} + +function getTestCase(rawTestResult, definitionMap, testRunName) { let id = rawTestResult["@_testId"]; if (definitionMap.has(id)) { @@ -85,6 +117,8 @@ function getTestCase(rawTestResult, definitionMap) { testCase.setFailure(rawTestResult.Output.ErrorInfo.Message); testCase.stack_trace = rawTestResult.Output.ErrorInfo.StackTrace ?? ''; } + // populate attachments + populateAttachments(rawTestResult, testCase.attachments, testRunName); // populate meta populateMetaData(rawDefinition, testCase.meta_data); @@ -126,6 +160,9 @@ function getTestResults(rawTestResults) { } function getTestSuites(rawTestRun) { + + // test attachments are stored in a testrun specific folder /in// + const testRunName = getTestRunName(rawTestRun); // outcomes + durations are stored in /TestRun/TestResults/* const testResults = getTestResults(rawTestRun.Results); // test names and details are stored in /TestRun/TestDefinitions/* @@ -137,7 +174,7 @@ function getTestSuites(rawTestRun) { for (let i = 0; i < testResults.length; i++) { let rawTestResult = testResults[i]; - let testCase = getTestCase(rawTestResult, testDefinitions); + let testCase = getTestCase(rawTestResult, testDefinitions, testRunName); let suiteName = getTestSuiteName(testCase); if (!suiteMap.has(suiteName)) { diff --git a/tests/data/mstest/testresults.trx b/tests/data/mstest/testresults.trx index 4f5d9db..7fa10f4 100644 --- a/tests/data/mstest/testresults.trx +++ b/tests/data/mstest/testresults.trx @@ -6,6 +6,8 @@ + + @@ -50,11 +52,25 @@ System.NotImplementedException: The method or operation is not implemented. + - + + + + + + + + + + + + + + @@ -122,10 +138,23 @@ System.NotImplementedException: The method or operation is not implemented. + + + + + + + + + + + + + @@ -138,6 +167,7 @@ System.NotImplementedException: The method or operation is not implemented. + diff --git a/tests/parser.mstest.spec.js b/tests/parser.mstest.spec.js index 08ab4a1..52d1b7e 100644 --- a/tests/parser.mstest.spec.js +++ b/tests/parser.mstest.spec.js @@ -1,5 +1,6 @@ const { parse } = require('../src'); const assert = require('assert'); +const path = require('path'); describe('Parser - MSTest', () => { @@ -11,12 +12,12 @@ describe('Parser - MSTest', () => { }); it('Should calculate totals', () => { - assert.equal(result.total, 10); - assert.equal(result.passed, 5); + assert.equal(result.total, 12); + assert.equal(result.passed, 7); assert.equal(result.failed, 3); assert.equal(result.skipped, 2); - assert.equal(result.suites.length, 2); + assert.equal(result.suites.length, 3); //assert.equal(result.duration > 0, true); // TODO: Fix }) @@ -63,7 +64,26 @@ describe('Parser - MSTest', () => { }); it('Should include ResultFiles as test case attachments', () => { - assert.fail(); + const testSuiteWithAttachments = result.suites[2]; + let expectedPath1 = resolveExpectedResultFilePath("238c26aa-9963-4623-aeda-95ef9a6799d0", "dummy1.txt"); + let expectedPath2 = resolveExpectedResultFilePath("2b2b0f58-3d88-432c-9955-1040315f96e9", "dummy2.txt"); + let expectedPath3 = resolveExpectedResultFilePath("2b2b0f58-3d88-432c-9955-1040315f96e9", "dummy3.txt"); + + assert.equal(testSuiteWithAttachments.cases[0].attachments.length, 1); + assert.equal(testSuiteWithAttachments.cases[0].attachments[0].path, expectedPath1); + + assert.equal(testSuiteWithAttachments.cases[1].attachments.length, 2); + assert.equal(testSuiteWithAttachments.cases[1].attachments[0].path, expectedPath2) + assert.equal(testSuiteWithAttachments.cases[1].attachments[1].path, expectedPath3) }); + function resolveExpectedResultFilePath(executionId, filePath) { + return path.join( + "bryan.b.cook_MYCOMPUTER_2023-11-12_19_21_51", + "In", + executionId, + "MYCOMPUTER", + filePath); + } + }); \ No newline at end of file From a0a1584a0596ece3555d3229dd239ff1e1330456 Mon Sep 17 00:00:00 2001 From: bryan cook <3217452+bryanbcook@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:34:20 -0500 Subject: [PATCH 5/5] nunit implementation for attacments --- src/helpers/helper.js | 1 + src/parsers/nunit.js | 17 +++++++++++++++++ tests/data/nunit/nunit_v3.xml | 10 ++++++++++ tests/parser.nunit.spec.js | 11 +++++++---- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/helpers/helper.js b/src/helpers/helper.js index 50ff951..d0d399d 100644 --- a/src/helpers/helper.js +++ b/src/helpers/helper.js @@ -52,6 +52,7 @@ const configured_parser = new XMLParser({ case "property": case "test-suite": case "test-case": + case "attachment": return true; default: return false; diff --git a/src/parsers/nunit.js b/src/parsers/nunit.js index 72102c3..b6c0769 100644 --- a/src/parsers/nunit.js +++ b/src/parsers/nunit.js @@ -3,6 +3,7 @@ const { getJsonFromXMLFile } = require('../helpers/helper'); const TestResult = require('../models/TestResult'); const TestSuite = require('../models/TestSuite'); const TestCase = require('../models/TestCase'); +const TestAttachment = require('../models/TestAttachment'); const SUITE_TYPES_WITH_TEST_CASES = [ "TestFixture", @@ -24,6 +25,20 @@ const RESULT_MAP = { Skipped: "SKIP", // v3 } +function populateAttachments(rawCase, attachments) { + if (rawCase.attachments && rawCase.attachments.attachment) { + let rawAttachments = rawCase.attachments.attachment; + for (var i = 0; i < rawAttachments.length; i++) { + var attachment = new TestAttachment(); + attachment.path = rawAttachments[i].filePath; + if (rawAttachments[i].description) { + attachment.name = rawAttachments[i].description; + } + attachments.push(attachment); + } + } +} + function mergeMeta(map1, map2) { for (let kvp of map1) { map2.set(kvp[0], kvp[1]); @@ -130,6 +145,8 @@ function getTestCases(rawSuite, parent_meta) { testCase.stack_trace = errorDetails["stack-trace"] } } + // populate attachments + populateAttachments(rawCase, testCase.attachments); // copy parent_meta data to test case mergeMeta(parent_meta, testCase.meta_data); populateMetaData(rawCase, testCase.meta_data); diff --git a/tests/data/nunit/nunit_v3.xml b/tests/data/nunit/nunit_v3.xml index d0d1712..b273cee 100644 --- a/tests/data/nunit/nunit_v3.xml +++ b/tests/data/nunit/nunit_v3.xml @@ -121,5 +121,15 @@ + + + + + c:\absolute\filepath\dummy.txt + + + + + \ No newline at end of file diff --git a/tests/parser.nunit.spec.js b/tests/parser.nunit.spec.js index 020d29e..b4c471d 100644 --- a/tests/parser.nunit.spec.js +++ b/tests/parser.nunit.spec.js @@ -110,8 +110,8 @@ describe('Parser - NUnit', () => { it('Should calculate totals', () => { // totals on the testresult - assert.equal(result.total, 18); - assert.equal(result.passed, 12); + assert.equal(result.total, 19); + assert.equal(result.passed, 13); assert.equal(result.failed, 2); assert.equal(result.errors, 1); @@ -138,7 +138,7 @@ describe('Parser - NUnit', () => { }); it('Should map results correctly', () => { - assert.equal(result.suites.length, 8); + assert.equal(result.suites.length, 9); // assemblies.mocktestfixture assert.equal(result.suites[0].status, "FAIL"); @@ -233,7 +233,10 @@ describe('Parser - NUnit', () => { }); it('Should include attachments associated to test-case', () => { - assert.fail(); + const testCaseWithAttachments = result.suites[8].cases[0]; + assert.equal(testCaseWithAttachments.attachments.length, 1); + assert.equal(testCaseWithAttachments.attachments[0].path, "c:\\absolute\\filepath\\dummy.txt") + assert.equal(testCaseWithAttachments.attachments[0].name, "my description") }); });