import { expect, test, type Page } from "./fixtures"; import { gotoAppShell } from "./helpers/app"; import { expectNoBranchSwitcherInWorkspaceHeader, expectWorkspaceBranch, openChangesPanel, switchBranchFromChangesPanel, } from "./helpers/branch-switcher"; import { seedWorkspace } from "./helpers/seed-client"; import { getServerId } from "./helpers/server-id"; import { readWorktreeBranchInfo } from "./helpers/workspace"; import { switchWorkspaceViaSidebar, waitForSidebarHydration } from "./helpers/workspace-ui"; async function renameWorkspaceViaSidebar( page: Page, input: { workspaceId: string; title: string }, ): Promise { const serverId = getServerId(); const row = page.getByTestId(`sidebar-workspace-row-${serverId}:${input.workspaceId}`); await expect(row).toBeVisible({ timeout: 30_000 }); await row.hover(); const kebab = page.getByTestId(`sidebar-workspace-kebab-${serverId}:${input.workspaceId}`); await expect(kebab).toBeVisible({ timeout: 10_000 }); await kebab.click(); const renameItem = page.getByTestId( `sidebar-workspace-menu-rename-${serverId}:${input.workspaceId}`, ); await expect(renameItem).toBeVisible({ timeout: 10_000 }); await renameItem.click(); const modalPrefix = `sidebar-workspace-rename-modal-${serverId}:${input.workspaceId}`; const renameInput = page.getByTestId(`${modalPrefix}-input`); await expect(renameInput).toBeVisible({ timeout: 10_000 }); await renameInput.fill(input.title); await page.getByTestId(`${modalPrefix}-submit`).click(); await expect(renameInput).toHaveCount(0, { timeout: 15_000 }); } test.describe("Branch switcher", () => { // The first test after a spec-file switch can fail while the shared daemon // releases stale sessions from the previous spec; one retry stabilizes it. test.describe.configure({ retries: 1 }); test("switches the workspace branch from the git diff panel for an opaque workspace id", async ({ page, }) => { test.setTimeout(90_000); const serverId = getServerId(); const workspace = await seedWorkspace({ repoPrefix: "branch-switch-", repo: { branches: ["main", "dev"] }, }); try { await gotoAppShell(page); await waitForSidebarHydration(page); await switchWorkspaceViaSidebar({ page, serverId, workspaceId: workspace.workspaceId }); await openChangesPanel(page); await expectWorkspaceBranch(page, "main"); await switchBranchFromChangesPanel(page, { from: "main", to: "dev" }); await expectWorkspaceBranch(page, "dev"); await expect .poll( async () => (await readWorktreeBranchInfo({ worktreePath: workspace.repoPath })).currentBranch, { timeout: 30_000 }, ) .toBe("dev"); } finally { await workspace.cleanup(); } }); test("a custom workspace title stays in the header while the diff panel switches the real branch", async ({ page, }) => { test.setTimeout(90_000); const serverId = getServerId(); const workspace = await seedWorkspace({ repoPrefix: "branch-coherence-", repo: { branches: ["main", "dev"] }, }); try { expect(workspace.workspaceName).toBe("main"); await gotoAppShell(page); await waitForSidebarHydration(page); await switchWorkspaceViaSidebar({ page, serverId, workspaceId: workspace.workspaceId }); const customTitle = "Payments Refactor"; await renameWorkspaceViaSidebar(page, { workspaceId: workspace.workspaceId, title: customTitle, }); // The header shows the custom title verbatim (a plain static title), never a // branch name, and the branch switcher does not live in the header. const headerTitle = page .getByTestId("workspace-header-title") .filter({ visible: true }) .first(); await expect(headerTitle).toHaveText(customTitle, { timeout: 30_000 }); await expectNoBranchSwitcherInWorkspaceHeader(page); // The diff panel's switcher tracks the real branch ("main"), not the title, // and switching it checks out the real branch on disk. await openChangesPanel(page); await expectWorkspaceBranch(page, "main"); await switchBranchFromChangesPanel(page, { from: "main", to: "dev" }); await expectWorkspaceBranch(page, "dev"); // The custom title is unaffected by the branch switch. await expect(headerTitle).toHaveText(customTitle, { timeout: 30_000 }); await expect .poll( async () => (await readWorktreeBranchInfo({ worktreePath: workspace.repoPath })).currentBranch, { timeout: 30_000 }, ) .toBe("dev"); } finally { await workspace.cleanup(); } }); });