Repository navigation
Web: connected-flow smokes for the core tabs beyond Apps #2148
Description
Sub-issue of #2031 — the second bullet of its suggested scope.
Problem
The web client has exactly one connected-flow smoke, and it is the Apps tab. smoke:web:app deep-links a connect, opens an app, and asserts data-app-status="ready"; smoke:web:elicit drives the app-rendered elicitation path off the same shape. Everything else the web UI does against a live server is unsmoked through the prod bundle:
- Tools — list renders, select a tool, run it, result panel populates (including
structuredContent) - Resources — list renders, read a resource, content renders; template expansion via the RFC 6570 form
- Prompts — list renders, get a prompt, messages render
- Network — a request/response pair appears with its
Mcp-*headers - Protocol — the JSON-RPC exchange for a call is grouped and rendered
- Logs —
logging/setLevel+ a streamednotifications/messagelands in the panel - Tasks — a "Run as task" call surfaces in the Tasks tab and completes
Those surfaces are carried today by unit tests, Storybook play functions, and the integration project — all of which mock or bypass the prod server. So a regression that only exists in the built bundle, or in the prod Hono backend's wiring of a tab, passes npm run smoke cleanly. That is the same class smoke:web:browser was added for (#1615) and that smoke:web:app extended (#1859) — this issue finishes the job for the remaining tabs.
What already exists to build on
Nothing here needs new server-side work:
- The server harness is shared.
scripts/lib/prod-web-server.mjsowns spawn/readiness/teardown and the throwawayMCP_CATALOG_PATH(chore(smoke): isolate the web smokes' catalog — they write a deep-link row into the developer's real mcp.json #1977), andscripts/lib/announced-child.mjsowns spawning the test server and parsing its announced URL (Three small cleanups flagged in the v2.2.0 merge review #2000). - The deep-link connect shape is already factored out.
scripts/lib/mcp-app-flow.mjscarries the?serverUrl=…&autoConnect=<token>&…construction and its CSRF gates, shared bysmoke:web:appandpack:verify(pack:verify should render an MCP App from the installed tarball, not just assert sandbox_proxy.html exists #2003). A connected-tab smoke wants the connect half of that, minus the app-specific staging — extract it rather than copying it, since a drifted deep link fails as an opaque timeout rather than a mismatch. - The servers exist.
test-servers/configs/already ships a showcase config per surface:structured-output-http.json,rfc6570-templates-http.json,modern-network-http.json,logging-{legacy,modern}-http.json,tasks-{legacy,modern}-http.json,pagination-http.json. - The readiness-contract pattern exists.
data-app-status="ready"is a single attribute standing for "the whole chain completed". Each tab needs the equivalent — adata-*contract asserted in the DOM, not a text lookup — so the assertions do not depend on copy. Note the main-view tabs are a MantineSegmentedControl, so there is norole="tab"; the clickable element is the siblinglabel[for$="-Tools"](seesmoke:web:elicit).
Suggested shape
- One script,
scripts/smoke-web-tabs.mjs, driving several tabs against one or two servers on a single browser launch — rather than one script per tab. Browser launch and server boot dominate the cost, andnpm run ciis already several minutes. - Add whatever
data-*readiness attributes the assertions need to the components, alongside the existingdata-app-status/data-app-elicitation-statusprecedent. - Wire into
npm run smoke(and thereforenpm run ci), and into the GitHub workflow's smoke step. - Keep it Chromium-only here; cross-engine is the third bullet of Deepen TUI and web smoke coverage, and run the browser smokes cross-engine #2031 and is tracked separately (Run the MCP Apps sandbox smokes locally in Firefox and WebKit, not just Chromium #2086 covered the Apps smokes).
Decisions to make while sizing
- Which tabs are in scope for the first pass. Tools / Resources / Prompts are the highest-traffic and the cheapest; Network / Protocol / Logs / Tasks each need a specific server config and more waiting. Splitting again is reasonable if the whole set is too large for one PR.
- Legacy vs modern era per tab. Logs, Tasks, and Subscriptions behave differently per era and the configs come in pairs — smoking both doubles the cost for a surface the integration project already covers per era.
- Budget. State the added wall-clock in the PR. If the whole set is more than a minute or two, consider gating the deeper half behind a separate script that CI runs but
npm run cidoes not — and say so explicitly rather than letting it drift.
Out of scope
- TUI interaction coverage — the first bullet of Deepen TUI and web smoke coverage, and run the browser smokes cross-engine #2031.
- Cross-engine parameterization — the third bullet of Deepen TUI and web smoke coverage, and run the browser smokes cross-engine #2031, and Run the MCP Apps sandbox smokes locally in Firefox and WebKit, not just Chromium #2086.
- Tarball-level coverage —
pack:verify's dimension (pack:verify should render an MCP App from the installed tarball, not just assert sandbox_proxy.html exists #2003).
Activity
chore(web): address Copilot review on the tab smoke
chore(web): connected-flow smoke for the Tools, Resources and Prompts…