This document covers the runtime testing lanes in this monorepo.
For general test-layer philosophy, see TESTING_PHILOSOPHY.md.
- Canonical E2E: tools are registered inside the real runtime, discovered through that runtime's public boundary, and called through that same boundary with zero mocked transports or fake servers.
- Runtime API integration: direct
page.evaluate(...),navigator.modelContextTesting, demo flows, and other browser-accurate checks that do not use the same public caller boundary as production clients. - Native Chromium exception: for native WebMCP, the real public boundary is
navigator.modelContext/navigator.modelContextTesting, not an SDKClient.
# Repo default: unit + canonical runtime E2E
pnpm test
# Canonical zero-mock runtime E2E umbrella
pnpm test:e2e
# Playwright browser-runtime contract lane only (tab/global + iframe + native)
pnpm --filter mcp-e2e-tests test
pnpm --filter mcp-e2e-tests test:runtime-contract
# Runtime API integration lanes (not canonical E2E)
pnpm --filter mcp-e2e-tests test:integration:runtime-api
pnpm --filter mcp-e2e-tests test:integration:frameworks
# Native contract lanes
pnpm --filter mcp-e2e-tests test:native-contract:default
pnpm --filter mcp-e2e-tests test:native-contract:beta
# Native parity / showcase integration lanes
pnpm --filter mcp-e2e-tests test:native-parity:default
pnpm --filter mcp-e2e-tests test:native-parity:beta
pnpm --filter mcp-e2e-tests test:native-showcase
# Runtime-specific canonical E2E packages
pnpm --filter @mcp-b/webmcp-local-relay test:e2e
pnpm --filter @mcp-b/chrome-devtools-mcp test:e2e
pnpm --filter @mcp-b/extension-tools test:e2e
# Tarball validation
pnpm test:e2e:tarball:globalNotes:
pnpm test:e2eis the canonical zero-mock umbrella and runs sequentially for stability.pnpm test:e2e:ui,pnpm test:e2e:headed, andpnpm test:e2e:debugdrive the Playwrighte2e/package only. They do not run the relay, DevTools, or extension package E2E lanes.
| Runtime | Canonical caller | Real runtime boundary under test | Command |
|---|---|---|---|
| Tab / global | SDK Client + TabClientTransport |
Browser page running @mcp-b/global |
pnpm --filter mcp-e2e-tests test:runtime-contract |
| Iframe | SDK Client + IframeParentTransport |
Parent/iframe runtime boundary | pnpm --filter mcp-e2e-tests test:runtime-contract |
| Native Chromium | navigator.modelContext / navigator.modelContextTesting |
Native browser API | pnpm --filter mcp-e2e-tests test:native-contract:default |
| Native Chromium (flagged) | navigator.modelContext / navigator.modelContextTesting |
Chrome Beta with WebMCP flags | pnpm --filter mcp-e2e-tests test:native-contract:beta |
| Local relay | SDK Client over stdio |
Real relay server + real browser runtime | pnpm --filter @mcp-b/webmcp-local-relay test:e2e |
| DevTools bridge | SDK Client + WebMCPClientTransport |
Real page discovered through DevTools bridge | pnpm --filter @mcp-b/chrome-devtools-mcp test:e2e |
| Extension transport | SDK Client + ExtensionClientTransport |
Real MV3 extension using ExtensionServerTransport |
pnpm --filter @mcp-b/extension-tools test:e2e |
Every canonical runtime suite is expected to prove all of the following against the real runtime:
- Initial discovery returns the expected base tools.
- A successful call returns the expected payload.
- The runtime records the invocation.
- Dynamic registration becomes discoverable without restarting.
- Dynamic unregistration removes the tool and later calls fail through the real runtime error surface.
- Runtime-thrown tool errors propagate to the caller.
The shared browser/server fixture lives in e2e/runtime-contract/ and defines the deterministic tool set:
echosumdynamic_toolalways_fail
The shared test-only hook is window.__WEBMCP_E2E__ / globalThis.__WEBMCP_E2E__ with:
isReady()registerDynamicTool()unregisterDynamicTool(name?)readInvocations()resetInvocations()
These are useful and still required, but they are not the canonical E2E gate.
pnpm --filter mcp-e2e-tests test:integration:runtime-api
This lane keeps direct runtime and demo validation for:
e2e/tests/tab-transport.spec.tse2e/tests/mcp-iframe-element.spec.tse2e/tests/chromium-native-api.spec.tse2e/tests/notification-batching.spec.tse2e/tests/chrome-beta-webmcp.spec.tse2e/playwright-native-showcase.config.ts
pnpm --filter mcp-e2e-tests test:integration:frameworks
This lane covers framework-level integrations such as React hooks and validation matrices.
The canonical runtime gate lives in .github/workflows/e2e.yml.
The workflow runs:
pnpm test:e2e- Native contract on default Chromium
- Native contract on Chrome Beta with WebMCP flags
- Native showcase integration coverage
- Tarball validation for
@mcp-b/global
pnpm test at the repo root includes this gate by default.
Extension transport E2E is no longer future work. The fixture is a real MV3 extension built into packages/extension-tools/dist/e2e-extension and exercised with:
- real background service worker
- real
ExtensionServerTransport - real extension page client using
ExtensionClientTransport - real SDK
Client
pnpm test:e2e:ui
pnpm test:e2e:headed
pnpm test:e2e:debugThese target the Playwright e2e/ package only.
pnpm --filter @mcp-b/webmcp-local-relay test:e2e
pnpm --filter @mcp-b/chrome-devtools-mcp test:e2e
pnpm --filter @mcp-b/extension-tools test:e2epnpm --filter mcp-e2e-tests exec playwright install chromiumThe Playwright tab/global runtime-contract lane uses PLAYWRIGHT_TAB_TRANSPORT_PORT=4173 by default and only reuses an existing server when PLAYWRIGHT_REUSE_SERVER=1.
If the configured port is in use:
lsof -ti:4173 | xargs killThe flagged native lane requires Chrome Beta with:
--enable-experimental-web-platform-features--enable-features=WebMCPTesting
See e2e/tests/CHROMIUM_TESTING.md for the native contract details.