Skip to content

feat(ui-test): Playwright ui tests foundation stage 0#2180

Open
cjlg-soloio wants to merge 9 commits into
kagent-dev:mainfrom
cjlg-soloio:feat(ui)--Playwright-tests-foundation-stage-1
Open

feat(ui-test): Playwright ui tests foundation stage 0#2180
cjlg-soloio wants to merge 9 commits into
kagent-dev:mainfrom
cjlg-soloio:feat(ui)--Playwright-tests-foundation-stage-1

Conversation

@cjlg-soloio

@cjlg-soloio cjlg-soloio commented Jul 8, 2026

Copy link
Copy Markdown

Description

Adds the Stage 0 foundation for Playwright page-level E2E testing of the kagent UI, running against a mocked backend with no cluster required.

The suite targets the one gap nothing else covers — multi-step user flows across components:

Tool Covers
Storybook / Chromatic Component render states
Jest Logic
Cypress Page-load smoke
Playwright (this PR) Cross-component user flows

The core design challenge: the UI fetches data server-side via Next.js server actions, so browser-level page.route("**/api/**") intercepts nothing. Instead, this PR boots a dependency-free stub backend and redirects Next's server-side fetch to it via BACKEND_INTERNAL_URL — which getBackendUrl() in ui/src/lib/utils.ts already honors. Playwright's webServer block starts both the stub (:8899) and next dev (:8001) automatically.

This is foundation-only: config, stub backend, shared fixture, CI workflow, and a single smoke test. The helper/driver library and per-test scenarios land in Stage 1; feature flows in Stage 3 (see ui/playwright/README.md).

Files

New

File Purpose
ui/playwright.config.ts Boots stub + dev server; chromium project; CI-aware retries/workers; trace & screenshot on failure
ui/playwright/mocks/server.mjs Dependency-free stub backend (Node http only); serves happy-path payloads mirroring src/types/index.ts; exposes /__mock/health & /__mock/reset
ui/playwright/mocks/data.ts Typed spec-side data builders mirroring the stub's shapes
ui/playwright/fixtures/test.ts Shared test/expect fixture; resets stub per test and bypasses first-run onboarding
ui/playwright/tests/smoke.spec.ts Stage 0 smoke test — asserts the Agents list renders against the mock
ui/playwright/tsconfig.json Extends UI tsconfig with node + Playwright types
ui/playwright/README.md Test strategy, mocking rationale, conventions, roadmap
.github/workflows/ui-playwright.yaml Standalone CI workflow (paths-filtered to ui/**); installs chromium, runs test:pw, uploads report

Modified

  • ui/package.json@playwright/test dev dep + test:pw / test:pw:ui / test:pw:debug scripts
  • ui/package-lock.json — lockfile updates
  • ui/.gitignore — ignores playwright-report, playwright/test-results, playwright/.cache

Testing

cd ui
npm install
npx playwright install chromium   # first time only
npm run test:pw

Playwright starts the stub backend and dev server automatically. The smoke test passes when the home page renders the Agents, no "Error Encountered" state appears, and no uncaught page errors occur. CI runs the same on any ui/** change.

Change type

test / ci — new test infrastructure and CI workflow. No product or runtime code changed.

Changelog

Stage 1 of 3 playwright tests for ui

Copilot AI review requested due to automatic review settings July 8, 2026 16:06
@cjlg-soloio cjlg-soloio requested a review from peterj as a code owner July 8, 2026 16:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Introduces a foundational Playwright E2E test setup for the UI, including a dependency-free stub backend and CI workflow, to enable end-to-end coverage of multi-step user flows against mocked API responses.

Changes:

  • Added Playwright configuration, fixtures, and an initial smoke spec to validate the app loads against a stubbed backend.
  • Implemented a standalone Node HTTP stub backend plus typed mock builders for specs.
  • Wired Playwright into UI scripts, gitignore, and a dedicated GitHub Actions workflow.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
ui/playwright/tsconfig.json Adds Playwright-local TS config extending the UI tsconfig.
ui/playwright/tests/smoke.spec.ts Adds initial Stage 0 smoke test asserting Agents page loads without error state/page errors.
ui/playwright/README.md Documents Playwright scope, mocking approach, layout, and conventions.
ui/playwright/mocks/server.mjs Adds dependency-free stub backend serving /api/* responses used by server actions.
ui/playwright/mocks/data.ts Adds typed mock builders for assertions and future scenario plumbing.
ui/playwright/fixtures/test.ts Adds shared fixture to reset stub and bypass onboarding via localStorage init script.
ui/playwright.config.ts Adds Playwright runner config including webServer boot of stub + next dev.
ui/package.json Adds Playwright test scripts and @playwright/test dev dependency.
ui/package-lock.json Locks @playwright/test and updates Playwright packages.
ui/.gitignore Ignores Playwright report/output directories.
.github/workflows/ui-playwright.yaml Adds CI workflow to run Playwright tests on UI changes and upload reports.
Files not reviewed (1)
  • ui/package-lock.json: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ui/playwright.config.ts Outdated
Comment thread ui/playwright/mocks/server.mjs Outdated
Comment thread ui/playwright/fixtures/test.ts Outdated
Comment thread .github/workflows/ui-playwright.yaml Outdated
@cjlg-soloio cjlg-soloio changed the title Merge branch 'main' of https://github.com/kagent-dev/kagent into feat(ui)--Playwright-tests-foundation-stage-1 Playwright ui tests foundation stage 0 Jul 8, 2026
@cjlg-soloio cjlg-soloio changed the title Playwright ui tests foundation stage 0 feat(ui-test): Playwright ui tests foundation stage 0 Jul 8, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Jul 8, 2026
@cjlg-soloio cjlg-soloio force-pushed the feat(ui)--Playwright-tests-foundation-stage-1 branch from 4bed054 to 4e52362 Compare July 8, 2026 18:42
Comment thread ui/playwright.config.ts

export default defineConfig({
testDir: "./playwright/tests",
outputDir: "./playwright/test-results",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With workers: 1 this is a no-op, but raising workers before Stage 1 isolation lands will cause tests to race against the shared stub. Consider setting this to false until then.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good call — Fixed in 08b3cfc — set fullyParallel: false to match workers: 1, so both stay off until Stage 1 isolation lands. Thanks @mesutoezdil !

@mesutoezdil mesutoezdil Jul 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call — Fixed in 08b3cfc — set fullyParallel: false to match workers: 1, so both stay off until Stage 1 isolation lands. Thanks @mesutoezdil !

pls write your own sentences when interacting with me, not llm outputs. thx!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

my bad! I will keep it human moving forward 🤝

@mesutoezdil

Copy link
Copy Markdown
Contributor

dco is red

cjlg-soloio and others added 4 commits July 8, 2026 15:50
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>
@cjlg-soloio cjlg-soloio force-pushed the feat(ui)--Playwright-tests-foundation-stage-1 branch from 4e52362 to be5ee4e Compare July 8, 2026 19:56
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>
@cjlg-soloio cjlg-soloio force-pushed the feat(ui)--Playwright-tests-foundation-stage-1 branch from 08b3cfc to 5d1b617 Compare July 8, 2026 20:09
Comment thread ui/playwright/tsconfig.json Outdated
"compilerOptions": {
"types": ["node", "@playwright/test"]
},
"include": ["**/*.ts", "**/*.mjs"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

mjs without allowJs: true is a no-op, typescript won't check server.mjs

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

removed it

Comment thread ui/playwright.config.ts
projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
webServer: [
{
command: "node playwright/mocks/server.mjs",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

server.mjs reads STUB_PORT from env but this block doesn't pin it, so a shell-set STUB_PORT makes the stub bind to the wrong port and the health check times out

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I pinned STUB_PORT in the stub's webServer env so it always goes to the health endpoint or whatever BACKEND_INTERNAL_URL is set to

Comment thread ui/playwright.config.ts Outdated
{
command: "npm run dev",
url: APP_URL,
reuseExistingServer: !CI,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

if npm run dev is already running without BACKEND_INTERNAL_URL, reuseExistingServer reuses it and the stub is bypassed silently

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

changed it to boot always on BACKEND_INTERNAL_URL and made it fail loudly if 8001 is already taken

Comment thread ui/playwright/mocks/data.ts Outdated
} from "@/types";

export type Namespace = { name: string; status: string };
export type ToolServerListEntry = { ref: string; groupKind: string; discoveredTools: unknown[] };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

discoveredTools is typed as unknown[] but the real ToolServerResponse from @/types uses DiscoveredTool[]. the file comment promises compile-time drift detection, but this local type bypasses it

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

good catch! using RemoteMCPServerResponse now

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

again! pls write your own sentences when interacting with me, not llm outputs. thx!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I wrote that sentence! 😅

cjlg-soloio and others added 3 commits July 8, 2026 17:22
- 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants