Skip to content

VS Test Explorer integration; remove VS Code's Run mechanism (#504) - #505

Merged
clrudolphi merged 7 commits into
masterfrom
docs/issue-504-vs-outcome-api-investigation
Aug 28, 2026
Merged

VS Test Explorer integration; remove VS Code's Run mechanism (#504)#505
clrudolphi merged 7 commits into
masterfrom
docs/issue-504-vs-outcome-api-investigation

Conversation

@clrudolphi

Copy link
Copy Markdown
Collaborator

🤔 What's changed?

Visual Studio — the Run CodeLens now fully integrates with VS's real Test Explorer:

  • Run/Debug already delegated to Test Explorer's own commands; added a "Show in Test Explorer" action alongside them.
  • Added a pass/fail glyph to the CodeLens label via a guarded reflection bridge (RunTestOutcomeBridge) into VS's internal (unsupported) outcome-cache API — every failure mode is caught and permanently vs. transiently classified, so a future VS update can only ever degrade the glyph back to "none," never crash the CodeLens host.
  • Fixed the Run/Hook/StepHooks CodeLens providers being tied at the same Priority, which left their left-to-right order on a Scenario: line unspecified.

VS Code — removed the Run CodeLens and its entire supporting pipeline (dotnet test invocation, TRX parsing, test-filter building, the dotnet-CLI locator) entirely. An owned vscode.TestController was tried and reverted along the way (see commit history / design doc for the full arc) — on reflection, neither it nor the original CodeLens added value beyond what C# Dev Kit's own gutter/Test Explorer integration already provides for Reqnroll-generated methods (mapped back to .feature files via Reqnroll's #line pragmas). VS Code's Reqnroll extension now has no run mechanism of its own.

Rider — research spike only, no code change. Decompiled the actual pinned Rider 2024.3.5 distribution to find the plugin-API accessor the design doc had flagged as an open follow-up. Finding: the design doc's SMTestProxy hypothesis was wrong — Rider's .NET unit testing has no JVM-side extension point at all; native tool-window integration would need a separate C#/ReSharperHost-SDK backend plugin, a materially larger project than anything else done for this issue. Not pursued; Rider's existing CodeVisionProvider-based Run lens is unchanged.

⚡️ What's your motivation?

Issue #504 started as "does VS Code's own gutter/Test Explorer integration make our custom Run CodeLens redundant?" Investigating that question across all three IDEs surfaced follow-on work in each: VS's Run/Debug delegation had an easy win (Test Explorer sync + pass/fail glyph) worth shipping; VS Code's answer ended up being "yes, defer to C# Dev Kit, remove our own mechanism"; Rider's answer was "no native integration path exists without a much bigger separate project."

Fixes #504.

🏷️ What kind of change is this?

  • ⚡ New feature (non-breaking change which adds new behaviour) — VS
  • 💥 Breaking change (incompatible changes to the protocol or extension API) — VS Code (removes the Run CodeLens)
  • 📖 Documentation (improvements without changing code) — Rider

🧩 Area(s) touched

  • Visual Studio extension (src/VisualStudio)
  • VS Code extension (src/VSCode)

♻️ Anything particular you want feedback on?

  • Whether removing VS Code's Run CodeLens outright (rather than keeping a minimal fallback) is the right call, given C# Dev Kit's own discovery is known to be occasionally flaky across a VS Code relaunch.
  • The reflection-based pass/fail glyph on VS (RunTestOutcomeBridge) intentionally reaches into an unsupported internal VS API — reviewed and accepted the risk, but flagging for visibility since it's an unusual pattern for this codebase.

📋 Checklist:

  • I've changed the behaviour of the code
    • I have added/updated tests to cover my changes.
  • My change alters as-built behaviour described in a design doc under docs/
    • I have updated the relevant doc accordingly (see docs/AsBuilt-Reconciliation-Reminder.md).
  • Users should know about my change
    • I have added an entry to the "[vNext]" section of the CHANGELOG, linking to this pull request & included my GitHub handle to the release contributors list.

clrudolphi and others added 7 commits August 27, 2026 14:42
…504)

Investigating issue #504 (VS Code test explorer vs. our Run CodeLens)
confirmed VS's Run/Debug delegation to Test Explorer was already
correct, but the pass/fail outcome API (ICodeLensTestInformationService)
is internal/unsupported - decompiled and documented that finding instead
of reflecting into it. In its place, added a "Show in Test Explorer"
action (the public SyncTestFromCodeLens command) so users can reach the
native pass/fail state without leaving the .feature file.

Also fixed the Run/Hook/StepHooks CodeLens providers being tied at the
same Priority, which left their left-to-right order on a Scenario line
unspecified - now Run leads, matching VS's own TestStatusProvider
convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…adation (VS, #504)

Reflects into VS's internal ICodeLensTestInformationService (the same
mechanism its own TestStatusProvider CodeLens uses) to show a pass/fail
glyph on the Run CodeLens, since that outcome data has no public API.
Reads the outcome by name rather than casting, so a reshaped/renamed
enum degrades to "unrecognized" instead of throwing.

Distinguishes a permanent shape change (TypeLoadException/
MissingMemberException from a failed reflection lookup - disable for
the process's lifetime) from a transient failure (a dropped connection,
or the outcome service not yet registered right after a fresh VS
launch - log and retry on the next call). The first cut conflated the
two and disabled itself permanently on any failure at all, which made
the glyph go dark after every VS relaunch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the CodeLens-only "own execution, no TestController" design
(Option 2) with a real vscode.TestController: .feature scenarios now
get native Testing-sidebar presence, run/rerun, pass/fail history, and
a failed-step marker via TestMessage.location - all previously
hand-rolled through TestResultStore/ResultDecorationService (both
deleted).

Reconsidered because issue #504 confirmed live that C# Dev Kit's own
test discovery already places a decoration on a Reqnroll-generated
method's .feature-mapped location - the exact "no way to address a
.feature line" premise the original Option 2 analysis rested on. Given
that, owning a reliable TestController was judged worth the accepted
risk of an occasional duplicate Testing-sidebar entry when C# Dev
Kit's separately flaky/async discovery also fires for the same
scenario.

The item tree is still built lazily (document symbols only, no
reqnroll/resolveTestTargets calls) to preserve issue #495's fix; the
existing TRX-based dotnet test invocation and stdout step-trace parsing
are reused as-is, just reported through vscode.TestRun instead of a
custom decoration service. Debug remains deliberately unimplemented,
matching the CodeLens this replaces - VSTEST_HOST_DEBUG + a
debug-adapter attach needs its own spike.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Live testing of the new TestController against C# Dev Kit's own test
items found three gaps. This fixes the first:

- Output pane showed "The test run did not record any output" because
  nothing ever called TestRun.appendOutput() - VS Code doesn't
  populate that tab on its own. Now streams every result's captured
  stdout (Reqnroll's step trace) for both passed and failed runs,
  CRLF-normalized as the terminal-style Output view requires.

The other two are recorded in the design doc rather than fixed here:
Scenario Outline rows don't show as a per-row tree (the LSP server's
Examples document-symbol node has no row-level children to build from
yet - deferred, not a regression, the Outline still runs correctly)
and an intermittent DLL-lock build failure needs no code change
(MSBuild's own retry already covers it).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
)

On reflection, neither the original CodeLens-based Run action nor the
TestController it was migrated to add value that C# Dev Kit's own
gutter/Test Explorer integration doesn't already provide for
Reqnroll-generated methods (mapped back to .feature files via
Reqnroll's #line pragmas). Removes the entire testRunner/ pipeline
(dotnet test invocation, TRX parsing, test-filter building, the
dotnet-CLI locator) along with the run/test command registrations and
manifest entries - VS Code's Reqnroll extension now has no run
mechanism of its own.

VS and Rider are unaffected; this is VS-Code-specific. Design doc
updated to record the full arc (Option 2 shipped -> TestController
migration -> this reversal) so it isn't re-litigated from scratch if
revisited later. Two CHANGELOG entries pre-dating this session also
narrowed to drop their now-inaccurate "VS Code" attribution, since the
code they described (the dotnet-CLI locator) no longer exists there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
)

Decompiled the actual pinned Rider 2024.3.5 distribution (via the
devcontainer's Gradle cache, no live UI session needed) to find the
exact plugin-API accessor the design doc had flagged as an open
follow-up under the SMTestProxy hypothesis.

Finding: that hypothesis was wrong. Rider's .NET unit testing isn't
built on IntelliJ Platform's generic SMTRunnerEventsListener/
SMTestProxy at all - it's an entirely separate, RD-protocol-driven
system (com.jetbrains.rider.unitTesting.* frontend UI synced from
com.jetbrains.rider.model.RdUnitTest* backend-owned state). The JVM
frontend can only fire Run/Debug signals on a session; every test
element the tool window shows originates from the .NET ReSharperHost
backend. There is no JVM-side extension point for a plugin to inject
a synthetic test item.

Decision: not pursuing native tool-window integration for Reqnroll
scenarios. It would require a separate C#/ReSharperHost-SDK backend
plugin project - a different architecture entirely from this repo's
existing pure-Kotlin frontend plugin, and a materially larger scope
than anything else done for #504. Rider keeps its existing
CodeVisionProvider-based own-execution Run lens unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@clrudolphi
clrudolphi merged commit 14e1804 into master Aug 28, 2026
17 checks passed
@clrudolphi
clrudolphi deleted the docs/issue-504-vs-outcome-api-investigation branch August 28, 2026 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant