Files
vscode/.github
43ddfbfb38 Make UI scenario validation work against an installed build, without an MCP server (#331674)
* Fix automation MCP launches against an installed build

getApplication re-applied the from-source environment on every launch, so
--build runs were also marked VSCODE_DEV=1. A packaged build then behaves as
if it were running from a checkout and never opens a window, and the launch fails
with Timeout 60000ms exceeded while waiting for event ''window''. That
environment is already resolved at module load, and only for the from-source
path, so drop the duplicate.

The launcher also never passed an extensions directory, so a --build run loaded
the user's installed extensions: those change the product under test and their
logs are copied into the evidence bundle. Point it at an isolated directory under
the existing test data path, matching the smoke test runner.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485

* Stop downloading a stable build the MCP server never uses

\setup\ downloaded the previous stable release on every \--build\ launch, and
the test data directory it downloads into is wiped at startup, so the cost was
paid on every run: 335 MB and ~36s before VS Code even starts.

The result was only ever assigned to \opts['stable-build']\, which nothing in
this server reads. Migration tests belong to the smoke test runner, which has its
own copy of this logic. Remove the download along with the now-unused
\--stable-build\ option.

A full \--build\ evidence run drops from about 90s to 19s.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485

* Run UI validation scenarios without configuring an MCP server

The ui-scenario-validation skill could only be used by first registering
test/mcp as an MCP server and then driving the evidence tools by hand. That is a
lot of setup for a one-off reproduction, and it puts the capability out of reach
of a plain request like ''reproduce this issue and record it''.

Add runScenario, which takes a scenario file and runs it end to end:

    node test/mcp/out/runScenario.js <scenario.js> --build <app-root>

A scenario is plain JavaScript that exports an id, a title and a list of steps.
Each step gets the Application, the Workbench helpers and the Playwright page,
returns a string describing how it was validated, throws to fail, or calls
skip(reason) when a precondition is unavailable. The runner launches VS Code with
video and tracing, captures a screenshot at every step boundary, stops at the
first failed or skipped step, writes the report and renders the chapter titles
onto the recording.

Clean capture is enabled by default, so the recording shows unmodified UI and the
step titles are added afterwards.

A skipped step reports the run as aborted rather than passed: the scenario did
not validate, so calling it a pass would overstate the result.

Rewrite the skill around this flow. The MCP server remains available for
interactive exploration, where inspecting the UI before choosing an assertion is
worth the setup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485

* Caption the recording instead of cutting chapter cards into it

Step titles were shown on full-screen cards spliced between segments, which
stretched the timeline and told the viewer nothing about what the step actually
checked. The validation detail was meant to appear on those cards but never did:
it was read from the opening capture, which only records that a step started, so
the field was always empty.

Draw a caption band under the frame instead. ffmpeg pads the canvas and the text
is drawn into the added strip, so the recording keeps its original length and no
recorded pixel is covered - the status bar and the bottom of the workbench stay
readable. Each caption shows the step number and id, its status, the title, and
the validation detail from the closing capture, coloured green, red or amber to
match. The run outcome sits in the corner for the whole video.

This also collapses the render to a single ffmpeg pass: the previous version
trimmed one segment per step, generated a card per step and concatenated them.

Give a CommonJS scenario a .cjs extension. This package is an ES module
package, so a scenario saved as .js inside the repository is treated as ESM and
a CommonJS one fails to load - which is exactly what the skill told people to do.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485

* Rename the skill to validate-ui-scenario

Workspace skills are surfaced as slash commands named after the skill, so the
name is what a user types. "ui-scenario-validation" reads as a topic; the verb
form matches how it is invoked:

    /validate-ui-scenario reproduce <issue url> against my installed Insiders

Update the example to that phrasing, and state that a reproduction which fails at
the expected step is a successful reproduction rather than a broken scenario.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485

* Put the caption band above the recorded frame

The band reads before the frame it describes, and it keeps the eye near the
toolbar and editor where the action happens rather than at the far edge of the
window.

The canvas is still padded rather than overlaid, so no recorded pixel is hidden.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485

* Reject per-run arguments that escape the isolated profile

Per-run `extraArgs` are appended after the generated arguments, and VS Code keeps
the last value of a repeated string option, so a caller-supplied
`--extensions-dir` would replace the isolated directory and let real user
extensions and their logs back into the recording. The same applies to
`--user-data-dir` on the restart path, which had no guard at all.

Move the check into a shared helper and apply it to both the launch and restart
argument paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485

* Unwrap a default export without the `in` operator

`local/code-no-in-operator` rejects `'default' in loaded`. Reading the optional
property directly is equivalent here and simpler: a CommonJS scenario has no
`default`, and an ES module namespace carries the scenario on it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: adb443eb-11e5-40a1-8608-7f593fa79485
2026-08-19 17:03:39 -07:00
..
2026-07-23 18:15:53 +00:00