Skip to content

Test declarative WebMCP discovery and invocation - #374

Merged
rgarcia merged 2 commits into
mainfrom
hypeship/webmcp-declarative-e2e
Sep 8, 2026
Merged

Test declarative WebMCP discovery and invocation#374
rgarcia merged 2 commits into
mainfrom
hypeship/webmcp-declarative-e2e

Conversation

@rgarcia

@rgarcia rgarcia commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a self-contained reservation form using native declarative WebMCP annotations, toolautosubmit, and SubmitEvent.respondWith; no imperative registration or polyfill.
  • Reuse TestPlaywrightExecuteAPI's container and warm daemon rather than adding another container startup. Exercise GET /webmcp/tools and POST /webmcp/invoke for both a top-level form and an embedded frame. Assert synthesized schema, field descriptions, required fields, numeric bounds, select enum, autosubmit annotation, and page/frame provenance.
  • Read the DOM through /playwright/execute to verify the field values, visible confirmation, agentInvoked, and exactly one submission. Include fixture documentation and local run commands.

Browser results

The locally built headless image runs Chromium 152.0.7977.42 with its default WebMCP flags. Both variants expose reserve_table with string name/date fields, numeric party size, and seating enum ["dining_room", "terrace", "booth"]. Chromium adds format: "date" and a date-format description hint. Top-level provenance has frame: null; embedded provenance identifies the reservation frame and retains the parent page title/URL.

Both invocations return status: "completed" and output:

{"date":"2030-06-15","name":"Test Guest","party_size":"4","seating":"terrace"}

The visible confirmation contains these values and records one native agent submission. Declarative synthesis works, so there is no unsupported-browser skip.

Validation

  • Built the headless image using the documented Dockerfile.
  • Passed make test-e2e with GOFLAGS='-run=TestPlaywrightExecuteAPI$ -count=3' against that image, including race detection. Used TESTCONTAINERS_HOST_OVERRIDE=127.0.0.1 because local localhost resolution was unavailable.
  • Passed make test-runtime (14 tests).
  • Passed go test -race ./lib/webmcpclient ./lib/browsersurface ./cmd/api/api ./lib/oapi.
  • make test-unit passed vet and all packages except the existing TestUpstreamManagerDetectsChromiumAndRestart: Chromium's temporary profile cleanup fails with directory not empty, including on retry. No unrelated production code changed.
  • Did not run the entire e2e suite or build the headful image.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5970a71. Configure here.

Comment thread server/e2e/e2e_webmcp_test.go Outdated
@rgarcia
rgarcia requested a review from sjmiller609 September 8, 2026 15:50
@rgarcia
rgarcia merged commit 7f86e4f into main Sep 8, 2026
11 checks passed
@rgarcia
rgarcia deleted the hypeship/webmcp-declarative-e2e branch September 8, 2026 21:58
rgarcia added a commit that referenced this pull request Sep 9, 2026
## Summary
- Reuse `browsersurface` for telemetry target/session discovery while
retaining separate CDP connections and tracker instances for telemetry
and WebMCP.
- Add configurable extra target types, early session-attachment events,
and a session-only mode that avoids window lookup and frame
initialization. Preserve the default WebMCP tracker behavior.
- Attach OOPIFs explicitly and dedicated workers through parent-session
auto-attachment, including nested workers. Capture shared/service
workers and retain background-page support.
- Scope network requests by session and request ID, clear
detached-session requests, and discard stale-session data events.
Preserve OOPIF parent-frame metadata without assigning top-level
screenshot/navigation ownership. Drain old capture work before
reconnecting.
- Add real-browser regressions and enable them in CI. Include `iframe`
and `worker` in the event target-type schema and regenerate the Go
OpenAPI output.

## Validation
- All 32 iframe matrix cases now pass with `-race`: top-level,
same-origin, cross-origin and nested cross-origin; default/isolated
contexts; sent/aborted POSTs; frames created before/after monitor
startup.
- Dedicated, shared and service worker request/response body capture
passes against real Chromium. A separate real-browser test verifies that
closing either client's connection leaves the other usable and that
telemetry reconnects with fresh sessions.
- After rebasing, the entire `cdpmonitor` suite with real-browser tests
enabled passed with `-race`, and all 15 runtime tests passed. Chromium
151.0.7922.169 on Linux. The dedicated CDP telemetry browser-regression
step runs in CI.
- `go vet ./...` and the complete non-e2e race suite passed on the
latest commit. An earlier run hit a pre-existing Chromium
temporary-directory cleanup flake in `lib/devtoolsproxy`; its retry and
the final full run both passed. Focused race tests for `cdpmonitor`,
`browsersurface`, `cdpclient`, `webmcpclient`, `oapi`, and the API
handlers also passed.
- Added unit coverage for worker discovery/lifetimes, stale-session
events, OOPIF parent metadata, session-scoped request IDs, and
default-mode iframe initialization with matching real-Chrome
target/frame IDs. Exactly-once tab-open events and in-flight response
draining across reconnect are now fake-server regressions; the new tests
passed 10 race-enabled repetitions. The local Chrome fixture terminates
its process group to avoid renderer/worker cleanup races.

Run from `server/`:
```sh
KERNEL_CDPMONITOR_CHROME_E2E=1 go test -race ./lib/cdpmonitor -count=1
```

## Scope and generated output
These tests cover settled targets, not requests racing domain
initialization. Discovery intentionally covers page, iframe,
dedicated/shared/service worker, and background-page targets;
worklet/webview/other target capture is not part of this change. Default
location-tracked iframe sessions retain their existing independent
initialization/lifetime behavior. No production deployment was
performed; Docker end-to-end tests run in CI.

Rebased onto `main` at `7f86e4f`, which includes the replay-audio timing
fix (#373) and declarative WebMCP end-to-end tests (#374). The five PR
patches are unchanged by the rebase (`git range-diff`). On rebased
commit `54c72f7`, all CI tests and image builds pass, including the full
Docker end-to-end suite; BugBot also completed with no findings. The
earlier replay-audio failures are addressed by the inherited main-branch
fix, not by changes in this PR.

A subsequent CI run hit the existing Chrome fixture's 20-second startup
limit before creating the monitor. The fixture now allows up to 60
seconds (capped by its parent deadline), enforces a real pipe-read
deadline, drains stderr after readiness, and reaps the command on
cleanup. Capture assertion deadlines are unchanged. Startup
deadline/partial-read/EOF tests passed 10 race-enabled repetitions; the
connection-ownership browser test passed five repetitions.

OpenAPI regeneration also synchronizes pre-existing embedded-spec drift
for WebMCP's `awaiting_submission` status. The source schema and
generated Go status types already used that value; this change does not
edit the WebMCP source definition. The generated output was produced
using the existing down-conversion/codegen/SSE-patch pipeline, not
hand-edited.

---------

Co-authored-by: rgarcia <72655+rgarcia@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants