diff --git a/packages/app/e2e/browser/new-workspace-navigation-guard.spec.ts b/packages/app/e2e/browser/new-workspace-navigation-guard.spec.ts index 0bbe9c3286..02079f2a5d 100644 --- a/packages/app/e2e/browser/new-workspace-navigation-guard.spec.ts +++ b/packages/app/e2e/browser/new-workspace-navigation-guard.spec.ts @@ -5,9 +5,12 @@ import { archiveLocalWorkspaceFromDaemon, archiveWorkspaceFromDaemon, connectNewWorkspaceDaemonClient, + countWorkspaceAgents, + countWorkspaceTerminals, delayBrowserWorkspaceCreatedResponse, openNewWorkspaceComposer, openProjectViaDaemon, + waitForCreatedWorkspace, } from "../support/helpers/new-workspace"; import { createTempGitRepo } from "../support/helpers/workspace"; import { expectAppRoute } from "../support/helpers/route-assertions"; @@ -41,30 +44,6 @@ const TERMINAL_PROFILE: TerminalProfile = { args: ["-c", 'echo captured: "$0"; sleep 120', "{{{prompt}}}"], }; -async function findUnknownWorkspace( - client: Awaited>, - knownWorkspaceIds: ReadonlySet, -) { - const payload = await client.fetchWorkspaces(); - return payload.entries.find((candidate) => !knownWorkspaceIds.has(candidate.id)) ?? null; -} - -async function countWorkspaceAgents( - client: Awaited>, - workspaceId: string, -): Promise { - const payload = await client.fetchAgents({ filter: { includeArchived: true } }); - return payload.entries.filter((entry) => entry.agent.workspaceId === workspaceId).length; -} - -async function countWorkspaceTerminals( - client: Awaited>, - workspaceId: string, -): Promise { - const payload = await client.listTerminals(undefined, undefined, { workspaceId }); - return payload.terminals.length; -} - test.describe("New workspace navigation guard", () => { let client: Awaited>; const localWorkspaceIds = new Set(); @@ -138,16 +117,7 @@ test.describe("New workspace navigation guard", () => { // Wait for the agent the background path is responsible for creating, then prove the app // never followed it. Polling the daemon rather than the URL keeps this ordering explicit. - await expect - .poll(async () => (await findUnknownWorkspace(client, knownWorkspaceIds))?.id ?? null, { - timeout: 60_000, - }) - .not.toBeNull(); - - const createdWorkspace = await findUnknownWorkspace(client, knownWorkspaceIds); - if (!createdWorkspace) { - throw new Error("Created workspace disappeared from the daemon"); - } + const createdWorkspace = await waitForCreatedWorkspace(client, knownWorkspaceIds); createdWorktreeDirectories.add(createdWorkspace.workspaceDirectory); await expect @@ -217,16 +187,7 @@ test.describe("New workspace navigation guard", () => { }); createDelay.release(); - await expect - .poll(async () => (await findUnknownWorkspace(client, knownWorkspaceIds))?.id ?? null, { - timeout: 60_000, - }) - .not.toBeNull(); - - const createdWorkspace = await findUnknownWorkspace(client, knownWorkspaceIds); - if (!createdWorkspace) { - throw new Error("Created workspace disappeared from the daemon"); - } + const createdWorkspace = await waitForCreatedWorkspace(client, knownWorkspaceIds); createdWorktreeDirectories.add(createdWorkspace.workspaceDirectory); // Wait for the terminal, not just the workspace. The launch path spawns the terminal and diff --git a/packages/app/e2e/support/helpers/new-workspace.ts b/packages/app/e2e/support/helpers/new-workspace.ts index f188c47e5c..0b453fb554 100644 --- a/packages/app/e2e/support/helpers/new-workspace.ts +++ b/packages/app/e2e/support/helpers/new-workspace.ts @@ -689,3 +689,50 @@ export async function delayBrowserWorkspaceCreatedResponse( waitForCreateRequest: () => createRequestSeen, }; } + +type WorkspaceEntry = Awaited< + ReturnType +>["entries"][number]; + +/** + * Waits for a workspace the caller did not already know about, and returns it. Tests that create a + * workspace without navigating to it have no route to assert on, so the daemon's own list is the + * signal that creation finished. + */ +export async function waitForCreatedWorkspace( + client: NewWorkspaceDaemonClient, + knownWorkspaceIds: ReadonlySet, + options?: { timeout?: number }, +): Promise { + let created: WorkspaceEntry | undefined; + await expect + .poll( + async () => { + const payload = await client.fetchWorkspaces(); + created = payload.entries.find((entry) => !knownWorkspaceIds.has(entry.id)); + return created !== undefined; + }, + { timeout: options?.timeout ?? 60_000 }, + ) + .toBe(true); + if (!created) { + throw new Error("Workspace list reported a new workspace but it could not be read back"); + } + return created; +} + +export async function countWorkspaceAgents( + client: NewWorkspaceDaemonClient, + workspaceId: string, +): Promise { + const payload = await client.fetchAgents({ filter: { includeArchived: true } }); + return payload.entries.filter((entry) => entry.agent.workspaceId === workspaceId).length; +} + +export async function countWorkspaceTerminals( + client: NewWorkspaceDaemonClient, + workspaceId: string, +): Promise { + const payload = await client.listTerminals(undefined, undefined, { workspaceId }); + return payload.terminals.length; +}