feat(ui-test): Playwright UI E2E suite — helpers + feature flows (stage 2)#2196
Closed
cjlg-soloio wants to merge 16 commits into
Closed
feat(ui-test): Playwright UI E2E suite — helpers + feature flows (stage 2)#2196cjlg-soloio wants to merge 16 commits into
cjlg-soloio wants to merge 16 commits into
Conversation
Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: cjlg-soloio <carlos.logrono@solo.io> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
- Force single Playwright worker unconditionally (shared stub + Next server) - Default req.method/req.url before parsing in the stub server - Fail fast on stub reset failure in CI; stay non-fatal locally - Drop unused pull-requests:write permission from the workflow Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Pairs fullyParallel with workers: 1 so both stay off until per-test data isolation lands, preventing tests from silently racing against the shared stub backend if the worker count is raised. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
- Pin STUB_PORT on the stub webServer so a shell-set STUB_PORT can't misbind it - Stop reusing the dev server so BACKEND_INTERNAL_URL always applies (no silent stub bypass) - Type ToolServerListEntry as the real RemoteMCPServerResponse for compile-time drift detection - Drop no-op **/*.mjs from the playwright tsconfig include Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
…ght video Resolve Charlesthebird's review on PR kagent-dev#2180: - Playwright workflow now reads node-version-file: ui/.nvmrc instead of a hardcoded major version. - Remove Cypress entirely: delete cypress.config.ts and cypress/e2e/smoke.cy.ts, drop the cypress and now-unused start-server-and-test devDeps plus the test:e2e/test:e2e:cypress scripts, and remove the dead CYPRESS_INSTALL_BINARY env from the ui-playwright, ci, and ui-chromatic workflows and the Dockerfile. - Enable Playwright video recording (video: "on"); artifacts already upload via the existing test-results step. - De-Cypress the Playwright README (Jest, Vitest, Storybook untouched). data.ts is intentionally kept — it is consumed by the stacked stage-2 PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Builds on the Stage 0 foundation to unlock non-happy-path testing and give
specs a small, proven driver surface:
- Scenario-override engine in the stub backend: POST /__mock/scenario sets a
per-endpoint { status, body } override; /__mock/reset clears them. Default
stays the happy path.
- Typed control seam (mocks/control.ts) surfaced as a `mock` fixture
(mock.noAgents(), mock.agentsError(), ...); the fixture resets the stub
before every test so scenarios never leak between tests.
- page.ts (loadPage, expectNoErrors, expectToast) and nav.ts (dropdown-aware
gotoView/gotoCreate) driver helpers.
- home spec (happy / empty / error) proving the engine, and a nav spec proving
dropdown routing.
Form/select/dialog helpers are deferred to Stage 2 (built demand-driven with the
create-agent flow).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
First Stage 2 feature spec — the declarative create-agent flow: - happy path: fill name/description, pick the model, submit -> asserts the redirect to /agents and the captured POST /api/agents payload - validation: empty required fields block submit (no request sent) - failure: forced create error surfaces an error toast, no redirect Groundwork introduced here (demand-driven, reused by later sub-stages): - stub captures mutation (POST/PUT/DELETE) bodies and exposes them via GET /__mock/requests; supports per-mutation error overrides; reset clears both - control.ts: setMutation, agentsCreateError, capturedRequests, lastRequest - helpers/select.ts: Radix <Select> driver Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Second Stage 2 feature (commit 2/8) — the chat streaming flow: - happy path: send a message, mock the A2A SSE reply -> asserts the user message, the streamed agent text, and a rendered tool-call block - empty state: a new chat shows "Start a conversation" - failure: an aborted stream surfaces an error toast, no agent reply Groundwork introduced here: - helpers/a2a.ts: mockAgentReply / mockAgentStreamError — page.route mock of the browser-side A2A SSE call (text/event-stream JSON-RPC frames) - stub: dynamic GET routes (agent detail, sessions-for-agent) + POST /api/sessions returning a session with an id (needed for the streamed contextId) - data-testid hooks: chat-input, chat-send (ChatInterface), tool-call (ToolDisplay) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Third Stage 2 feature (commit 3/8) — model config lifecycle: - create: pick provider (OpenAI) + model + API key -> asserts redirect to /models, success toast, and the captured POST /api/modelconfigs payload - edit-save: open the seeded config via the edit-model hook -> Save Changes -> asserts redirect + captured PUT /api/modelconfigs/<ref> Groundwork: - stub: /api/models keyed "OpenAI" (was lowercase); stock/configured provider endpoints (/api/modelproviderconfigs/*); GET /api/modelconfigs/<ns>/<name> detail - data-testid hooks: model-provider-select, model-select, model-api-key-input Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Fourth Stage 2 feature (commit 4/8) — create a RemoteMCPServer tool server: - happy: fill server name + URL, submit -> asserts redirect to /mcp and the captured POST /api/toolservers payload (type, url, name) - failure: forced 500 shows the inline "Couldn't create server" alert, no redirect Groundwork: stub GET /api/toolservertypes (blocking gate on /mcp/new). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Fifth Stage 2 feature (commit 5/8) — the harness create variant at /agents/new-harness: - happy: name + model, submit -> asserts redirect to /agents and the captured POST /api/agentharnesses (kind AgentHarness, backend openclaw) - validation: empty required fields block submit (no request) Groundwork: stub POST /api/agentharnesses returns data.agent (required by createAgentHarnessFromForm). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Sixth Stage 2 feature (commit 6/8) — delete an agent from the list: - happy: Agent options menu -> Delete -> confirm -> asserts the dialog closes and DELETE /api/agents/<ns>/<name> was captured - cancel: dismissing the dialog issues no DELETE No stub change (the generic mutation capture covers DELETE). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Seventh Stage 2 feature (commit 7/8) — prompt libraries: - empty state: /prompts (namespace kagent) with no libraries - create: name + a fragment key/content, submit -> asserts redirect to the detail page, success toast, and the captured POST /api/prompttemplates payload Groundwork: stub GET /api/prompttemplates (list) + GET /api/prompttemplates/<ns>/<name> (detail). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
Eighth Stage 2 feature (commit 8/8) — complete the first-run onboarding wizard: walks Welcome -> Model (select existing) -> Agent Setup -> Tools -> Review -> Finish, asserting the POST /api/agents at finalize, that the wizard dismisses to the Agents list, and that localStorage['kagent-onboarding'] flips to "true". No new stub routes (all endpoints already seeded). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Carlos Logroño Guerrero <carlos.logrono@solo.io>
1da788e to
3154d21
Compare
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Stage 2 of the Playwright UI E2E suite — the Stage 1 driver foundation plus the full set of multi-step feature flows built on top of it. Rebased directly on Stage 1 (#2180), so this branch stacks cleanly: once #2180 merges, this PR narrows to just the 9 commits below.
Foundation (helpers, stage 1):
POST /__mock/scenariosets a per-endpoint{ status, body }override;POST /__mock/resetclears them. Default stays the happy path.mocks/control.ts) surfaced as amockfixture:mock.noAgents(),mock.agentsError(), etc. The fixture resets the stub before every test, so scenarios never leak between tests.page.ts(loadPage,expectNoErrors,expectToast),nav.ts(dropdown-awaregotoView/gotoCreate),select.ts(combobox driver), anda2a.ts(chat/stream fixtures).Feature flows (stage 2): one spec per core UI journey, each asserting both UI state and the payload POSTed/PUT to the backend, plus empty/error/validation edge states.
tests/agents/create-agent.spec.tstests/chat/chat-session.spec.tstests/models/models.spec.tstests/mcp/mcp-server.spec.tstests/agents/create-harness.spec.tstests/agents/agent-lifecycle.spec.tstests/prompts/prompt-libraries.spec.tstests/onboarding/onboarding.spec.tsProduct code changes are limited to a handful of additive
data-testidhooks (chat input/send, tool-call card, combobox/dialog anchors) where role/text selectors were ambiguous — no behavior changed.Testing
Playwright boots the stub backend and dev server automatically and drives each flow through happy, empty, error, and validation states. Runs serially (
workers: 1) against the shared stub. Full suite: 43 passed locally.Change type
test — extends the Playwright E2E suite. Product changes limited to additive
data-testidhooks; no runtime behavior changed.Changelog
NONE