Skip to main content

Browser Testing With Playwright And MCP

Use the checked-in Playwright suites for repeatable portal coverage and a browser-capable MCP client for interactive investigation. The supported local stack entry point is scripts/local-validation.sh; do not start portals or run workspace package scripts directly.

Prerequisites

  • Bazel/Bazelisk and the repository toolchains are available.
  • Docker is running for the local services and, when needed, the Playwright MCP container.
  • Chromium is available to the checked-in Playwright installation.
  • Ports 5173, 5174, 8000, 9099, and the local service ports are free.

Check the workstation before starting a run:

./scripts/local-validation.sh doctor

Fix reported Docker, credential, browser, port, or toolchain problems before collecting evidence.

Bazel-First Automated Flow

Start with the Bazel coverage contracts. They detect portal routes or checklist flows that have no corresponding E2E ownership:

bazel test \
//scripts/qa:verify_web_e2e_coverage_test \
//scripts/qa:verify_web_e2e_depth_test

Then start the supported high-fidelity stack. The wrapper builds service and portal artifacts through the repository's Bazel paths, writes generated local environment files, seeds both Firebase tenants and Spanner, and starts the provider stubs:

./scripts/local-validation.sh up
./scripts/local-validation.sh ports

Run the focused checked-in browser smoke:

./scripts/local-validation.sh smoke browser

The smoke runs e2e/local-validation-smoke.spec.ts for both portals with one worker and the seeded credentials. Use the broader smoke only when the change crosses API, auth, provider, or money-path boundaries:

./scripts/local-validation.sh smoke all

Do not replace these commands with direct package-manager invocations. The wrapper owns the expected environment variables, base URLs, test identity, log paths, and stack lifecycle.

Local URLs And Authentication

SurfaceURLFirebase tenant
Retail portalhttp://localhost:5173user-tenant-local
Support portalhttp://localhost:5174admin-tenant-local
API proxyhttp://localhost:8000n/a
Firebase Auth emulatorhttp://localhost:9099tenant selected by the portal

The seed creates the local admin in both portal contexts. Use admin@peakpos.co and read the current local-only password from scripts/local-validation/seed.sh instead of duplicating it in documentation.

The account is a local fixture only. Read the current URLs, tenant, org, and store IDs from ./scripts/local-validation.sh ports and .dev-logs/local-validation/run.json; do not copy IDs from an older run.

The retail and support applications select different tenants even though the fixture email and password match. A login that succeeds in one portal is not evidence that the other tenant is configured correctly.

Interactive Browser And MCP Use

Automated smoke is the baseline. Use MCP after it passes when a reviewer needs to inspect a route, collect a screenshot, reproduce a browser-only failure, or compare UI state with a network response.

If the client already exposes a Playwright/browser MCP server, use that configured server. Otherwise a local HTTP MCP server can be started in Docker:

docker run --rm --init -i \
--network host \
--entrypoint node \
--name playwright-mcp \
mcr.microsoft.com/playwright/mcp \
cli.js --headless --browser chromium --no-sandbox \
--port 8931 --host 0.0.0.0

Point the MCP client at http://localhost:8931/mcp. Host networking is required for the container to reach the stack's localhost ports. Keep the container in the foreground so startup and protocol errors remain visible.

For each interactive check:

  1. Navigate to the portal's login route and authenticate with the appropriate seeded tenant.
  2. Wait for the expected API response, not only a DOM element or fixed delay.
  3. Exercise one named behavior with a stated org/store and expected state transition.
  4. Inspect the browser console and the relevant request status/body.
  5. Capture the final route, visible result, request ID when available, and a redaction-safe screenshot or trace.
  6. Verify destructive or rejected actions against backend state; a toast alone is not mutation evidence.

An MCP transcript is investigative evidence, not a replacement for a checked-in Playwright spec. If a reproduced regression should remain covered, add or update the owning portal's e2e/*.spec.ts and its coverage contract in the same change.

Deterministic Test-Data Boundary

The local seed is the shared baseline. Preserve it:

  • Use the seeded org and store for read-only checks and flows designed for those fixtures.
  • For create/update/delete checks, use a unique value such as qa-<UTC timestamp>-<short suffix> and record every created identifier.
  • Do not alter fixture identities, tenants, Gateway binding, or canonical seeded products unless the scenario explicitly tests that state.
  • Never point local MCP instructions at staging or production URLs. Staging browser work requires separately approved credentials, records, and cleanup.
  • Do not issue ad hoc database deletes. Remove disposable records through the product/API path, or reset the local environment if ownership is uncertain.
  • Keep retries and parallelism low for mutation scenarios; the focused wrapper intentionally runs the browser smoke with one worker.

Evidence And Artifacts

The supported browser smoke writes:

  • .dev-logs/local-validation/logs/playwright-retail-smoke.log
  • .dev-logs/local-validation/logs/playwright-support-smoke.log
  • failure screenshots under the affected portal's Playwright test-results/ directory

For interactive MCP work, create a run-specific directory under .dev-logs/qa/evidence/ and record:

  • branch and commit SHA
  • UTC timestamp and tester
  • portal, route, viewport, tenant, org ID, and store ID
  • expected behavior and observed result
  • redacted screenshot/trace paths
  • request URLs, status codes, request IDs, and relevant service-log paths
  • IDs created for the scenario and the cleanup result

Never save passwords, bearer tokens, App Check tokens, cookies, raw customer PII, PAN, card verification data, provider secrets, or unredacted payloads in a screenshot, trace, console capture, or report.

Cleanup

Delete any disposable records through the same UI or API flow, then stop the MCP container and local stack:

docker stop playwright-mcp
./scripts/local-validation.sh down

If the run intentionally changed shared local fixtures or cleanup cannot be proved, reset the local environment before the next tester uses it:

./scripts/local-validation.sh reset

A completed handoff includes the cleanup outcome. Leaving an unexplained local mutation for the next run makes later browser evidence nondeterministic.