Remove redundant prefixes from tracing timeline spans#5111
Conversation
The "test assembly:", "test suite:", and "test case:" prefixes add no value since indentation and names already make the span type clear. Removing them reduces text overflow in the timeline view.
There was a problem hiding this comment.
Code Review
This is a clean, well-scoped PR with two tightly coupled changes that make good sense together.
What the PR does
-
EnrichSpanName: Returns just the tag value (e.g."MyTest") instead of"test case: MyTest", removing the redundant prefix from the HTML timeline display. -
GetTestSpanLookup: Replaces name-prefix filtering (span.Name.StartsWith("test case", ...)) with tag-based identification (tunit.test.node_uid).
Analysis
The two changes are logically coupled and necessary together — without updating GetTestSpanLookup, the old name-prefix filter would have broken since the enriched span name is now just the test name, not "test case: ...".
Tag-based identification is the right approach. The tunit.test.node_uid tag is set exclusively on "test case" spans in TestExecutor.cs:137, so the lookup is semantically correct. String prefix matching on display names is inherently fragile; a tag is stable, meaningful, and aligned with OTel conventions.
Minor efficiency note: GetTestSpanLookup now iterates all spans rather than only those whose name starts with "test case". In practice this is negligible — the inner break on first tag match limits per-span cost, and tunit.test.node_uid is absent from non-test-case spans, so they pass through cheaply.
Correctness: The old check span.Name.StartsWith("test case") || span.Tags is null meant spans were skipped if either condition was true. The new check span.Tags is null correctly skips only tagless spans, letting the inner tag search find the right spans. No correctness regression.
Overall
The PR achieves its stated goals: cleaner timeline names without text overflow, and more robust test span identification. Code is minimal, easy to understand, and consistent with the FindTestCaseAncestor method which already used tunit.test.node_uid for the same purpose. No issues found.
The name no longer contains "test case:", "test suite:", etc. prefixes, so the JS timeline filtering broke. Add a separate spanType field that preserves the original activity display name for type identification.
There was a problem hiding this comment.
Updated Review — Second Commit Analysis
My previous review covered the first commit (removing name prefixes + tag-based GetTestSpanLookup). The second commit adds the SpanType field which is worth reviewing on its own.
What the second commit does
Adds SpanType = activity.DisplayName to SpanData and updates all JavaScript filtering from s.name.startsWith('test suite') to s.spanType === 'test suite'.
This is the right design
The two commits together establish a clean separation of concerns in SpanData:
Name— the enriched, human-readable display name (e.g."MyTest") used for renderingSpanType— the stable type discriminator (e.g."test case") used for filtering
Without the second commit, the first commit would have silently broken the JavaScript filtering, since the JS relied on s.name.startsWith('test case') which no longer matches after the prefix was removed. The two commits complete each other correctly.
The JavaScript switch from startsWith to strict equality is also a minor correctness improvement — it avoids false positives if a user-defined activity happened to have a name beginning with "test suite".
One minor observation
SpanType is declared as string? (nullable) even though it is always set in OnActivityStopped. This is reasonable defensive typing — it allows deserializing older JSON payloads that predate this field without breaking. No change needed.
Overall
The PR is complete and correct. Both commits together deliver a clean, maintainable solution: users get uncluttered timeline names, and the type-based filtering is more robust and semantically correct than string-prefix matching. No issues found.
Updated [TUnit](https://github.com/thomhurst/TUnit) from 1.19.16 to 1.19.22. <details> <summary>Release notes</summary> _Sourced from [TUnit's releases](https://github.com/thomhurst/TUnit/releases)._ ## 1.19.22 <!-- Release notes generated using configuration in .github/release.yml at v1.19.22 --> ## What's Changed ### Other Changes * Remove redundant prefixes from tracing timeline spans by @thomhurst in thomhurst/TUnit#5111 * Render span tags and events on separate lines by @thomhurst in thomhurst/TUnit#5113 * Demote granular internal logs from Debug to Trace level by @thomhurst in thomhurst/TUnit#5116 ### Dependencies * chore(deps): update tunit to 1.19.16 by @thomhurst in thomhurst/TUnit#5109 **Full Changelog**: thomhurst/TUnit@v1.19.16...v1.19.22 Commits viewable in [compare view](thomhurst/TUnit@v1.19.16...v1.19.22). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Summary
GetTestSpanLookupto identify test case spans by tag (tunit.test.node_uid) rather than name prefix, which is more robustTest plan