diff --git a/TUnit.Engine/Services/TestExecution/TestCoordinator.cs b/TUnit.Engine/Services/TestExecution/TestCoordinator.cs index 5377cdbd69..256384242e 100644 --- a/TUnit.Engine/Services/TestExecution/TestCoordinator.cs +++ b/TUnit.Engine/Services/TestExecution/TestCoordinator.cs @@ -150,6 +150,18 @@ await TimeoutHelper.ExecuteWithTimeoutAsync( { var cleanupExceptions = new List(); + // Flush console interceptors to ensure all buffered output is captured + // This is critical for output from Console.Write() without newline + try + { + await Console.Out.FlushAsync().ConfigureAwait(false); + await Console.Error.FlushAsync().ConfigureAwait(false); + } + catch (Exception flushEx) + { + await _logger.LogErrorAsync($"Error flushing console output for {test.TestId}: {flushEx}").ConfigureAwait(false); + } + await _objectTracker.UntrackObjects(test.Context, cleanupExceptions).ConfigureAwait(false); var testClass = test.Metadata.TestClassType; diff --git a/TUnit.TestProject/Bugs/Issue4545/OutputTruncationTests.cs b/TUnit.TestProject/Bugs/Issue4545/OutputTruncationTests.cs new file mode 100644 index 0000000000..329c9f9540 --- /dev/null +++ b/TUnit.TestProject/Bugs/Issue4545/OutputTruncationTests.cs @@ -0,0 +1,40 @@ +namespace TUnit.TestProject.Bugs.Issue4545; + +/// +/// Tests to reproduce the issue where console output is truncated/missing +/// when tests complete, especially when they end with Console.Write (no newline). +/// +[NotInParallel] +public class OutputTruncationTests +{ + [Test] + public async Task Test1_EndsWithWrite_ShouldCaptureAllOutput() + { + Console.WriteLine("Test1: Start"); + Console.WriteLine("Test1: Middle"); + Console.Write("Test1: End (no newline)"); // This may be lost! + + // Small delay to simulate real work + await Task.Delay(10); + } + + [Test] + public async Task Test2_EndsWithWrite_ShouldCaptureAllOutput() + { + Console.WriteLine("Test2: Start"); + Console.WriteLine("Test2: Middle"); + Console.Write("Test2: End (no newline)"); // This may be lost! + + await Task.Delay(10); + } + + [Test] + public async Task Test3_EndsWithWriteLine_ShouldCaptureAllOutput() + { + Console.WriteLine("Test3: Start"); + Console.WriteLine("Test3: Middle"); + Console.WriteLine("Test3: End (with newline)"); // This should be captured + + await Task.Delay(10); + } +} diff --git a/TUnit.TestProject/Bugs/Issue4545/ParallelConsoleOutputTests.cs b/TUnit.TestProject/Bugs/Issue4545/ParallelConsoleOutputTests.cs index c5f57302f7..bcd83772f5 100644 --- a/TUnit.TestProject/Bugs/Issue4545/ParallelConsoleOutputTests.cs +++ b/TUnit.TestProject/Bugs/Issue4545/ParallelConsoleOutputTests.cs @@ -43,4 +43,16 @@ public async Task Test3_ShouldCaptureOnlyOwnOutput() await Assert.That(output).DoesNotContain("Test1"); await Assert.That(output).DoesNotContain("Test2"); } + + [Test] + [Repeat(10)] + public async Task Test4_EndingWithoutNewline_ShouldStillCaptureOutput() + { + Console.WriteLine("Test4-Start"); + await Task.Delay(10); + Console.Write("Test4-End-NoNewline"); + // Test ends here - the final Write should be flushed by the framework + // Note: We check this DURING the test since output is buffered + // The framework flush will ensure it's available in test results + } }