From e2f82d4d30bbebbf89bdbb94b3e58c7aa0185151 Mon Sep 17 00:00:00 2001 From: Alex Knight Date: Fri, 22 May 2026 19:36:38 +1000 Subject: [PATCH] test: add mocked Control UI E2E tests and playwright for local verification and development (#85278) * test: add control ui mocked e2e --- .agents/skills/control-ui-e2e/SKILL.md | 53 ++ .../skills/control-ui-e2e/agents/openai.yaml | 4 + .../openclaw-live-and-e2e-checks-reusable.yml | 3 + .gitignore | 2 + docs/help/testing.md | 26 +- docs/reference/test.md | 4 +- package.json | 4 +- scripts/test-projects.test-support.mjs | 23 + test/scripts/test-projects.test.ts | 32 ++ test/vitest/vitest.scoped-config.ts | 1 + test/vitest/vitest.ui-e2e.config.ts | 38 ++ test/vitest/vitest.ui.config.ts | 4 +- ui/src/test-helpers/control-ui-e2e.ts | 470 ++++++++++++++++++ ui/src/ui/e2e/chat-flow.e2e.test.ts | 87 ++++ ui/vitest.config.ts | 2 +- 15 files changed, 748 insertions(+), 5 deletions(-) create mode 100644 .agents/skills/control-ui-e2e/SKILL.md create mode 100644 .agents/skills/control-ui-e2e/agents/openai.yaml create mode 100644 test/vitest/vitest.ui-e2e.config.ts create mode 100644 ui/src/test-helpers/control-ui-e2e.ts create mode 100644 ui/src/ui/e2e/chat-flow.e2e.test.ts diff --git a/.agents/skills/control-ui-e2e/SKILL.md b/.agents/skills/control-ui-e2e/SKILL.md new file mode 100644 index 00000000000..49354ae1c6e --- /dev/null +++ b/.agents/skills/control-ui-e2e/SKILL.md @@ -0,0 +1,53 @@ +--- +name: control-ui-e2e +description: Use when testing, fixing, or extending the OpenClaw Control UI GUI with Vitest + Playwright end-to-end checks, mocked Gateway WebSocket flows, or agent-verifiable browser proof. +--- + +# Control UI E2E + +Use this for Control UI changes that need a real browser flow with deterministic Gateway data. + +## Test Shape + +- Use `ui/src/**/*.e2e.test.ts` for full GUI flows. +- Use `ui/src/test-helpers/control-ui-e2e.ts` to start the Vite Control UI and install a mocked Gateway WebSocket. +- Keep scenarios deterministic. Do not use live provider keys, real channel credentials, or a real Gateway unless the user explicitly asks for live proof. +- Prefer existing `.browser.test.ts` or unit tests for narrow rendering logic; use this E2E lane when the proof should cover routing, app boot, Gateway handshake, requests, and visible UI behavior together. + +## Commands + +- Target one E2E test in a Codex worktree: + +```bash +node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/ui/e2e/chat-flow.e2e.test.ts +``` + +- Run the whole local lane in a normal checkout: + +```bash +pnpm test:ui:e2e +``` + +If dependencies are missing in a Codex worktree, install once with `pnpm install`; for broad GUI proof or dependency-heavy checks, use Testbox/Crabbox instead of running a wide local pnpm lane. + +## Mock Pattern + +Start the app server, install the mock before `page.goto`, then assert both Gateway traffic and visible UI: + +```ts +const server = await startControlUiE2eServer(); +const page = await context.newPage(); +const gateway = await installMockGateway(page, { + historyMessages: [{ role: "assistant", content: [{ type: "text", text: "Ready." }] }], +}); + +await page.goto(`${server.baseUrl}chat`); +await page.locator(".agent-chat__composer-combobox textarea").fill("hello"); +await page.getByRole("button", { name: "Send message" }).click(); + +const request = await gateway.waitForRequest("chat.send"); +await gateway.emitChatFinal({ runId: String(request.params.idempotencyKey), text: "Done." }); +await page.getByText("Done.").waitFor(); +``` + +Extend `installMockGateway` with typed scenario options or method responses when a new flow needs more Gateway surface. diff --git a/.agents/skills/control-ui-e2e/agents/openai.yaml b/.agents/skills/control-ui-e2e/agents/openai.yaml new file mode 100644 index 00000000000..f13b9006e18 --- /dev/null +++ b/.agents/skills/control-ui-e2e/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Control UI E2E" + short_description: "Mocked browser E2E for Control UI" + default_prompt: "Use $control-ui-e2e to verify a Control UI change with the mocked Vitest + Playwright browser lane." diff --git a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml index d35fb6d54d8..fe782ee2619 100644 --- a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml +++ b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml @@ -547,6 +547,9 @@ jobs: NODE_OPTIONS: --max-old-space-size=8192 run: pnpm build + - name: Install Playwright Chromium + run: pnpm --dir ui exec playwright install --with-deps chromium + - name: Run repo E2E suite run: pnpm test:e2e diff --git a/.gitignore b/.gitignore index 1c75763dec4..20fa36d01e7 100644 --- a/.gitignore +++ b/.gitignore @@ -123,6 +123,8 @@ mantis/ !.agents/skills/crabbox/** !.agents/skills/clawdtributor/ !.agents/skills/clawdtributor/** +!.agents/skills/control-ui-e2e/ +!.agents/skills/control-ui-e2e/** !.agents/skills/gitcrawl/ !.agents/skills/gitcrawl/** !.agents/skills/openclaw-docs/** diff --git a/docs/help/testing.md b/docs/help/testing.md index c2c8c0a68c3..bdc48a590dd 100644 --- a/docs/help/testing.md +++ b/docs/help/testing.md @@ -608,9 +608,19 @@ Native dependency policy: - CI-safe and keyless - Narrow lane for stability-regression follow-up, not a substitute for the full Gateway suite -### E2E (gateway smoke) +### E2E (repo aggregate) - Command: `pnpm test:e2e` +- Scope: + - Runs the gateway smoke E2E lane + - Runs the mocked Control UI browser E2E lane +- Expectations: + - CI-safe and keyless + - Requires Playwright Chromium to be installed + +### E2E (gateway smoke) + +- Command: `pnpm test:e2e:gateway` - Config: `vitest.e2e.config.ts` - Files: `src/**/*.e2e.test.ts`, `test/**/*.e2e.test.ts`, and bundled-plugin E2E tests under `extensions/` - Runtime defaults: @@ -628,6 +638,20 @@ Native dependency policy: - No real keys required - More moving parts than unit tests (can be slower) +### E2E (Control UI mocked browser) + +- Command: `pnpm test:ui:e2e` +- Config: `test/vitest/vitest.ui-e2e.config.ts` +- Files: `ui/src/**/*.e2e.test.ts` +- Scope: + - Starts the Vite Control UI + - Drives a real Chromium page through Playwright + - Replaces the Gateway WebSocket with deterministic in-browser mocks +- Expectations: + - Runs in CI as part of `pnpm test:e2e` + - No real Gateway, agents, or provider keys required + - Browser dependency must be present (`pnpm --dir ui exec playwright install chromium`) + ### E2E: OpenShell backend smoke - Command: `pnpm test:e2e:openshell` diff --git a/docs/reference/test.md b/docs/reference/test.md index a27e38dfac9..4884e42c294 100644 --- a/docs/reference/test.md +++ b/docs/reference/test.md @@ -20,6 +20,7 @@ title: "Tests" - `pnpm test`: routes explicit file/directory targets through scoped Vitest lanes. Untargeted runs use fixed shard groups and expand to leaf configs for local parallel execution; the extension group always expands to the per-extension shard configs instead of one giant root-project process. - Test wrapper runs end with a short `[test] passed|failed|skipped ... in ...` summary. Vitest's own duration line stays the per-shard detail. - Shared OpenClaw test state: use `src/test-utils/openclaw-test-state.ts` from Vitest when a test needs an isolated `HOME`, `OPENCLAW_STATE_DIR`, `OPENCLAW_CONFIG_PATH`, config fixture, workspace, agent dir, or auth-profile store. +- Control UI mocked E2E: use `pnpm test:ui:e2e` for the Vitest + Playwright lane that starts the Vite Control UI and drives a real Chromium page against a mocked Gateway WebSocket. Tests live in `ui/src/**/*.e2e.test.ts`; shared mocks and controls live in `ui/src/test-helpers/control-ui-e2e.ts`. `pnpm test:e2e` includes this lane. In Codex worktrees, prefer `node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/ui/e2e/chat-flow.e2e.test.ts` for tiny targeted proof after dependencies are installed, or Testbox/Crabbox for broader GUI proof. - Process E2E helpers: use `test/helpers/openclaw-test-instance.ts` when a Vitest process-level E2E test needs a running Gateway, CLI env, log capture, and cleanup in one place. - Docker/Bash E2E helpers: lanes that source `scripts/lib/docker-e2e-image.sh` can pass `docker_e2e_test_state_shell_b64