From d1504ea554cb5fc2d13ab85d4a5085ce809b0041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ce=CC=81dric=20Luthi?= Date: Sun, 22 Jun 2025 16:18:52 +0200 Subject: [PATCH 1/3] Add test on a trx report where the className attribute of TestMethod is missing This reproduces issue #556 --- .../__snapshots__/dotnet-trx.test.ts.snap | 4 +- __tests__/dotnet-trx.test.ts | 11 ++-- __tests__/fixtures/dotnet-xunitv3.trx | 60 +++++++++++++++++++ package.json | 1 + .../CalculatorTests.cs | 4 +- .../DotnetTests.NUnitV3Tests.csproj | 9 ++- .../DotnetTests.Unit/DotnetTests.Unit.csproj | 1 + .../DotnetTests.XUnitTests.csproj | 12 ++-- .../DotnetTests.XUnitV3Tests.csproj | 15 +++++ .../DotnetTests.XUnitV3Tests/FixtureTests.cs | 27 +++++++++ reports/dotnet/DotnetTests.sln | 7 +++ 11 files changed, 131 insertions(+), 20 deletions(-) create mode 100644 __tests__/fixtures/dotnet-xunitv3.trx create mode 100644 reports/dotnet/DotnetTests.XUnitV3Tests/DotnetTests.XUnitV3Tests.csproj create mode 100644 reports/dotnet/DotnetTests.XUnitV3Tests/FixtureTests.cs diff --git a/__tests__/__snapshots__/dotnet-trx.test.ts.snap b/__tests__/__snapshots__/dotnet-trx.test.ts.snap index f4053ec..46c8601 100644 --- a/__tests__/__snapshots__/dotnet-trx.test.ts.snap +++ b/__tests__/__snapshots__/dotnet-trx.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`dotnet-trx tests matches report snapshot (only failed tests) 1`] = ` +exports[`dotnet-trx tests matches dotnet-trx report snapshot 1`] = ` TestRunResult { "path": "fixtures/dotnet-trx.trx", "suites": [ @@ -135,7 +135,7 @@ Actual: False } `; -exports[`dotnet-trx tests matches report snapshot 1`] = ` +exports[`dotnet-trx tests matches report snapshot (only failed tests) 1`] = ` TestRunResult { "path": "fixtures/dotnet-trx.trx", "suites": [ diff --git a/__tests__/dotnet-trx.test.ts b/__tests__/dotnet-trx.test.ts index ede52b0..6ec363e 100644 --- a/__tests__/dotnet-trx.test.ts +++ b/__tests__/dotnet-trx.test.ts @@ -39,15 +39,18 @@ describe('dotnet-trx tests', () => { expect(result.result).toBe('success') }) - it('matches report snapshot', async () => { - const fixturePath = path.join(__dirname, 'fixtures', 'dotnet-trx.trx') - const outputPath = path.join(__dirname, '__outputs__', 'dotnet-trx.md') + it.each([ + ['dotnet-trx'], + ['dotnet-xunitv3'] + ])('matches %s report snapshot', async (reportName) => { + const fixturePath = path.join(__dirname, 'fixtures', `${reportName}.trx`) + const outputPath = path.join(__dirname, '__outputs__', `${reportName}.md`) const filePath = normalizeFilePath(path.relative(__dirname, fixturePath)) const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'}) const opts: ParseOptions = { parseErrors: true, - trackedFiles: ['DotnetTests.Unit/Calculator.cs', 'DotnetTests.XUnitTests/CalculatorTests.cs'] + trackedFiles: ['DotnetTests.Unit/Calculator.cs', 'DotnetTests.XUnitTests/CalculatorTests.cs', 'DotnetTests.XUnitV3Tests/FixtureTests.cs'] //workDir: 'C:/Users/Michal/Workspace/dorny/test-check/reports/dotnet/' } diff --git a/__tests__/fixtures/dotnet-xunitv3.trx b/__tests__/fixtures/dotnet-xunitv3.trx new file mode 100644 index 0000000..6bd9c25 --- /dev/null +++ b/__tests__/fixtures/dotnet-xunitv3.trx @@ -0,0 +1,60 @@ + + + + + + + + + + + Assert.Null() Failure: Value is not null +Expected: null +Actual: Fixture { } + at DotnetTests.XUnitV3Tests.FixtureTests.Failing_Test() in /_/reports/dotnet/DotnetTests.XUnitV3Tests/FixtureTests.cs:line 25 + at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) + at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Exit code indicates failure: '2'. Please refer to https://aka.ms/testingplatform/exitcodes for more information. + + + + \ No newline at end of file diff --git a/package.json b/package.json index 5705920..19c1674 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "all": "npm run build && npm run format && npm run lint && npm run package && npm test", "dart-fixture": "cd \"reports/dart\" && dart test --file-reporter=\"json:../../__tests__/fixtures/dart-json.json\"", "dotnet-fixture": "dotnet test reports/dotnet/DotnetTests.XUnitTests --logger \"trx;LogFileName=../../../../__tests__/fixtures/dotnet-trx.trx\"", + "dotnet-xunitv3-fixture": "dotnet run --project reports/dotnet/DotnetTests.XUnitV3Tests/DotnetTests.XUnitV3Tests.csproj --report-trx --report-trx-filename dotnet-xunitv3.trx --results-directory __tests__/fixtures/", "dotnet-nunit-fixture": "nunit.exe reports/dotnet/DotnetTests.NUnitV3Tests/bin/Debug/netcoreapp3.1/DotnetTests.NUnitV3Tests.dll --result=__tests__/fixtures/dotnet-nunit.xml", "dotnet-nunit-legacy-fixture": "nunit-console.exe reports/dotnet-nunit-legacy/NUnitLegacy.sln --result=__tests__/fixtures/dotnet-nunit-legacy.xml", "golang-json-fixture": "go test -v -json -timeout 5s ./reports/go | tee __tests__/fixtures/golang-json.json", diff --git a/reports/dotnet/DotnetTests.NUnitV3Tests/CalculatorTests.cs b/reports/dotnet/DotnetTests.NUnitV3Tests/CalculatorTests.cs index 9452ae9..a61e000 100644 --- a/reports/dotnet/DotnetTests.NUnitV3Tests/CalculatorTests.cs +++ b/reports/dotnet/DotnetTests.NUnitV3Tests/CalculatorTests.cs @@ -40,7 +40,7 @@ namespace DotnetTests.XUnitTests } [Test] - [Timeout(1)] + [CancelAfter(1)] public void Timeout_Test() { Thread.Sleep(100); @@ -58,7 +58,7 @@ namespace DotnetTests.XUnitTests [TestCase(3)] public void Is_Even_Number(int i) { - Assert.True(i % 2 == 0); + Assert.That(i % 2 == 0); } } } diff --git a/reports/dotnet/DotnetTests.NUnitV3Tests/DotnetTests.NUnitV3Tests.csproj b/reports/dotnet/DotnetTests.NUnitV3Tests/DotnetTests.NUnitV3Tests.csproj index 932ff5b..c72f99f 100644 --- a/reports/dotnet/DotnetTests.NUnitV3Tests/DotnetTests.NUnitV3Tests.csproj +++ b/reports/dotnet/DotnetTests.NUnitV3Tests/DotnetTests.NUnitV3Tests.csproj @@ -1,14 +1,13 @@ - netcoreapp3.1 - - false + net8.0 + true - - + + diff --git a/reports/dotnet/DotnetTests.Unit/DotnetTests.Unit.csproj b/reports/dotnet/DotnetTests.Unit/DotnetTests.Unit.csproj index 9f5c4f4..07a1cc7 100644 --- a/reports/dotnet/DotnetTests.Unit/DotnetTests.Unit.csproj +++ b/reports/dotnet/DotnetTests.Unit/DotnetTests.Unit.csproj @@ -2,6 +2,7 @@ netstandard2.0 + true diff --git a/reports/dotnet/DotnetTests.XUnitTests/DotnetTests.XUnitTests.csproj b/reports/dotnet/DotnetTests.XUnitTests/DotnetTests.XUnitTests.csproj index 22cfd8e..c41d64e 100644 --- a/reports/dotnet/DotnetTests.XUnitTests/DotnetTests.XUnitTests.csproj +++ b/reports/dotnet/DotnetTests.XUnitTests/DotnetTests.XUnitTests.csproj @@ -1,16 +1,14 @@ - netcoreapp3.1 - - false + net8.0 + true - - - - + + + diff --git a/reports/dotnet/DotnetTests.XUnitV3Tests/DotnetTests.XUnitV3Tests.csproj b/reports/dotnet/DotnetTests.XUnitV3Tests/DotnetTests.XUnitV3Tests.csproj new file mode 100644 index 0000000..4536685 --- /dev/null +++ b/reports/dotnet/DotnetTests.XUnitV3Tests/DotnetTests.XUnitV3Tests.csproj @@ -0,0 +1,15 @@ + + + + net8.0 + exe + true + true + + + + + + + + diff --git a/reports/dotnet/DotnetTests.XUnitV3Tests/FixtureTests.cs b/reports/dotnet/DotnetTests.XUnitV3Tests/FixtureTests.cs new file mode 100644 index 0000000..737ab8c --- /dev/null +++ b/reports/dotnet/DotnetTests.XUnitV3Tests/FixtureTests.cs @@ -0,0 +1,27 @@ +using System; +using Xunit; + +namespace DotnetTests.XUnitV3Tests; + +public sealed class Fixture : IDisposable +{ + public void Dispose() + { + throw new InvalidOperationException("Failure during fixture disposal"); + } +} + +public class FixtureTests(Fixture fixture) : IClassFixture +{ + [Fact] + public void Passing_Test() + { + Assert.NotNull(fixture); + } + + [Fact] + public void Failing_Test() + { + Assert.Null(fixture); + } +} diff --git a/reports/dotnet/DotnetTests.sln b/reports/dotnet/DotnetTests.sln index 7c5ff87..9635170 100644 --- a/reports/dotnet/DotnetTests.sln +++ b/reports/dotnet/DotnetTests.sln @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotnetTests.XUnitTests", "D EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetTests.NUnitV3Tests", "DotnetTests.NUnitV3Tests\DotnetTests.NUnitV3Tests.csproj", "{81023ED7-56CB-47E9-86C5-9125A0873C55}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetTests.XUnitV3Tests", "DotnetTests.XUnitV3Tests\DotnetTests.XUnitV3Tests.csproj", "{D35E65DC-62EF-4612-9FF3-66F5600BFB74}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -29,6 +31,10 @@ Global {81023ED7-56CB-47E9-86C5-9125A0873C55}.Debug|Any CPU.Build.0 = Debug|Any CPU {81023ED7-56CB-47E9-86C5-9125A0873C55}.Release|Any CPU.ActiveCfg = Release|Any CPU {81023ED7-56CB-47E9-86C5-9125A0873C55}.Release|Any CPU.Build.0 = Release|Any CPU + {D35E65DC-62EF-4612-9FF3-66F5600BFB74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D35E65DC-62EF-4612-9FF3-66F5600BFB74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D35E65DC-62EF-4612-9FF3-66F5600BFB74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D35E65DC-62EF-4612-9FF3-66F5600BFB74}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -36,6 +42,7 @@ Global GlobalSection(NestedProjects) = preSolution {F8607EDB-D25D-47AA-8132-38ACA242E845} = {BCAC3B31-ADB1-4221-9D5B-182EE868648C} {81023ED7-56CB-47E9-86C5-9125A0873C55} = {BCAC3B31-ADB1-4221-9D5B-182EE868648C} + {D35E65DC-62EF-4612-9FF3-66F5600BFB74} = {BCAC3B31-ADB1-4221-9D5B-182EE868648C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6ED5543C-74AA-4B21-8050-943550F3F66E} From 4128d36b9238297063f2ac18b871b325d5fd22a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ce=CC=81dric=20Luthi?= Date: Sun, 22 Jun 2025 16:22:35 +0200 Subject: [PATCH 2/3] Use "Unclassified" when no class name is available Fixes #556 --- __tests__/__outputs__/dotnet-xunitv3.md | 26 +++++++ .../__snapshots__/dotnet-trx.test.ts.snap | 70 +++++++++++++++++++ dist/index.js | 2 +- src/parsers/dotnet-trx/dotnet-trx-parser.ts | 2 +- 4 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 __tests__/__outputs__/dotnet-xunitv3.md diff --git a/__tests__/__outputs__/dotnet-xunitv3.md b/__tests__/__outputs__/dotnet-xunitv3.md new file mode 100644 index 0000000..f27f9e2 --- /dev/null +++ b/__tests__/__outputs__/dotnet-xunitv3.md @@ -0,0 +1,26 @@ +![Tests failed](https://img.shields.io/badge/tests-1%20passed%2C%203%20failed-critical) +|Report|Passed|Failed|Skipped|Time| +|:---|---:|---:|---:|---:| +|[fixtures/dotnet-xunitv3.trx](#user-content-r0)|1 ✅|3 ❌||267ms| +## ❌ fixtures/dotnet-xunitv3.trx +**4** tests were completed in **267ms** with **1** passed, **3** failed and **0** skipped. +|Test suite|Passed|Failed|Skipped|Time| +|:---|---:|---:|---:|---:| +|[DotnetTests.XUnitV3Tests.FixtureTests](#user-content-r0s0)|1 ✅|1 ❌||18ms| +|[Unclassified](#user-content-r0s1)||2 ❌||0ms| +### ❌ DotnetTests.XUnitV3Tests.FixtureTests +``` +❌ Failing_Test + Assert.Null() Failure: Value is not null + Expected: null + Actual: Fixture { } + at DotnetTests.XUnitV3Tests.FixtureTests.Failing_Test() in /_/reports/dotnet/DotnetTests.XUnitV3Tests/FixtureTests.cs:line 25 + at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) + at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) +✅ Passing_Test +``` +### ❌ Unclassified +``` +❌ [Test Class Cleanup Failure (DotnetTests.XUnitV3Tests.FixtureTests.Failing_Test)] +❌ [Test Class Cleanup Failure (DotnetTests.XUnitV3Tests.FixtureTests.Passing_Test)] +``` \ No newline at end of file diff --git a/__tests__/__snapshots__/dotnet-trx.test.ts.snap b/__tests__/__snapshots__/dotnet-trx.test.ts.snap index 46c8601..f432162 100644 --- a/__tests__/__snapshots__/dotnet-trx.test.ts.snap +++ b/__tests__/__snapshots__/dotnet-trx.test.ts.snap @@ -135,6 +135,76 @@ Actual: False } `; +exports[`dotnet-trx tests matches dotnet-xunitv3 report snapshot 1`] = ` +TestRunResult { + "path": "fixtures/dotnet-xunitv3.trx", + "suites": [ + TestSuiteResult { + "groups": [ + TestGroupResult { + "name": null, + "tests": [ + TestCaseResult { + "error": { + "details": "Assert.Null() Failure: Value is not null +Expected: null +Actual: Fixture { } + at DotnetTests.XUnitV3Tests.FixtureTests.Failing_Test() in /_/reports/dotnet/DotnetTests.XUnitV3Tests/FixtureTests.cs:line 25 + at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) + at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)", + "line": 25, + "message": "Assert.Null() Failure: Value is not null +Expected: null +Actual: Fixture { } + at DotnetTests.XUnitV3Tests.FixtureTests.Failing_Test() in /_/reports/dotnet/DotnetTests.XUnitV3Tests/FixtureTests.cs:line 25 + at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) + at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)", + "path": "DotnetTests.XUnitV3Tests/FixtureTests.cs", + }, + "name": "Failing_Test", + "result": "failed", + "time": 17.0545, + }, + TestCaseResult { + "error": undefined, + "name": "Passing_Test", + "result": "success", + "time": 0.8786, + }, + ], + }, + ], + "name": "DotnetTests.XUnitV3Tests.FixtureTests", + "totalTime": undefined, + }, + TestSuiteResult { + "groups": [ + TestGroupResult { + "name": null, + "tests": [ + TestCaseResult { + "error": undefined, + "name": "[Test Class Cleanup Failure (DotnetTests.XUnitV3Tests.FixtureTests.Failing_Test)]", + "result": "failed", + "time": 0, + }, + TestCaseResult { + "error": undefined, + "name": "[Test Class Cleanup Failure (DotnetTests.XUnitV3Tests.FixtureTests.Passing_Test)]", + "result": "failed", + "time": 0, + }, + ], + }, + ], + "name": "Unclassified", + "totalTime": undefined, + }, + ], + "totalTime": 267, +} +`; + exports[`dotnet-trx tests matches report snapshot (only failed tests) 1`] = ` TestRunResult { "path": "fixtures/dotnet-trx.trx", diff --git a/dist/index.js b/dist/index.js index b7ca089..a5ea165 100644 --- a/dist/index.js +++ b/dist/index.js @@ -974,7 +974,7 @@ class DotnetTrxParser { })); const testClasses = {}; for (const r of unitTestsResults) { - const className = r.test.TestMethod[0].$.className; + const className = r.test.TestMethod[0].$.className ?? "Unclassified"; let tc = testClasses[className]; if (tc === undefined) { tc = new TestClass(className); diff --git a/src/parsers/dotnet-trx/dotnet-trx-parser.ts b/src/parsers/dotnet-trx/dotnet-trx-parser.ts index 826d27c..48a383f 100644 --- a/src/parsers/dotnet-trx/dotnet-trx-parser.ts +++ b/src/parsers/dotnet-trx/dotnet-trx-parser.ts @@ -81,7 +81,7 @@ export class DotnetTrxParser implements TestParser { const testClasses: {[name: string]: TestClass} = {} for (const r of unitTestsResults) { - const className = r.test.TestMethod[0].$.className + const className = r.test.TestMethod[0].$.className ?? "Unclassified" let tc = testClasses[className] if (tc === undefined) { tc = new TestClass(className) From be36461fba51cdf91727fbbd526514b22b3818ed Mon Sep 17 00:00:00 2001 From: Jozef Izso Date: Wed, 9 Jul 2025 16:00:06 +0200 Subject: [PATCH 3/3] Fix code formatting in the `dotnet-trx.tests.ts` file --- __tests__/dotnet-trx.test.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/__tests__/dotnet-trx.test.ts b/__tests__/dotnet-trx.test.ts index 6ec363e..a7aead6 100644 --- a/__tests__/dotnet-trx.test.ts +++ b/__tests__/dotnet-trx.test.ts @@ -39,10 +39,7 @@ describe('dotnet-trx tests', () => { expect(result.result).toBe('success') }) - it.each([ - ['dotnet-trx'], - ['dotnet-xunitv3'] - ])('matches %s report snapshot', async (reportName) => { + it.each([['dotnet-trx'], ['dotnet-xunitv3']])('matches %s report snapshot', async reportName => { const fixturePath = path.join(__dirname, 'fixtures', `${reportName}.trx`) const outputPath = path.join(__dirname, '__outputs__', `${reportName}.md`) const filePath = normalizeFilePath(path.relative(__dirname, fixturePath)) @@ -50,7 +47,11 @@ describe('dotnet-trx tests', () => { const opts: ParseOptions = { parseErrors: true, - trackedFiles: ['DotnetTests.Unit/Calculator.cs', 'DotnetTests.XUnitTests/CalculatorTests.cs', 'DotnetTests.XUnitV3Tests/FixtureTests.cs'] + trackedFiles: [ + 'DotnetTests.Unit/Calculator.cs', + 'DotnetTests.XUnitTests/CalculatorTests.cs', + 'DotnetTests.XUnitV3Tests/FixtureTests.cs' + ] //workDir: 'C:/Users/Michal/Workspace/dorny/test-check/reports/dotnet/' }