mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
* chore(e2e): begin Playwright test-quality pass
* test(e2e): migrate terminal-performance spec onto TerminalE2EHarness
Replace the hand-rolled daemon-client lifecycle (connectTerminalClient +
openProject + createTerminal/navigateToTerminal/killTerminal) with the shared
TerminalE2EHarness, matching terminal-keystroke-stress.spec.ts. The spec now
seeds the workspace and terminals through the harness vocabulary instead of
duplicating setup, cutting the file by ~40 lines with no behavior change.
* test(e2e): extract shared mock-agent workspace helper
Five specs reimplemented the same setup: seed a temp repo, open it as a
project, create a mock-provider agent, then navigate to its workspace route.
Extract seedMockAgentWorkspace + openAgentRoute into helpers/mock-agent.ts and
migrate the rewind-menu and user-message-contract UI-contract specs onto them,
dropping their local getServerId/openAgent/inline-seed duplication.
* test(e2e): migrate terminal tab rename spec onto TerminalE2EHarness
Replace the spec's hand-rolled daemon client setup (connectTerminalClient +
openProject + createTerminal + navigateToTerminal + manual cleanup) with the
shared TerminalE2EHarness and withTerminalInApp helpers, matching the other
terminal specs. Behavior and assertions are unchanged.
* test(e2e): share openProjectViaDaemon across sidebar specs
Both sidebar-workspace and sidebar-workspace-rename rolled their own
identical openProjectViaDaemon helper against the workspace-setup daemon
client. Promote a single shared helper into helpers/workspace-setup.ts
(returning id/name/workspaceDirectory) and have seedProjectForWorkspaceSetup
delegate to it, removing the duplicated open-project logic.
* test(e2e): migrate client-slash-commands spec onto shared mock-agent helper
Replace the spec's hand-rolled openProject/createReadyMockAgent/
openActiveAgentTab/getServerId setup with seedMockAgentWorkspace and
openAgentRoute from helpers/mock-agent, matching the rewind-menu and
user-message-contract specs. Drops ~60 lines of duplicated daemon-client
wiring; the test bodies now read as domain intent.
* test(e2e): converge remaining workspace-setup specs onto shared daemon helpers
Replace the last inline openProject + null-check blocks with the shared
openProjectViaDaemon helper in the file-explorer-collapse and pr-pane specs,
and route workspace-setup-runtime project registration through
seedProjectForWorkspaceSetup. Behavior is identical; the seeding vocabulary now
lives entirely in helpers/workspace-setup.ts.
* test(e2e): migrate composer-autocomplete spec onto shared mock-agent helper
Replace the spec's hand-rolled daemon client setup (connectTerminalClient +
openProject + createAgent + route building + bespoke cleanup) with
seedMockAgentWorkspace + openAgentRoute from helpers/mock-agent, matching the
client-slash-commands migration. Drops the local getServerId, openProject, and
cleanupWithin helpers.
* test(e2e): migrate codex-plan-approval spec onto shared mock-agent helper
Replace the hand-rolled daemon client, project open, agent creation, and
manual route building with seedMockAgentWorkspace + openAgentRoute. The spec
now reads as intent: seed a mock agent, open it, approve the plan, assert the
panel clears.
* test(e2e): converge daemon-client bootstrap onto one shared factory
The five e2e helpers each rolled their own daemon-client connect logic —
duplicating the ws-url resolution, node WebSocket factory, client
construction, and connect call, plus a redeclared config interface.
Extract a single connectDaemonClient factory in daemon-client-loader.ts
that each helper delegates to with its own typed client interface. This
also propagates the port-6767 safety guard (previously only in two
helpers) to all of them, so no test client can target the developer
daemon. Specs are untouched; behavior is preserved.
* test(e2e): promote shared daemon seed client out of terminal-perf helper
The general-purpose E2E daemon client (workspace/agent/terminal seeding and
driving) had grown inside terminal-perf.ts under the name
TerminalPerfDaemonClient, even though most consumers — mock-agent, composer,
rewind-flow, and the launcher/title-handoff specs — have nothing to do with
terminal performance. Move the interface and its connect factory into a
neutrally-named helpers/seed-client.ts (SeedDaemonClient / connectSeedClient)
and point every consumer at it. terminal-perf.ts keeps only its terminal page
helpers. Pure rename/relocate; no behavior change.
* test(e2e): converge E2E_SERVER_ID lookup onto one shared helper
The server-id env accessor was copy-pasted as a local `getServerId`
function in six helpers and five specs (plus a `requireServerId` twin in
the sidebar helper). Extract a single `helpers/server-id.ts` accessor and
route every caller through it, so a new spec imports the vocabulary
instead of re-deriving it. Pure refactor — identical lookup behavior.
* test(e2e): finish converging server-id lookup onto the shared helper
The previous pass extracted helpers/server-id.ts but only routed callers
that wrapped the env read in a local function. Eight specs still re-derived
the lookup inline — some as their own copy-pasted getSeededServerId/
getE2EServerId functions, some as bare `process.env.E2E_SERVER_ID` blocks
inside test bodies. Route them all through getServerId() so a new spec
imports the vocabulary instead of re-deriving it. Pure refactor — identical
lookup behavior; daemon-port reads are left untouched.
* test(e2e): converge workspace seeding onto a shared seedWorkspace helper
Extract the repeated temp-repo + seed-client + openProject bootstrap into
seedWorkspace() in helpers/seed-client.ts, returning a {client, repoPath,
workspaceId, cleanup} handle. seedMockAgentWorkspace and the agent-title-handoff
spec now build on it instead of re-rolling the trio, so the open-project error
handling and teardown live in one place.
* test(e2e): converge launcher-tab spec onto the shared seedWorkspace helper
Replace the hand-rolled createTempGitRepo + connectSeedClient + openProject
trio in beforeAll with seedWorkspace(), and drop the redundant second seed
client in the terminal-title block in favor of the shared workspace.client.
* test(e2e): converge file-explorer-collapse onto the shared seedWorkspace helper
Teach seedWorkspace to forward createTempGitRepo options (files/branches/
remote) so file-seeding specs can drop their hand-rolled
createTempGitRepo + connect + openProjectViaDaemon trio. Migrate
file-explorer-collapse onto it, removing its bespoke WorkspaceSetup client setup.
* test(e2e): converge non-git project setup onto a shared workspace helper
Promote the non-git createTempDirectory out of sidebar-workspace.spec.ts
into helpers/workspace.ts next to createTempGitRepo, and dedupe the
copy-pasted temp-root resolution (workspace.ts, with-workspace.ts, and the
spec) into one shared resolveTempRoot(). The spec drops its low-level
node:fs imports and reads in domain terms.
* test(e2e): converge agent-tab-rename spec onto the shared seedWorkspace helper
Drop the bespoke daemon-client + temp-repo + manual-cleanup trio in
workspace-agent-tab-rename and seed through seedWorkspace, matching the
other converged specs. createIdleAgent now takes a minimal structural
client interface so it accepts either the archive-tab client or the
shared seed client (type-only; the existing archive-tab callers are
unchanged). Verified by running the spec on Desktop Chrome.
* test(e2e): converge pane-remount spec onto the shared seedWorkspace helper
Drop the bespoke archive-tab daemon client + temp-repo + manual-cleanup
trio in workspace-pane-remount and seed through seedWorkspace, matching
the other converged specs. createIdleAgent already accepts the shared
seed client structurally, so the only behavior change is teardown now
goes through workspace.cleanup(). Verified by running the spec on
Desktop Chrome.
* test(e2e): converge sidebar-workspace-rename onto the shared seedWorkspace helper
Expose workspaceName and workspaceDirectory on SeededWorkspace (sourced from
the open-project response) so branch-rename specs can read the resolved branch
name and checkout directory without a bespoke client. Migrate
sidebar-workspace-rename off its hand-rolled connectWorkspaceSetupClient +
createTempGitRepo + openProjectViaDaemon trio, dropping the per-test
client/repo cleanup in favor of seedWorkspace's single cleanup handle.
* test(e2e): converge sidebar-workspace list onto the shared seedWorkspace helper
Migrate all five "Sidebar workspace list" tests off their hand-rolled
connectWorkspaceSetupClient + createTempGitRepo/createTempDirectory +
openProjectViaDaemon trio onto seedWorkspace, collapsing each test's
client/repo cleanup into the single seedWorkspace cleanup handle and dropping
the spec-local setGitHubRemote/execSync machinery.
Two small helper additions make the full file converge:
- seedWorkspace gains a `git: false` option that seeds a plain non-git
directory (via createTempDirectory) instead of a git repo, so the non-git
project test gets the same single-handle treatment.
- createTempGitRepo's configureRemote now relabels origin to a display URL
when both `withRemote` and `originUrl` are given: it sets up the local
tracking remote, pushes, then `git remote set-url` to the GitHub URL. This
reproduces the prior withRemote + setGitHubRemote git state exactly (real
local tracking refs, GitHub origin URL for project grouping) in one fixture
call, so the GitHub-remote tests are behavior-preserving.
* test(e2e): converge projects-settings onto the shared seedWorkspace helper
Replace the per-fixture connectNewWorkspaceDaemonClient + createTempGitRepo +
openProjectViaDaemon trio with seedWorkspace(), and expose the daemon's
projectId/projectDisplayName on SeededWorkspace so fixtures can read the
project label directly. All 9 specs pass.
* test(e2e): converge composer-attachments onto the shared seedWorkspace helper
Replace the inline connectNewWorkspaceDaemonClient + createTempGitRepo +
openProjectViaDaemon trio in the "composer is locked while new workspace agent
is being created" test with a single seedWorkspace() call, dropping the manual
client.close()/repo.cleanup() teardown in favor of workspace.cleanup(). The
test still passes against a real daemon.
* test(e2e): converge settings-toggle-tab-regression onto the shared seedWorkspace helper
Both tests rolled their own daemon client + temp git repo + manual agent
archive cleanup. Replace that trio with seedWorkspace(), drive idle agents
through workspace.client, and route off workspace.repoPath, leaving cleanup
to workspace.cleanup(). Matches the pattern already used by
workspace-pane-remount and workspace-agent-tab-rename.
* test(e2e): converge workspace-navigation-regression onto the shared seedWorkspace helper
Replace the bespoke connect/openProject/createTempGitRepo/archive trios in
the reconnect, cold-URL, and sidebar-navigation tests with seedWorkspace(),
matching the other migrated specs. Cleanup collapses to workspace.cleanup().
* test(e2e): drop orphaned dead code from agent-bottom-anchor helper
The agent-bottom-anchor spec was removed in a prior cleanup, but its
helper kept a private daemon-client interface and connect fn (duplicating
the shared seed client), seedBottomAnchorAgent, the reply-message builders,
and several scroll helpers that no spec references anymore. Only
readScrollMetrics, expectNearBottom, and waitForContentGrowth are still
used (by agent-stream.ts); keep those and delete the rest.
* test(e2e): converge archive-tab daemon client onto the shared seed client
Fold archiveAgent and fetchAgentHistory into the canonical SeedDaemonClient
and route the archive-tab and sessions-empty specs through connectSeedClient,
deleting the bespoke ArchiveTabDaemonClient wrapper. Both specs only need
general-purpose agent seed/drive operations, so they now share one client
interface instead of re-declaring their own.
* test(e2e): derive workspace-setup daemon client from the real client type
Replace the hand-rolled WorkspaceSetupDaemonClient interface with a
Pick<InternalDaemonClient, ...> over the real daemon client, matching the
pattern already used by the new-workspace helper. The 45-line re-declaration
of RPC method signatures could silently drift from the protocol; deriving it
from the source of truth keeps the test client honest and shrinks the helper.
* test(e2e): converge duplicated escapeRegex onto one shared helper
Seven byte-identical copies of escapeRegex lived across three specs and four
helpers. Extract a single helpers/regex.ts and route every caller through it,
so the suite has one regex-escaping primitive instead of re-declaring the same
pure function per file.
* test(e2e): converge E2E_DAEMON_PORT resolution onto one shared accessor
The isolated test daemon's port was re-read from the environment in ~10
places — three local helper functions in specs, two inline blocks, and
several helper modules — each repeating the "throw if unset" check and,
in the safety-critical paths, the "refuse the developer daemon (6767)"
guard.
Add helpers/daemon-port.ts exporting getE2EDaemonPort(), mirroring
getServerId(), and route every reader through it. The 6767 guard now
applies everywhere: the test port is never legitimately 6767, so
refusing it uniformly keeps every spec off the developer daemon.
While here, route the two inline port-regex escapes through the existing
escapeRegex helper instead of hand-inlining the same pattern.
* test(e2e): capture create-agent cwd via shared WS-frame helper
workspace-cwd's draft-agent test rolled its own request recorder by
monkeypatching WebSocket.prototype.send and stashing frames on a
window global, then reading them back through page.evaluate. Replace
that with captureWsSessionFrames — the same outbound-frame helper four
other specs already use for create_agent_request — so the assertion
reads the cwd directly and the spec drops the browser-side internals
reach-around. No behavior change; the three cwd cases still pass.
* test(e2e): converge daemon WS-route regex onto one shared helper
Five sites rebuilt the Playwright routeWebSocket matcher for the E2E
daemon inline as `new RegExp(`:${escapeRegex(getE2EDaemonPort())}\b`)`
(new-workspace, project-settings, composer-autocomplete, and two in
workspace-navigation-regression), and startup-dsl rolled the same regex
for arbitrary blocked test-host ports. Add daemonWsRoutePattern() and
wsRoutePatternForPort(port) to daemon-port.ts — whose docstring already
promised route patterns live here — and point every site at them.
The emitted regex is byte-identical, so interception behavior is
unchanged; composer-autocomplete still passes. Drops the now-unused
escapeRegex/getE2EDaemonPort imports and the redundant daemonPort locals.
123 lines
4.0 KiB
TypeScript
123 lines
4.0 KiB
TypeScript
import { test } from "./fixtures";
|
|
import {
|
|
openPrPane,
|
|
expectPrPaneTitle,
|
|
expectPrPaneState,
|
|
expectPrPaneCheckSummary,
|
|
expectPrPaneActivityCount,
|
|
} from "./helpers/pr-pane";
|
|
import { gotoWorkspace } from "./helpers/launcher";
|
|
import { hasGithubAuth, createTempGithubRepo, type GhRepoFixture } from "./helpers/github-fixtures";
|
|
import {
|
|
connectWorkspaceSetupClient,
|
|
openProjectViaDaemon,
|
|
type WorkspaceSetupDaemonClient,
|
|
} from "./helpers/workspace-setup";
|
|
|
|
const GITHUB_AUTH = hasGithubAuth();
|
|
|
|
test.describe("PR pane", () => {
|
|
test.describe.configure({ retries: 1 });
|
|
|
|
let seedClient: WorkspaceSetupDaemonClient;
|
|
let repoFixture: GhRepoFixture;
|
|
const workspaceByTitle = new Map<string, string>();
|
|
|
|
test.beforeAll(async () => {
|
|
if (!GITHUB_AUTH) return;
|
|
|
|
seedClient = await connectWorkspaceSetupClient();
|
|
|
|
repoFixture = await createTempGithubRepo({
|
|
category: "pr-pane",
|
|
prs: [
|
|
{ title: "Review selected start ref", state: "open" },
|
|
{ title: "Merged feature branch", state: "merged" },
|
|
{ title: "Closed without merge", state: "closed" },
|
|
{ title: "Work in progress", state: "draft" },
|
|
{
|
|
title: "PR with mixed checks",
|
|
state: "open",
|
|
checks: [
|
|
{ context: "build-1", state: "success" },
|
|
{ context: "build-2", state: "success" },
|
|
{ context: "deploy", state: "failure" },
|
|
{ context: "security", state: "pending" },
|
|
],
|
|
},
|
|
{ title: "PR with reviews", state: "open", commentCount: 3 },
|
|
{ title: "PR with no checks", state: "open" },
|
|
],
|
|
});
|
|
|
|
for (const pr of repoFixture.prs) {
|
|
const workspace = await openProjectViaDaemon(seedClient, pr.localPath);
|
|
workspaceByTitle.set(pr.title, workspace.id);
|
|
}
|
|
});
|
|
|
|
test.afterAll(async () => {
|
|
await repoFixture?.cleanup().catch(() => undefined);
|
|
await seedClient?.close().catch(() => undefined);
|
|
});
|
|
|
|
test.beforeEach(async () => {
|
|
test.skip(!GITHUB_AUTH, "Requires GitHub authentication (gh auth login)");
|
|
test.setTimeout(60_000);
|
|
});
|
|
|
|
test("renders an open PR with title, state, and repo line", async ({ page }) => {
|
|
await gotoWorkspace(page, workspaceByTitle.get("Review selected start ref")!);
|
|
await openPrPane(page);
|
|
|
|
await expectPrPaneTitle(page, "Review selected start ref");
|
|
await expectPrPaneState(page, "open");
|
|
});
|
|
|
|
test("renders merged state label and icon", async ({ page }) => {
|
|
await gotoWorkspace(page, workspaceByTitle.get("Merged feature branch")!);
|
|
await openPrPane(page);
|
|
|
|
await expectPrPaneState(page, "merged");
|
|
await expectPrPaneTitle(page, "Merged feature branch");
|
|
});
|
|
|
|
test("renders closed state label and icon", async ({ page }) => {
|
|
await gotoWorkspace(page, workspaceByTitle.get("Closed without merge")!);
|
|
await openPrPane(page);
|
|
|
|
await expectPrPaneState(page, "closed");
|
|
await expectPrPaneTitle(page, "Closed without merge");
|
|
});
|
|
|
|
test("renders draft state label and icon", async ({ page }) => {
|
|
await gotoWorkspace(page, workspaceByTitle.get("Work in progress")!);
|
|
await openPrPane(page);
|
|
|
|
await expectPrPaneState(page, "draft");
|
|
await expectPrPaneTitle(page, "Work in progress");
|
|
});
|
|
|
|
test("renders check pills with correct passed/failed/pending counts", async ({ page }) => {
|
|
await gotoWorkspace(page, workspaceByTitle.get("PR with mixed checks")!);
|
|
await openPrPane(page);
|
|
|
|
await expectPrPaneCheckSummary(page, { passed: 2, failed: 1, pending: 1 });
|
|
});
|
|
|
|
test("renders activity rows with correct count", async ({ page }) => {
|
|
await gotoWorkspace(page, workspaceByTitle.get("PR with reviews")!);
|
|
await openPrPane(page);
|
|
|
|
await expectPrPaneActivityCount(page, 3);
|
|
});
|
|
|
|
test("renders gracefully with zero checks", async ({ page }) => {
|
|
await gotoWorkspace(page, workspaceByTitle.get("PR with no checks")!);
|
|
await openPrPane(page);
|
|
|
|
await expectPrPaneCheckSummary(page, { passed: 0, failed: 0, pending: 0 });
|
|
await expectPrPaneTitle(page, "PR with no checks");
|
|
});
|
|
});
|