From 13cc030d3224900afc0a0a3244b8a74b1e50246a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Mar 2026 14:44:54 +0000 Subject: [PATCH 1/2] Initial plan From 01c17c6fc9015a6999ae38c477f00e3467f251a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Mar 2026 14:49:36 +0000 Subject: [PATCH 2/2] feat: add source and request custom attributes to JUnit XML report - Add SourceType and RequestName properties to TestResult model - Set SourceType='inline' and RequestName for inline tests in TestFactory - Set SourceType='csx' for CSX tests in Registrator - Propagate SourceType and RequestName in Tester when creating Passed/Failed results - Add sourceType and requestName parameters to JUnitXmlWriter.WriteTestCase - Pass SourceType and RequestName from TestResult to writer in JUnitXmlTestResultsSummaryReporter - Add tests for new attributes in JUnitXmlWriterShould and JUnitXmlTestResultsSummaryReporterShould Co-authored-by: Burgyn <5930822+Burgyn@users.noreply.github.com> Agent-Logs-Url: https://github.com/Kros-sk/TeaPie/sessions/9641a5f3-e740-4ba9-ad44-ceb0f42b5fa4 --- .../JUnitXmlTestResultsSummaryReporter.cs | 12 +++- src/TeaPie/Testing/Registrator.cs | 2 +- src/TeaPie/Testing/TestFactory.cs | 19 ++++- src/TeaPie/Testing/TestResult.cs | 4 ++ src/TeaPie/Testing/Tester.cs | 8 ++- src/TeaPie/Xml/JUnitXmlWriter.cs | 14 +++- ...UnitXmlTestResultsSummaryReporterShould.cs | 71 +++++++++++++++++++ .../TeaPie.Tests/Xml/JUnitXmlWriterShould.cs | 57 +++++++++++++++ 8 files changed, 177 insertions(+), 10 deletions(-) diff --git a/src/TeaPie/Reporting/JUnitXmlTestResultsSummaryReporter.cs b/src/TeaPie/Reporting/JUnitXmlTestResultsSummaryReporter.cs index f98a5d66..4614cd9b 100644 --- a/src/TeaPie/Reporting/JUnitXmlTestResultsSummaryReporter.cs +++ b/src/TeaPie/Reporting/JUnitXmlTestResultsSummaryReporter.cs @@ -88,7 +88,9 @@ private static void WriteFailedTest( failedTest.Duration, false, failedTest.ErrorMessage, - stackTrace: failedTest.Exception?.StackTrace); + stackTrace: failedTest.Exception?.StackTrace, + sourceType: failedTest.SourceType, + requestName: failedTest.RequestName); private static void WriteSkippedTest( JUnitXmlWriter writer, @@ -98,7 +100,9 @@ private static void WriteSkippedTest( testCaseSummary.Name, skippedTest.TestName, 0.0, - true); + true, + sourceType: skippedTest.SourceType, + requestName: skippedTest.RequestName); private static void WritePassedTest( JUnitXmlWriter writer, @@ -108,5 +112,7 @@ private static void WritePassedTest( testCaseSummary.Name, passedTest.TestName, passedTest.Duration, - false); + false, + sourceType: passedTest.SourceType, + requestName: passedTest.RequestName); } diff --git a/src/TeaPie/Testing/Registrator.cs b/src/TeaPie/Testing/Registrator.cs index 13087126..c414baff 100644 --- a/src/TeaPie/Testing/Registrator.cs +++ b/src/TeaPie/Testing/Registrator.cs @@ -30,7 +30,7 @@ private async Task RegisterBase(string testName, Func testFunction, bool s testName, skipTest, testFunction, - new TestResult.NotRun() { TestName = testName, TestCasePath = testCase.RequestsFile.RelativePath }, + new TestResult.NotRun() { TestName = testName, TestCasePath = testCase.RequestsFile.RelativePath, SourceType = "csx" }, testCase); testCaseExecutionContext.RegisterTest(test); diff --git a/src/TeaPie/Testing/TestFactory.cs b/src/TeaPie/Testing/TestFactory.cs index da9225dd..c8536a33 100644 --- a/src/TeaPie/Testing/TestFactory.cs +++ b/src/TeaPie/Testing/TestFactory.cs @@ -33,12 +33,23 @@ private static Test Create( { CheckParameters(description, out var requestExecutionContext); + var requestName = !string.IsNullOrEmpty(requestExecutionContext.Name) + ? requestExecutionContext.Name + : null; + return CreateTest(testDirective.TestNameGetter(description.Parameters), requestExecutionContext.TestCaseExecutionContext?.TestCase, - async () => await testDirective.TestFunction(requestExecutionContext.Response!, description.Parameters)); + async () => await testDirective.TestFunction(requestExecutionContext.Response!, description.Parameters), + sourceType: "inline", + requestName: requestName); } - private static Test CreateTest(string testName, TestCase? testCase, Func testFunction) + private static Test CreateTest( + string testName, + TestCase? testCase, + Func testFunction, + string? sourceType = null, + string? requestName = null) { var test = new Test( $"[{_factoryCount}] {testName}", @@ -47,7 +58,9 @@ private static Test CreateTest(string testName, TestCase? testCase, Func t new TestResult.NotRun() { TestName = testName, - TestCasePath = testCase?.RequestsFile.RelativePath ?? string.Empty + TestCasePath = testCase?.RequestsFile.RelativePath ?? string.Empty, + SourceType = sourceType, + RequestName = requestName }, testCase); diff --git a/src/TeaPie/Testing/TestResult.cs b/src/TeaPie/Testing/TestResult.cs index b8ac52b7..c7427d30 100644 --- a/src/TeaPie/Testing/TestResult.cs +++ b/src/TeaPie/Testing/TestResult.cs @@ -12,4 +12,8 @@ public partial record Failed(long Duration, string ErrorMessage, Exception? Exce public required string TestName { get; init; } public string TestCasePath { get; init; } + + public string? SourceType { get; init; } + + public string? RequestName { get; init; } } diff --git a/src/TeaPie/Testing/Tester.cs b/src/TeaPie/Testing/Tester.cs index db91b7e6..14ac524c 100644 --- a/src/TeaPie/Testing/Tester.cs +++ b/src/TeaPie/Testing/Tester.cs @@ -126,14 +126,18 @@ private TestResult.Passed CreatePassedResult(Test test, TestCase? testCase) => new(_stopWatch.ElapsedMilliseconds) { TestName = test.Name, - TestCasePath = testCase?.RequestsFile.RelativePath ?? string.Empty + TestCasePath = testCase?.RequestsFile.RelativePath ?? string.Empty, + SourceType = test.Result.SourceType, + RequestName = test.Result.RequestName }; private TestResult.Failed CreateFailedResult(Test test, Exception ex, TestCase? testCase) => new(_stopWatch.ElapsedMilliseconds, ex.Message, ex) { TestName = test.Name, - TestCasePath = testCase?.RequestsFile.RelativePath ?? string.Empty + TestCasePath = testCase?.RequestsFile.RelativePath ?? string.Empty, + SourceType = test.Result.SourceType, + RequestName = test.Result.RequestName }; #region Logging diff --git a/src/TeaPie/Xml/JUnitXmlWriter.cs b/src/TeaPie/Xml/JUnitXmlWriter.cs index af528e5f..55968385 100644 --- a/src/TeaPie/Xml/JUnitXmlWriter.cs +++ b/src/TeaPie/Xml/JUnitXmlWriter.cs @@ -58,7 +58,9 @@ public void WriteTestCase( bool skipped, string? failureMessage = null, string failureType = "AssertionError", - string? stackTrace = null) + string? stackTrace = null, + string? sourceType = null, + string? requestName = null) { EnsureTestSuiteWritten(); @@ -66,6 +68,16 @@ public void WriteTestCase( WriteNameAndTimeAttributes(testName, timeMs); _writer.WriteAttributeString("classname", className); + if (!string.IsNullOrEmpty(sourceType)) + { + _writer.WriteAttributeString("source", sourceType); + } + + if (!string.IsNullOrEmpty(requestName)) + { + _writer.WriteAttributeString("request", requestName); + } + if (skipped) { _writer.WriteElementString("skipped", string.Empty); diff --git a/tests/TeaPie.Tests/Reporting/JUnitXmlTestResultsSummaryReporterShould.cs b/tests/TeaPie.Tests/Reporting/JUnitXmlTestResultsSummaryReporterShould.cs index e88897af..df9aba18 100644 --- a/tests/TeaPie.Tests/Reporting/JUnitXmlTestResultsSummaryReporterShould.cs +++ b/tests/TeaPie.Tests/Reporting/JUnitXmlTestResultsSummaryReporterShould.cs @@ -124,6 +124,57 @@ public void EnsureTimeFormatUsesDotAsDecimalSeparator() Contains(".", suite.Attribute("time")?.Value); } + [Fact] + public void WriteSourceAttributeForInlineTests() + { + var summary = CreateMockTestSummaryWithSourceInfo(); + + var reporter = new JUnitXmlTestResultsSummaryReporter(TestFilePath); + reporter.Report(summary); + + var doc = XDocument.Load(TestFilePath); + var inlineTest = doc.Descendants("testcase") + .FirstOrDefault(tc => tc.Attribute("name")?.Value == "InlineTest"); + + NotNull(inlineTest); + Equal("inline", inlineTest.Attribute("source")?.Value); + Equal("EditCarRequest", inlineTest.Attribute("request")?.Value); + } + + [Fact] + public void WriteSourceAttributeForCsxTests() + { + var summary = CreateMockTestSummaryWithSourceInfo(); + + var reporter = new JUnitXmlTestResultsSummaryReporter(TestFilePath); + reporter.Report(summary); + + var doc = XDocument.Load(TestFilePath); + var csxTest = doc.Descendants("testcase") + .FirstOrDefault(tc => tc.Attribute("name")?.Value == "CsxTest"); + + NotNull(csxTest); + Equal("csx", csxTest.Attribute("source")?.Value); + Null(csxTest.Attribute("request")); + } + + [Fact] + public void OmitSourceAndRequestAttributesWhenNotSet() + { + var summary = CreateMockTestSummary(); + + var reporter = new JUnitXmlTestResultsSummaryReporter(TestFilePath); + reporter.Report(summary); + + var doc = XDocument.Load(TestFilePath); + var testCase = doc.Descendants("testcase") + .FirstOrDefault(tc => tc.Attribute("name")?.Value == "Test1"); + + NotNull(testCase); + Null(testCase.Attribute("source")); + Null(testCase.Attribute("request")); + } + private static CollectionTestResultsSummary CreateMockTestSummary() { var summary = new CollectionTestResultsSummary(); @@ -144,4 +195,24 @@ private static CollectionTestResultsSummary CreateMockTestSummary() return summary; } + + private static CollectionTestResultsSummary CreateMockTestSummaryWithSourceInfo() + { + var summary = new CollectionTestResultsSummary(); + summary.AddPassedTest("SampleTestCase", new TestResult.Passed(150) + { + TestName = "InlineTest", + SourceType = "inline", + RequestName = "EditCarRequest" + }); + summary.AddPassedTest("SampleTestCase", new TestResult.Passed(200) + { + TestName = "CsxTest", + SourceType = "csx" + }); + + summary.Start(); + + return summary; + } } diff --git a/tests/TeaPie.Tests/Xml/JUnitXmlWriterShould.cs b/tests/TeaPie.Tests/Xml/JUnitXmlWriterShould.cs index 81115189..0981872d 100644 --- a/tests/TeaPie.Tests/Xml/JUnitXmlWriterShould.cs +++ b/tests/TeaPie.Tests/Xml/JUnitXmlWriterShould.cs @@ -139,4 +139,61 @@ public void EnsureTimeFormatUsesDotAsDecimalSeparator() NotNull(suite); Contains(".", suite.Attribute("time")?.Value); } + + [Fact] + public void WriteSourceAttributeWhenProvided() + { + using (var writer = new JUnitXmlWriter(TestFilePath)) + { + writer.WriteTestSuitesRoot(); + writer.WriteTestSuite("SuiteF", totalTests: 1, skipped: 0, failures: 0, timeMs: 100); + writer.WriteTestCase("Tests", "InlineTest", 50, skipped: false, sourceType: "inline", requestName: "MyRequest"); + writer.EndTestSuite(); + writer.EndTestSuitesRoot(); + } + + var doc = XDocument.Load(TestFilePath); + var testCase = doc.Descendants("testcase").First(); + + Equal("inline", testCase.Attribute("source")?.Value); + Equal("MyRequest", testCase.Attribute("request")?.Value); + } + + [Fact] + public void WriteCsxSourceAttributeWithoutRequestAttribute() + { + using (var writer = new JUnitXmlWriter(TestFilePath)) + { + writer.WriteTestSuitesRoot(); + writer.WriteTestSuite("SuiteG", totalTests: 1, skipped: 0, failures: 0, timeMs: 100); + writer.WriteTestCase("Tests", "CsxTest", 50, skipped: false, sourceType: "csx"); + writer.EndTestSuite(); + writer.EndTestSuitesRoot(); + } + + var doc = XDocument.Load(TestFilePath); + var testCase = doc.Descendants("testcase").First(); + + Equal("csx", testCase.Attribute("source")?.Value); + Null(testCase.Attribute("request")); + } + + [Fact] + public void OmitSourceAndRequestAttributesWhenNotProvided() + { + using (var writer = new JUnitXmlWriter(TestFilePath)) + { + writer.WriteTestSuitesRoot(); + writer.WriteTestSuite("SuiteH", totalTests: 1, skipped: 0, failures: 0, timeMs: 100); + writer.WriteTestCase("Tests", "PlainTest", 50, skipped: false); + writer.EndTestSuite(); + writer.EndTestSuitesRoot(); + } + + var doc = XDocument.Load(TestFilePath); + var testCase = doc.Descendants("testcase").First(); + + Null(testCase.Attribute("source")); + Null(testCase.Attribute("request")); + } }