chore(web): address Copilot review on the tab smoke

Three findings, all valid.

**The read/get stages asserted an RPC status, not a render.** #2148 asks
for the resource content and the prompt messages to *render*, and
`data-read-status` / `data-get-status` flip the moment the call resolves
— so the smoke stayed green with the panel deleted. `ResourcePreviewPanel`
and `PromptMessagesDisplay` now carry `data-testid="resource-preview"` /
`"prompt-messages"`, and each stage waits on the status **and** the
rendered panel. Verified by breaking each testid: the smoke fails with
`reading `events` did not render a preview — last observed:
data-read-status="ok"`, which is the finding stated back exactly.

**`smoke:web:tabs` followed ambient `SMOKE_BROWSER`**, so
`SMOKE_BROWSER=firefox npm run ci` would have run the supposedly
Chromium-only smoke under Firefox — contradicting both this PR's stated
scope and the gated-tier invariant in `run-engine-smokes.test.mjs`. The
npm script now pins `chromium` on **both** halves (install and launch)
and the smoke resolves through `resolveRequestedBrowser(argv, env)`, where
an explicit argument wins over the environment; a new case in that same
test file pins it, including that the smoke stays out of `ENGINE_SMOKES`.

**The AGENTS rules were not mirrored into `.github/copilot-instructions.md`.**
Correct, and worse than an omission: that file's engine bullet asserts the
headless web smokes are "engine-parameterized, not Chromium-only", which
this PR made false. It now names `smoke:web:tabs` as the deliberate
exception, and carries the genuinely review-citable new rule — assert
`data-*`, never copy, and never stop at an RPC status where the ask was
that something render.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UL9retfvAXRgvi6EWk4SY4
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-26 23:35:58 -04:00
commit 23088e9c69
4 changed files with 101 additions and 25 deletions

View file

@ -64,3 +64,14 @@ describe("PromptMessagesDisplay", () => {
).not.toBeInTheDocument();
});
});
// The `data-testid` the headless tab smoke waits on (#2148). It asserts the
// messages RENDERED, which `data-get-status="ok"` alone does not — that flips
// as soon as `prompts/get` resolves. Pinned here so a rename fails loudly in a
// unit test rather than as an opaque timeout in a five-minute gate.
describe("automation contract (#2148)", () => {
it("exposes a stable data-testid on the panel", () => {
renderWithMantine(<PromptMessagesDisplay messages={messages} />);
expect(screen.getByTestId("prompt-messages")).toBeInTheDocument();
});
});

View file

@ -67,7 +67,10 @@ export function PromptMessagesDisplay({
onClose,
}: PromptMessagesDisplayProps) {
return (
<PanelStack>
// `data-testid` so a driver can wait on the messages having actually
// RENDERED, not merely on `prompts/get` having returned (#2148) — see the
// ResourcePreviewPanel counterpart for why the RPC status is not enough.
<PanelStack data-testid="prompt-messages">
<HeaderRow>
<HeaderLeft>
{onClose && (

View file

@ -566,3 +566,22 @@ describe("ResourcePreviewPanel", () => {
});
});
});
// The `data-testid` the headless tab smoke waits on (#2148) — see the
// PromptMessagesDisplay counterpart: `data-read-status="ok"` flips as soon as
// `resources/read` resolves, so only this proves the preview rendered.
describe("automation contract (#2148)", () => {
it("exposes a stable data-testid on the panel", () => {
renderWithMantine(
<ResourcePreviewPanel
resource={textResource}
contents={textContents}
isSubscribed={false}
onRefresh={vi.fn()}
onSubscribe={vi.fn()}
onUnsubscribe={vi.fn()}
/>,
);
expect(screen.getByTestId("resource-preview")).toBeInTheDocument();
});
});

View file

@ -222,7 +222,12 @@ export function ResourcePreviewPanel({
const sourceToggleable = isSourceToggleable(mimeType);
return (
<PanelStack>
// `data-testid` so a driver can wait on the preview having actually
// RENDERED, not merely on `resources/read` having returned (#2148). The
// read status flips as soon as the RPC resolves, so a smoke stopping there
// would stay green with this panel removed. A `data-*` attribute is not
// part of a component's typed props, so it is passed at the call site.
<PanelStack data-testid="resource-preview">
<HeaderRow>
<HeaderLeft>
{onClose && (