diff --git a/TUnit.Engine/Reporters/Html/ActivityCollector.cs b/TUnit.Engine/Reporters/Html/ActivityCollector.cs index 2d0888dd4b..cae6be94c1 100644 --- a/TUnit.Engine/Reporters/Html/ActivityCollector.cs +++ b/TUnit.Engine/Reporters/Html/ActivityCollector.cs @@ -122,7 +122,7 @@ public SpanData[] GetAllSpans() { foreach (var span in kvp.Value) { - if (!span.Name.StartsWith("test case", StringComparison.Ordinal) || span.Tags is null) + if (span.Tags is null) { continue; } @@ -180,7 +180,7 @@ private static string EnrichSpanName(Activity activity) var value = activity.GetTagItem(tagKey)?.ToString(); if (!string.IsNullOrEmpty(value)) { - return $"{displayName}: {value}"; + return value; } } @@ -284,6 +284,7 @@ private void OnActivityStopped(Activity activity) SpanId = activity.SpanId.ToString(), ParentSpanId = parentSpanId, Name = EnrichSpanName(activity), + SpanType = activity.DisplayName, Source = activity.Source.Name, Kind = activity.Kind.ToString(), StartTimeMs = activity.StartTimeUtc.Subtract(DateTime.UnixEpoch).TotalMilliseconds, diff --git a/TUnit.Engine/Reporters/Html/HtmlReportDataModel.cs b/TUnit.Engine/Reporters/Html/HtmlReportDataModel.cs index 16fe6ace97..c5d1bcb6e9 100644 --- a/TUnit.Engine/Reporters/Html/HtmlReportDataModel.cs +++ b/TUnit.Engine/Reporters/Html/HtmlReportDataModel.cs @@ -187,6 +187,9 @@ internal sealed class SpanData [JsonPropertyName("name")] public required string Name { get; init; } + [JsonPropertyName("spanType")] + public string? SpanType { get; init; } + [JsonPropertyName("source")] public required string Source { get; init; } diff --git a/TUnit.Engine/Reporters/Html/HtmlReportGenerator.cs b/TUnit.Engine/Reporters/Html/HtmlReportGenerator.cs index cf262ba8f3..88ae811082 100644 --- a/TUnit.Engine/Reporters/Html/HtmlReportGenerator.cs +++ b/TUnit.Engine/Reporters/Html/HtmlReportGenerator.cs @@ -1159,7 +1159,7 @@ private static string GetJavaScript() // Build suite span lookup: className -> span const suiteSpanByClass = {}; spans.forEach(s => { - if (!s.name.startsWith('test suite')) return; + if (s.spanType !== 'test suite') return; const tag = (s.tags||[]).find(t => t.key === 'test.suite.name'); if (tag) suiteSpanByClass[tag.value] = s; }); @@ -1460,7 +1460,7 @@ function renderSuiteTrace(className) { if (!allSpans) return ''; const all = getDescendants(allSpans, suite.spanId); const testCaseIds = new Set(); - all.forEach(s => { if (s.name.startsWith('test case')) testCaseIds.add(s.spanId); }); + all.forEach(s => { if (s.spanType === 'test case') testCaseIds.add(s.spanId); }); const tcDescendants = new Set(); testCaseIds.forEach(id => { getDescendants(all, id).forEach(s => { if (s.spanId !== id) tcDescendants.add(s.spanId); }); }); const filtered = all.filter(s => !tcDescendants.has(s.spanId) && !testCaseIds.has(s.spanId)); @@ -1476,7 +1476,7 @@ function renderSuiteTrace(className) { // Global timeline: session + assembly + suite spans function renderGlobalTimeline() { - const topSpans = spans.filter(s => s.name.startsWith('test session') || s.name.startsWith('test assembly') || s.name.startsWith('test suite')); + const topSpans = spans.filter(s => s.spanType === 'test session' || s.spanType === 'test assembly' || s.spanType === 'test suite'); if (!topSpans.length) return ''; return '
' + tlArrow + 'Execution Timeline
' + renderSpanRows(topSpans, 'global') + '
'; }