fix: populate retry/flaky attempt history in HTML report (#6119) by thomhurst · Pull Request #6124 · thomhurst/TUnit (original) (raw)
Retried tests showed as ordinary passes in the HTML report — no retry badge, empty flaky panel, no attempt timeline. Root cause: RetryHelper discarded each failed attempt (Result/timings cleared) before reporting, and the engine emits only one TestNodeUpdateMessage per test (the final result). The HtmlReporter tried to rebuild attempts by walking the update stream, but that stream never contained more than one final state, so the attempts array was always null.
Capture each failed attempt on TestContext before it is cleared, expose it publicly via ITestExecution.RetryAttempts, carry it to the reporter on the final node via TUnitRetryAttemptsProperty, and have HtmlReporter stitch the prior attempts in front of the surviving final attempt.
- TestContext.Execution: RetryAttempts collection + public RetryAttemptRecord
- RetryHelper: record attempt before clearing result
- TestExtensions.ToTestNode: attach property on final state
- HtmlReporter: rebuild attempts from the property instead of the update walk
- Tests: reporter reconstruction + node-attachment coverage
- PublicAPI snapshots updated for the new public surface
[](/apps/claude)
- Move TUnitRetryAttemptsProperty to neutral TUnit.Engine.Reporters namespace (shared ToTestNode should not depend on the Html reporter namespace)
- Accept IReadOnlyList in the property and pass the list directly, dropping a per-retried-test array copy in ToTestNode
- Drop the redundant cast in ITestExecution.RetryAttempts (?? [])
[](/apps/claude)
- Add ExceptionStackTrace to RetryAttemptRecord and ReportAttempt so prior retry attempts carry stack traces (parity with the final attempt).
- Defensive-copy the live RetryAttempts list when publishing the property.
- Clarify ITestExecution.RetryAttempts doc on the n-1 count semantics.
[](/apps/claude)
- Unwrap TUnit wrapper exceptions when recording a failed retry attempt so the captured type/message/stack trace match the final attempt (which unwraps via HtmlReporter.MapException). Fixes inconsistent stack traces for assertion failures across prior vs final attempts.
- Use Array.Empty for the no-retry RetryAttempts fast path.
[](/apps/claude)
[](/apps/claude)
The Trace tab plotted spans against an axis starting at 0, but span start values are absolute offsets from the run start. Tests starting partway through a run had all their bars pushed to the right with empty lead-in space, making the trace look erroneously sparse.
Normalise span positions to the earliest span start (minStart), mirroring the logic already used by the other timeline renderer in the template.
Co-authored-by: Claude Opus 4.8 noreply@anthropic.com
This was referenced
Jun 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
[ Show hidden characters]({{ revealButtonHref }})