import { expect, test } from "../../fixtures/test-base"; import { createFolderTestRepository, findFolderTestWorktree, mockFolderAvailability, } from "../../helpers/open-task-folder"; import { SessionPage } from "../../pages/session-page"; // @covers AC-TASKS-OPEN-FOLDER-001.1, AC-TASKS-OPEN-FOLDER-001.3 test("editor dropdown opens the folder without configured editors and recovers from errors", async ({ testPage, apiClient, seedData, }) => { const task = await apiClient.createTaskWithAgent( seedData.workspaceId, "Open task folder", seedData.agentProfileId, { description: "/e2e:simple-message", workflow_id: seedData.workflowId, workflow_step_id: seedData.startStepId, repository_ids: [seedData.repositoryId], executor_profile_id: seedData.worktreeExecutorProfileId, }, ); await testPage.route("**/api/v1/editors", (route) => route.fulfill({ json: { editors: [], folder_opening_available: true } }), ); await testPage.goto(`/t/${task.id}`); const session = new SessionPage(testPage); await session.waitForLoad(); await session.waitForChatIdle(); let attempts = 0; const requests: string[] = []; await testPage.route("**/api/v1/task-sessions/*/open-folder", async (route) => { requests.push(route.request().url()); attempts++; await route.fulfill({ status: attempts === 1 ? 500 : 200, json: attempts === 1 ? { error: "failed to open folder" } : { success: true }, }); }); await expect(testPage.getByTestId("open-task-folder")).toHaveCount(0); await expect(testPage.getByTestId("editors-menu-open")).toBeDisabled(); const trigger = testPage.getByTestId("editors-menu-list"); await expect(trigger).toHaveAccessibleName("Editor and folder actions"); await expect(trigger).toBeEnabled(); expect((await trigger.boundingBox())!.height).toBeCloseTo(28, 0); await trigger.click(); const folder = testPage.getByRole("menuitem", { name: "Open folder", exact: true }); await expect(folder).toBeVisible(); await testPage.screenshot({ path: test.info().outputPath("desktop-folder-menu.png"), animations: "disabled", }); await folder.click(); await expect(testPage.getByText("Failed to open folder", { exact: true })).toBeVisible(); await trigger.click(); await folder.click(); await expect.poll(() => attempts).toBe(2); expect( requests.every((url) => url.endsWith(`/task-sessions/${task.session_id}/open-folder`)), ).toBe(true); await trigger.click(); await expect(folder).toBeEnabled(); }); // @covers AC-TASKS-OPEN-FOLDER-001.2 test("desktop folder picker opens only the selected repository", async ({ testPage, apiClient, seedData, backend, }) => { const repository = await createFolderTestRepository( apiClient, seedData.workspaceId, backend.tmpDir, ); const task = await apiClient.createTaskWithAgent( seedData.workspaceId, "Desktop folder picker", seedData.agentProfileId, { description: "/e2e:simple-message", workflow_id: seedData.workflowId, workflow_step_id: seedData.startStepId, repository_ids: [seedData.repositoryId, repository.id], executor_profile_id: seedData.worktreeExecutorProfileId, }, ); await mockFolderAvailability(testPage, true); await testPage.goto(`/t/${task.id}`); const session = new SessionPage(testPage); await session.waitForLoad(); await session.waitForChatIdle(); if (!task.session_id) throw new Error("Task has no session"); const worktreeId = await findFolderTestWorktree( apiClient, task.id, task.session_id, repository.id, ); const payloads: unknown[] = []; await testPage.route("**/api/v1/task-sessions/*/open-folder", async (route) => { payloads.push(route.request().postDataJSON()); await route.fulfill({ json: { success: true } }); }); const trigger = testPage.getByTestId("editors-menu-list"); await trigger.focus(); await testPage.keyboard.press("Enter"); await testPage.getByRole("menuitem", { name: "Open folder", exact: true }).focus(); await testPage.keyboard.press("Enter"); const picker = testPage.getByRole("dialog", { name: "Choose a folder" }); await expect(picker).toBeVisible(); await testPage.screenshot({ path: test.info().outputPath("desktop-folder-picker.png"), animations: "disabled", }); await picker.getByRole("button", { name: "Cancel", exact: true }).click(); await expect(picker).not.toBeVisible(); await expect(trigger).toBeFocused(); expect(payloads).toEqual([]); await trigger.click(); await testPage.getByRole("menuitem", { name: "Open folder", exact: true }).click(); await picker.getByRole("button", { name: /Folder second repo/ }).click(); await expect.poll(() => payloads).toEqual([{ worktree_id: worktreeId }]); await expect(picker).not.toBeVisible(); }); test("missing host folder opener disables the action before any picker opens", async ({ testPage, apiClient, seedData, }) => { const task = await apiClient.createTaskWithAgent( seedData.workspaceId, "Unavailable folder opener", seedData.agentProfileId, { description: "/e2e:simple-message", workflow_id: seedData.workflowId, workflow_step_id: seedData.startStepId, repository_ids: [seedData.repositoryId], executor_profile_id: seedData.worktreeExecutorProfileId, }, ); await mockFolderAvailability(testPage, false); let requests = 0; await testPage.route("**/api/v1/task-sessions/*/open-folder", async (route) => { requests++; await route.fulfill({ json: { success: true } }); }); await testPage.goto(`/t/${task.id}`); const session = new SessionPage(testPage); await session.waitForLoad(); await session.waitForChatIdle(); await testPage.getByTestId("editors-menu-list").click(); await expect(testPage.getByRole("menuitem", { name: "Open folder", exact: true })).toBeDisabled(); await expect(testPage.getByRole("dialog", { name: "Choose a folder" })).not.toBeVisible(); expect(requests).toBe(0); });