From 9dfee9a2cbc271c3f5c1fdcd44d4029fc3fe9e37 Mon Sep 17 00:00:00 2001 From: Mitch Denny Date: Tue, 26 May 2026 13:02:51 +1000 Subject: [PATCH] Use xUnit test method name for CLI E2E recording filenames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves bug #1 of the two root causes that left CLI E2E recordings tagged as Unknown in the PR recording-comment. CliE2ETestHelpers.CreateTestTerminal / CreateDockerTestTerminal / CreatePodmanDockerTestTerminal (and the shared Hex1bTestHelpers.CreateTestTerminal) use [CallerMemberName] to pick the .cast filename. When a public [Fact] is a thin wrapper that delegates into a private helper — e.g. DashboardRunWithAgentMcpListTracesReturnsNoTraces => DashboardRunWithAgentMcpCore in DashboardRunTests, or the *Core helper in AgentMcpLogsTests — [CallerMemberName] captures the helper. The .cast file ends up named after the helper, the TRX has no entry for that name, and the recording-comment workflow's lookup falls through to Unknown on every PR. Fix: prefer TestContext.Current?.TestCase?.TestMethodName when running inside a live xUnit test context, fall back to the [CallerMemberName] default otherwise. The public API surface is unchanged (no caller passes testName explicitly), so the recording filenames quietly flip from 'DashboardRunWithAgentMcpCore' to the public test name with no test-side edits required. The companion workflow-side fix for the second root cause (jq splitting on '.' inside theory parameters before stripping the param suffix) ships in a follow-up commit on the same PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Helpers/CliE2ETestHelpers.cs | 22 ++++++++++++++++++- tests/Shared/Hex1bTestHelpers.cs | 21 ++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/tests/Aspire.Cli.EndToEnd.Tests/Helpers/CliE2ETestHelpers.cs b/tests/Aspire.Cli.EndToEnd.Tests/Helpers/CliE2ETestHelpers.cs index efa72c80999..0b70b1db12f 100644 --- a/tests/Aspire.Cli.EndToEnd.Tests/Helpers/CliE2ETestHelpers.cs +++ b/tests/Aspire.Cli.EndToEnd.Tests/Helpers/CliE2ETestHelpers.cs @@ -93,6 +93,13 @@ internal static string GetTestResultsRecordingPath(string testName) return Hex1bTestHelpers.GetTestResultsRecordingPath(testName, "aspire-cli-e2e"); } + /// + /// Resolves the test method name for naming a recording file. See + /// for the full rationale. + /// + private static string ResolveTestMethodName(string callerMemberName) + => Hex1bTestHelpers.ResolveTestMethodName(callerMemberName); + /// /// Creates a headless Hex1b terminal configured for E2E testing with asciinema recording. /// Uses default dimensions of 160x48 unless overridden. @@ -103,7 +110,14 @@ internal static string GetTestResultsRecordingPath(string testName) /// A configured instance. Caller is responsible for disposal. internal static Hex1bTerminal CreateTestTerminal(int width = 160, int height = 48, [CallerMemberName] string testName = "") { - var recordingPath = GetTestResultsRecordingPath(testName); + // Prefer the xUnit-reported test method name so that when a [Fact]/[Theory] + // delegates into a private helper (e.g. *Core methods), the .cast file is + // still named after the public test the TRX records an outcome for. Without + // this, `[CallerMemberName]` captures the helper, the recording filename has + // no matching TRX entry, and the recording-comment workflow tags the test as + // "Unknown". + var resolvedTestName = ResolveTestMethodName(testName); + var recordingPath = GetTestResultsRecordingPath(resolvedTestName); RegisterCaptureFile("recording.cast", recordingPath); return Hex1bTerminal.CreateBuilder() .WithHeadless() @@ -162,6 +176,9 @@ internal static Hex1bTerminal CreateDockerTestTerminal( int height = 48, [CallerMemberName] string testName = "") { + // See CreateTestTerminal above for why we prefer the xUnit-reported test + // method name over `[CallerMemberName]`. + testName = ResolveTestMethodName(testName); var recordingPath = GetTestResultsRecordingPath(testName); RegisterCaptureFile("recording.cast", recordingPath); var dockerfilePath = GetDockerfilePath(repoRoot, variant); @@ -334,6 +351,9 @@ internal static Hex1bTerminal CreatePodmanDockerTestTerminal( int height = 48, [CallerMemberName] string testName = "") { + // See CreateTestTerminal above for why we prefer the xUnit-reported test + // method name over `[CallerMemberName]`. + testName = ResolveTestMethodName(testName); var recordingPath = GetTestResultsRecordingPath(testName); RegisterCaptureFile("recording.cast", recordingPath); diff --git a/tests/Shared/Hex1bTestHelpers.cs b/tests/Shared/Hex1bTestHelpers.cs index 4d6739cddc2..2b958615030 100644 --- a/tests/Shared/Hex1bTestHelpers.cs +++ b/tests/Shared/Hex1bTestHelpers.cs @@ -89,6 +89,13 @@ internal static Hex1bTerminal CreateTestTerminal( int height = 48, [CallerMemberName] string testName = "") { + // Prefer the xUnit-reported test method name so that when a [Fact]/[Theory] + // delegates into a private helper (e.g. *Core methods), the .cast file is + // still named after the public test the TRX records an outcome for. The CLI + // E2E recording-comment workflow joins .cast files to TRX outcomes by name; + // when the helper name leaks in via `[CallerMemberName]`, no TRX entry + // matches and the test ends up tagged "Unknown" on every PR. + testName = ResolveTestMethodName(testName); var recordingPath = GetTestResultsRecordingPath(testName, localSubDir); var builder = Hex1bTerminal.CreateBuilder() @@ -128,6 +135,20 @@ internal static string GetTestResultsRecordingPath(string testName, string local return Path.Combine(recordingsDir, $"{testName}.cast"); } + /// + /// Resolves the test method name for naming a recording file. Prefers the xUnit-reported + /// TestContext.Current.TestCase.TestMethodName when running inside a live test + /// context, so a recording created from inside a private helper still gets named after + /// the public [Fact]/[Theory] that the TRX records an outcome for. Falls + /// back to the -supplied name when no test context + /// is available. + /// + internal static string ResolveTestMethodName(string callerMemberName) + { + var fromXunit = Xunit.TestContext.Current?.TestCase?.TestMethodName; + return !string.IsNullOrEmpty(fromXunit) ? fromXunit : callerMemberName; + } + /// /// Waits for a successful command prompt with the expected sequence number. ///