Fix Playwright workspace isolation (#1627)
* Fix Playwright workspace isolation * Clean up empty project E2E cleanup * Clean up worktree restore E2E projects
This commit is contained in:
@@ -12,7 +12,7 @@ import { startRunningMockAgent } from "./helpers/composer";
|
||||
test.describe("Agent stream UI", () => {
|
||||
test("auto-scroll sticks to bottom across token bursts", async ({ page }) => {
|
||||
test.setTimeout(120_000);
|
||||
const { client, repo } = await startRunningMockAgent(page, {
|
||||
const agent = await startRunningMockAgent(page, {
|
||||
prefix: "stream-scroll-",
|
||||
model: "one-minute-stream",
|
||||
prompt: "Stream for auto-scroll test.",
|
||||
@@ -21,14 +21,13 @@ test.describe("Agent stream UI", () => {
|
||||
await awaitAssistantMessage(page);
|
||||
await expectScrollFollowsNewContent(page);
|
||||
} finally {
|
||||
await client.close();
|
||||
await repo.cleanup();
|
||||
await agent.cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
test("working-indicator transitions to copy-button when stream ends", async ({ page }) => {
|
||||
test.setTimeout(60_000);
|
||||
const { client, repo } = await startRunningMockAgent(page, {
|
||||
const agent = await startRunningMockAgent(page, {
|
||||
prefix: "stream-indicator-",
|
||||
model: "ten-second-stream",
|
||||
prompt: "Stream briefly for indicator transition test.",
|
||||
@@ -39,8 +38,7 @@ test.describe("Agent stream UI", () => {
|
||||
await expectAgentIdle(page, 30_000);
|
||||
await expectTurnCopyButton(page);
|
||||
} finally {
|
||||
await client.close();
|
||||
await repo.cleanup();
|
||||
await agent.cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -26,15 +26,26 @@ import {
|
||||
test.describe("Archive tab reconciliation", () => {
|
||||
let client: Awaited<ReturnType<typeof connectSeedClient>>;
|
||||
let tempRepo: { path: string; cleanup: () => Promise<void> };
|
||||
let projectId: string;
|
||||
let workspaceId: string;
|
||||
|
||||
test.describe.configure({ timeout: 300_000 });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
tempRepo = await createTempGitRepo("archive-tab-");
|
||||
client = await connectSeedClient();
|
||||
const created = await client.createWorkspace({
|
||||
source: { kind: "directory", path: tempRepo.path },
|
||||
});
|
||||
if (!created.workspace) {
|
||||
throw new Error(created.error ?? `Failed to create workspace ${tempRepo.path}`);
|
||||
}
|
||||
projectId = created.workspace.projectId;
|
||||
workspaceId = created.workspace.id;
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await client?.removeProject(projectId).catch(() => undefined);
|
||||
await client?.close().catch(() => undefined);
|
||||
await tempRepo?.cleanup();
|
||||
});
|
||||
@@ -42,10 +53,12 @@ test.describe("Archive tab reconciliation", () => {
|
||||
test("non-UI archive prunes the archived tab across open pages and reload", async ({ page }) => {
|
||||
const archived = await createIdleAgent(client, {
|
||||
cwd: tempRepo.path,
|
||||
workspaceId,
|
||||
title: `cli-archive-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
const surviving = await createIdleAgent(client, {
|
||||
cwd: tempRepo.path,
|
||||
workspaceId,
|
||||
title: `cli-control-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
const passivePage = await page.context().newPage();
|
||||
@@ -81,10 +94,12 @@ test.describe("Archive tab reconciliation", () => {
|
||||
test("Sessions archive prunes the archived tab across open pages", async ({ page }) => {
|
||||
const archived = await createIdleAgent(client, {
|
||||
cwd: tempRepo.path,
|
||||
workspaceId,
|
||||
title: `ui-archive-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
const surviving = await createIdleAgent(client, {
|
||||
cwd: tempRepo.path,
|
||||
workspaceId,
|
||||
title: `ui-control-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
const passivePage = await page.context().newPage();
|
||||
@@ -111,10 +126,12 @@ test.describe("Archive tab reconciliation", () => {
|
||||
test("clicking an archived session unarchives it and opens the agent", async ({ page }) => {
|
||||
const archived = await createIdleAgent(client, {
|
||||
cwd: tempRepo.path,
|
||||
workspaceId,
|
||||
title: `unarchive-archived-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
const surviving = await createIdleAgent(client, {
|
||||
cwd: tempRepo.path,
|
||||
workspaceId,
|
||||
title: `unarchive-control-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ test.describe("Composer attachments", () => {
|
||||
page,
|
||||
}) => {
|
||||
test.setTimeout(120_000);
|
||||
const { client, repo } = await startRunningMockAgent(page, {
|
||||
const agent = await startRunningMockAgent(page, {
|
||||
prefix: "attach-queue-",
|
||||
model: "one-minute-stream",
|
||||
prompt: "Stay running for queue test.",
|
||||
@@ -205,8 +205,7 @@ test.describe("Composer attachments", () => {
|
||||
await expectQueuedMessageButton(page);
|
||||
await expectComposerDraft(page, "");
|
||||
} finally {
|
||||
await client.close();
|
||||
await repo.cleanup();
|
||||
await agent.cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -214,7 +213,7 @@ test.describe("Composer attachments", () => {
|
||||
page,
|
||||
}) => {
|
||||
test.setTimeout(120_000);
|
||||
const { client, repo } = await startRunningMockAgent(page, {
|
||||
const agent = await startRunningMockAgent(page, {
|
||||
prefix: "attach-interrupt-",
|
||||
model: "ten-second-stream",
|
||||
prompt: "Stay running for interrupt test.",
|
||||
@@ -226,8 +225,7 @@ test.describe("Composer attachments", () => {
|
||||
await expectAgentIdle(page, 15_000);
|
||||
await expectComposerDraft(page, "preserve me");
|
||||
} finally {
|
||||
await client.close();
|
||||
await repo.cleanup();
|
||||
await agent.cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { gotoAppShell } from "./helpers/app";
|
||||
import { connectSeedClient, seedWorkspace } from "./helpers/seed-client";
|
||||
import { getServerId } from "./helpers/server-id";
|
||||
import { createTempGitRepo } from "./helpers/workspace";
|
||||
import { waitForNoProjectsInSidebar, waitForSidebarHydration } from "./helpers/workspace-ui";
|
||||
import { waitForSidebarHydration } from "./helpers/workspace-ui";
|
||||
|
||||
function workspaceRowTestId(workspaceId: string): string {
|
||||
return `sidebar-workspace-row-${getServerId()}:${workspaceId}`;
|
||||
@@ -66,6 +66,13 @@ async function addProjectFromPicker(page: Page, projectPath: string): Promise<st
|
||||
return testId!.replace("sidebar-project-row-", "");
|
||||
}
|
||||
|
||||
async function waitForSidebarProjectListReady(page: Page): Promise<void> {
|
||||
await page
|
||||
.locator('[data-testid="sidebar-project-empty-state"], [data-testid^="sidebar-project-row-"]')
|
||||
.first()
|
||||
.waitFor({ state: "visible", timeout: 60_000 });
|
||||
}
|
||||
|
||||
// Projects are parents in the sidebar. Archiving the last workspace leaves the
|
||||
// project row in place with a ghost "+ New workspace" child row.
|
||||
test.describe("Project with no workspaces persists", () => {
|
||||
@@ -76,7 +83,7 @@ test.describe("Project with no workspaces persists", () => {
|
||||
|
||||
try {
|
||||
await gotoAppShell(page);
|
||||
await waitForNoProjectsInSidebar(page);
|
||||
await waitForSidebarProjectListReady(page);
|
||||
|
||||
projectId = await addProjectFromPicker(page, repo.path);
|
||||
const projectRow = page.getByTestId(`sidebar-project-row-${projectId}`);
|
||||
@@ -92,7 +99,7 @@ test.describe("Project with no workspaces persists", () => {
|
||||
expect(workspaces.entries).toEqual([]);
|
||||
} finally {
|
||||
if (projectId) {
|
||||
await removeProjectFromSidebar(page, projectId).catch(() => undefined);
|
||||
await client.removeProject(projectId).catch(() => undefined);
|
||||
}
|
||||
await client.close().catch(() => undefined);
|
||||
await repo.cleanup().catch(() => undefined);
|
||||
@@ -163,7 +170,7 @@ test.describe("Project remove", () => {
|
||||
await expect(projectRow).toHaveCount(0, { timeout: 30_000 });
|
||||
|
||||
await page.reload();
|
||||
await waitForSidebarHydration(page);
|
||||
await waitForSidebarProjectListReady(page);
|
||||
await expect(projectRow).toHaveCount(0, { timeout: 30_000 });
|
||||
|
||||
const readded = await workspace.client.addProject(workspace.repoPath);
|
||||
@@ -179,7 +186,6 @@ test.describe("Project remove", () => {
|
||||
page.getByTestId(`sidebar-project-new-workspace-row-${workspace.projectId}`),
|
||||
).toBeVisible({ timeout: 30_000 });
|
||||
} finally {
|
||||
await removeProjectFromSidebar(page, workspace.projectId).catch(() => undefined);
|
||||
await workspace.cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -35,10 +35,6 @@ function buildSeededStoragePayload() {
|
||||
* idle agent from the same client it uses for everything else.
|
||||
*/
|
||||
export interface IdleAgentSeedClient {
|
||||
createWorkspace(input: { source: { kind: "directory"; path: string } }): Promise<{
|
||||
workspace: { id: string } | null;
|
||||
error: string | null;
|
||||
}>;
|
||||
createAgent(options: {
|
||||
provider: string;
|
||||
model: string;
|
||||
@@ -56,20 +52,14 @@ export interface IdleAgentSeedClient {
|
||||
|
||||
export async function createIdleAgent(
|
||||
client: IdleAgentSeedClient,
|
||||
input: { cwd: string; title: string },
|
||||
input: { cwd: string; workspaceId: string; title: string },
|
||||
): Promise<ArchiveTabAgent> {
|
||||
const createdWorkspace = await client.createWorkspace({
|
||||
source: { kind: "directory", path: input.cwd },
|
||||
});
|
||||
if (!createdWorkspace.workspace) {
|
||||
throw new Error(createdWorkspace.error ?? `Failed to create workspace ${input.cwd}`);
|
||||
}
|
||||
const created = await client.createAgent({
|
||||
provider: "opencode",
|
||||
model: "opencode/gpt-5-nano",
|
||||
modeId: "bypassPermissions",
|
||||
cwd: input.cwd,
|
||||
workspaceId: createdWorkspace.workspace.id,
|
||||
workspaceId: input.workspaceId,
|
||||
title: input.title,
|
||||
});
|
||||
const snapshot = await client.waitForAgentUpsert(
|
||||
@@ -84,7 +74,7 @@ export async function createIdleAgent(
|
||||
id: created.id,
|
||||
title: input.title,
|
||||
cwd: input.cwd,
|
||||
workspaceId: createdWorkspace.workspace.id,
|
||||
workspaceId: input.workspaceId,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -149,6 +149,7 @@ export async function selectGithubOption(
|
||||
export interface MockAgentSetup {
|
||||
client: SeedDaemonClient;
|
||||
repo: Awaited<ReturnType<typeof createTempGitRepo>>;
|
||||
cleanup: () => Promise<void>;
|
||||
}
|
||||
|
||||
/** Create a temp repo, start a mock agent, navigate to it, and wait for it to be running. */
|
||||
@@ -166,20 +167,29 @@ export async function startRunningMockAgent(
|
||||
if (!createdWorkspace.workspace) {
|
||||
throw new Error(createdWorkspace.error ?? "Failed to create workspace");
|
||||
}
|
||||
const workspace = createdWorkspace.workspace;
|
||||
const agent = await client.createAgent({
|
||||
provider: "mock",
|
||||
cwd: repo.path,
|
||||
workspaceId: createdWorkspace.workspace.id,
|
||||
workspaceId: workspace.id,
|
||||
model: opts.model,
|
||||
});
|
||||
const agentUrl = `${buildHostWorkspaceRoute(serverId, createdWorkspace.workspace.id)}?open=${encodeURIComponent(`agent:${agent.id}`)}`;
|
||||
const agentUrl = `${buildHostWorkspaceRoute(serverId, workspace.id)}?open=${encodeURIComponent(`agent:${agent.id}`)}`;
|
||||
await page.goto(agentUrl);
|
||||
await expectComposerVisible(page);
|
||||
await client.sendAgentMessage(agent.id, opts.prompt);
|
||||
await expect(page.getByRole("button", { name: /stop|cancel/i }).first()).toBeVisible({
|
||||
timeout: 30_000,
|
||||
});
|
||||
return { client, repo };
|
||||
return {
|
||||
client,
|
||||
repo,
|
||||
cleanup: async () => {
|
||||
await client.removeProject(workspace.projectId).catch(() => undefined);
|
||||
await client.close().catch(() => undefined);
|
||||
await repo.cleanup().catch(() => undefined);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export interface GithubWorkspaceHandle {
|
||||
@@ -198,8 +208,14 @@ export async function openGithubWorkspace(
|
||||
if (!createdWorkspace.workspace) {
|
||||
throw new Error(createdWorkspace.error ?? `Failed to create workspace ${repoPath}`);
|
||||
}
|
||||
const workspace = createdWorkspace.workspace;
|
||||
await gotoAppShell(page);
|
||||
await selectWorkspaceInSidebar(page, createdWorkspace.workspace.id);
|
||||
await selectWorkspaceInSidebar(page, workspace.id);
|
||||
await waitForTabBar(page);
|
||||
return { cleanup: () => client.close().catch(() => undefined) };
|
||||
return {
|
||||
cleanup: async () => {
|
||||
await client.removeProject(workspace.projectId).catch(() => undefined);
|
||||
await client.close().catch(() => undefined);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ type NewWorkspaceDaemonClient = Pick<
|
||||
| "getPaseoWorktreeList"
|
||||
| "getDaemonConfig"
|
||||
| "patchDaemonConfig"
|
||||
| "removeProject"
|
||||
>;
|
||||
|
||||
type CreateWorkspacePayload = Awaited<ReturnType<NewWorkspaceDaemonClient["createWorkspace"]>>;
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface AgentHandle {
|
||||
page: Page;
|
||||
client: SeedDaemonClient;
|
||||
agentId: string;
|
||||
projectId: string;
|
||||
workspaceId: string;
|
||||
cwd: string;
|
||||
provider: RewindFlowProvider;
|
||||
@@ -187,6 +188,7 @@ export async function launchAgent(input: {
|
||||
page: input.page,
|
||||
client,
|
||||
agentId: agent.id,
|
||||
projectId: createdWorkspace.workspace.projectId,
|
||||
workspaceId: createdWorkspace.workspace.id,
|
||||
cwd: input.cwd,
|
||||
provider: input.provider,
|
||||
@@ -196,6 +198,7 @@ export async function launchAgent(input: {
|
||||
}
|
||||
|
||||
export async function closeAgent(handle: AgentHandle): Promise<void> {
|
||||
await handle.client.removeProject(handle.projectId).catch(() => undefined);
|
||||
await handle.client.close().catch(() => undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ export interface SeedDaemonClient {
|
||||
} | null;
|
||||
error: string | null;
|
||||
}>;
|
||||
removeProject(projectId: string): Promise<{ removedWorkspaceIds: string[] }>;
|
||||
fetchWorkspaces(options?: { filter?: { projectId?: string } }): Promise<{
|
||||
entries: SeedWorkspaceDescriptor[];
|
||||
}>;
|
||||
@@ -199,15 +200,17 @@ export async function seedWorkspace(options: {
|
||||
if (!created.workspace) {
|
||||
throw new Error(created.error ?? `Failed to create workspace ${project.path}`);
|
||||
}
|
||||
const workspace = created.workspace;
|
||||
return {
|
||||
client,
|
||||
repoPath: project.path,
|
||||
workspaceId: created.workspace.id,
|
||||
workspaceName: created.workspace.name,
|
||||
workspaceDirectory: created.workspace.workspaceDirectory,
|
||||
projectId: created.workspace.projectId,
|
||||
projectDisplayName: created.workspace.projectDisplayName,
|
||||
workspaceId: workspace.id,
|
||||
workspaceName: workspace.name,
|
||||
workspaceDirectory: workspace.workspaceDirectory,
|
||||
projectId: workspace.projectId,
|
||||
projectDisplayName: workspace.projectDisplayName,
|
||||
cleanup: async () => {
|
||||
await client.removeProject(workspace.projectId).catch(() => undefined);
|
||||
await client.close().catch(() => undefined);
|
||||
await project.cleanup().catch(() => undefined);
|
||||
},
|
||||
|
||||
@@ -28,15 +28,18 @@ function sleep(ms: number): Promise<void> {
|
||||
export class TerminalE2EHarness {
|
||||
readonly client: SeedDaemonClient;
|
||||
readonly tempRepo: TempRepo;
|
||||
readonly projectId: string;
|
||||
readonly workspaceId: string;
|
||||
|
||||
private constructor(input: {
|
||||
client: SeedDaemonClient;
|
||||
tempRepo: TempRepo;
|
||||
projectId: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
this.client = input.client;
|
||||
this.tempRepo = input.tempRepo;
|
||||
this.projectId = input.projectId;
|
||||
this.workspaceId = input.workspaceId;
|
||||
}
|
||||
|
||||
@@ -54,11 +57,13 @@ export class TerminalE2EHarness {
|
||||
return new TerminalE2EHarness({
|
||||
client,
|
||||
tempRepo,
|
||||
projectId: seedResult.workspace.projectId,
|
||||
workspaceId: seedResult.workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
async cleanup(): Promise<void> {
|
||||
await this.client.removeProject(this.projectId).catch(() => {});
|
||||
await this.client.close().catch(() => {});
|
||||
await this.tempRepo.cleanup().catch(() => {});
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ export function createWithWorkspace(page: Page): WithWorkspaceHandle {
|
||||
let client: WorkspaceSetupDaemonClient | null = null;
|
||||
const repos: Array<{ cleanup: () => Promise<void> }> = [];
|
||||
const worktrees: WorktreeRecord[] = [];
|
||||
const projectIds = new Set<string>();
|
||||
|
||||
const withWorkspace: WithWorkspace = async (options) => {
|
||||
if (!client) {
|
||||
@@ -64,6 +65,7 @@ export function createWithWorkspace(page: Page): WithWorkspaceHandle {
|
||||
if (!added.project) {
|
||||
throw new Error(added.error ?? `Failed to add project ${repo.path}`);
|
||||
}
|
||||
projectIds.add(added.project.projectId);
|
||||
}
|
||||
|
||||
const created = await client.createWorkspace({
|
||||
@@ -73,6 +75,7 @@ export function createWithWorkspace(page: Page): WithWorkspaceHandle {
|
||||
throw new Error(created.error ?? `Failed to create workspace ${workspacePath}`);
|
||||
}
|
||||
const workspaceId = created.workspace.id;
|
||||
projectIds.add(created.workspace.projectId);
|
||||
|
||||
return {
|
||||
workspaceId,
|
||||
@@ -88,6 +91,11 @@ export function createWithWorkspace(page: Page): WithWorkspaceHandle {
|
||||
return {
|
||||
withWorkspace,
|
||||
cleanup: async () => {
|
||||
if (client) {
|
||||
for (const projectId of projectIds) {
|
||||
await client.removeProject(projectId).catch(() => undefined);
|
||||
}
|
||||
}
|
||||
for (const { repoPath, worktreePath } of worktrees) {
|
||||
try {
|
||||
execSync(`git worktree remove ${JSON.stringify(worktreePath)} --force`, {
|
||||
|
||||
@@ -19,6 +19,7 @@ type WorkspaceSetupDaemonClient = Pick<
|
||||
| "fetchAgents"
|
||||
| "fetchWorkspaces"
|
||||
| "listTerminals"
|
||||
| "removeProject"
|
||||
| "subscribeRawMessages"
|
||||
>;
|
||||
|
||||
|
||||
@@ -54,10 +54,12 @@ test.describe("Settings toggle tab regression", () => {
|
||||
try {
|
||||
const firstAgent = await createIdleAgent(workspace.client, {
|
||||
cwd: workspace.repoPath,
|
||||
workspaceId: workspace.workspaceId,
|
||||
title: `settings-toggle-a-${Date.now()}`,
|
||||
});
|
||||
const secondAgent = await createIdleAgent(workspace.client, {
|
||||
cwd: workspace.repoPath,
|
||||
workspaceId: workspace.workspaceId,
|
||||
title: `settings-toggle-b-${Date.now()}`,
|
||||
});
|
||||
|
||||
@@ -95,10 +97,12 @@ test.describe("Settings toggle tab regression", () => {
|
||||
try {
|
||||
const firstAgent = await createIdleAgent(workspace.client, {
|
||||
cwd: workspace.repoPath,
|
||||
workspaceId: workspace.workspaceId,
|
||||
title: `agent-route-refresh-a-${Date.now()}`,
|
||||
});
|
||||
const secondAgent = await createIdleAgent(workspace.client, {
|
||||
cwd: workspace.repoPath,
|
||||
workspaceId: workspace.workspaceId,
|
||||
title: `agent-route-refresh-b-${Date.now()}`,
|
||||
});
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ test.describe("Workspace agent tab rename", () => {
|
||||
const initialTitle = `agent-rename-${randomUUID().slice(0, 8)}`;
|
||||
const agent = await createIdleAgent(workspace.client, {
|
||||
cwd: workspace.repoPath,
|
||||
workspaceId: workspace.workspaceId,
|
||||
title: initialTitle,
|
||||
});
|
||||
|
||||
|
||||
@@ -204,6 +204,7 @@ test.describe("Workspace navigation regression", () => {
|
||||
try {
|
||||
const agent = await createIdleAgent(workspace.client, {
|
||||
cwd: workspace.repoPath,
|
||||
workspaceId: workspace.workspaceId,
|
||||
title: `workspace-reconnect-${Date.now()}`,
|
||||
});
|
||||
|
||||
@@ -306,6 +307,7 @@ test.describe("Workspace navigation regression", () => {
|
||||
try {
|
||||
const agent = await createIdleAgent(workspace.client, {
|
||||
cwd: workspace.repoPath,
|
||||
workspaceId: workspace.workspaceId,
|
||||
title: `workspace-refresh-route-${Date.now()}`,
|
||||
});
|
||||
await injectDesktopBridge(page, {
|
||||
@@ -344,10 +346,12 @@ test.describe("Workspace navigation regression", () => {
|
||||
try {
|
||||
const firstAgent = await createIdleAgent(firstWorkspace.client, {
|
||||
cwd: firstWorkspace.repoPath,
|
||||
workspaceId: firstWorkspace.workspaceId,
|
||||
title: `workspace-nav-a-${Date.now()}`,
|
||||
});
|
||||
const secondAgent = await createIdleAgent(secondWorkspace.client, {
|
||||
cwd: secondWorkspace.repoPath,
|
||||
workspaceId: secondWorkspace.workspaceId,
|
||||
title: `workspace-nav-b-${Date.now()}`,
|
||||
});
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ test.describe("Workspace pane mounting", () => {
|
||||
try {
|
||||
const agent = await createIdleAgent(workspace.client, {
|
||||
cwd: workspace.repoPath,
|
||||
workspaceId: workspace.workspaceId,
|
||||
title: `pane-remount-${Date.now()}`,
|
||||
});
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ test.describe("Worktree restore after daemon restart", () => {
|
||||
let worktreeClient: Awaited<ReturnType<typeof connectNewWorkspaceDaemonClient>>;
|
||||
let tempRepo: { path: string; cleanup: () => Promise<void> };
|
||||
const createdWorktreeDirectories = new Set<string>();
|
||||
const createdProjectIds = new Set<string>();
|
||||
|
||||
test.describe.configure({ retries: 0, timeout: 180_000 });
|
||||
|
||||
@@ -34,6 +35,10 @@ test.describe("Worktree restore after daemon restart", () => {
|
||||
await archiveWorkspaceFromDaemon(worktreeClient, directory).catch(() => undefined);
|
||||
}
|
||||
createdWorktreeDirectories.clear();
|
||||
for (const projectId of createdProjectIds) {
|
||||
await worktreeClient.removeProject(projectId).catch(() => undefined);
|
||||
}
|
||||
createdProjectIds.clear();
|
||||
await client?.close().catch(() => undefined);
|
||||
await worktreeClient?.close().catch(() => undefined);
|
||||
await tempRepo?.cleanup().catch(() => undefined);
|
||||
@@ -49,15 +54,18 @@ test.describe("Worktree restore after daemon restart", () => {
|
||||
// the History table cells must show after restore — never "main".
|
||||
const worktreeSlug = `restart-restore-${randomUUID().slice(0, 8)}`;
|
||||
|
||||
await openProjectViaDaemon(worktreeClient, tempRepo.path);
|
||||
const project = await openProjectViaDaemon(worktreeClient, tempRepo.path);
|
||||
createdProjectIds.add(project.projectKey);
|
||||
const worktree = await createWorktreeViaDaemon(worktreeClient, {
|
||||
cwd: tempRepo.path,
|
||||
slug: worktreeSlug,
|
||||
});
|
||||
createdProjectIds.add(worktree.projectKey);
|
||||
createdWorktreeDirectories.add(worktree.workspaceDirectory);
|
||||
|
||||
const agent = await createIdleAgent(client, {
|
||||
cwd: worktree.workspaceDirectory,
|
||||
workspaceId: worktree.workspaceId,
|
||||
title: `restart-restore-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
expect(existsSync(worktree.workspaceDirectory)).toBe(true);
|
||||
|
||||
@@ -25,6 +25,7 @@ test.describe("Worktree restore", () => {
|
||||
let worktreeClient: Awaited<ReturnType<typeof connectNewWorkspaceDaemonClient>>;
|
||||
let tempRepo: { path: string; cleanup: () => Promise<void> };
|
||||
const createdWorktreeDirectories = new Set<string>();
|
||||
const createdProjectIds = new Set<string>();
|
||||
|
||||
test.describe.configure({ timeout: 120_000 });
|
||||
|
||||
@@ -39,6 +40,10 @@ test.describe("Worktree restore", () => {
|
||||
await archiveWorkspaceFromDaemon(worktreeClient, directory).catch(() => undefined);
|
||||
}
|
||||
createdWorktreeDirectories.clear();
|
||||
for (const projectId of createdProjectIds) {
|
||||
await worktreeClient.removeProject(projectId).catch(() => undefined);
|
||||
}
|
||||
createdProjectIds.clear();
|
||||
await client?.close().catch(() => undefined);
|
||||
await worktreeClient?.close().catch(() => undefined);
|
||||
await tempRepo?.cleanup().catch(() => undefined);
|
||||
@@ -48,15 +53,18 @@ test.describe("Worktree restore", () => {
|
||||
page,
|
||||
}) => {
|
||||
const serverId = getServerId();
|
||||
await openProjectViaDaemon(worktreeClient, tempRepo.path);
|
||||
const project = await openProjectViaDaemon(worktreeClient, tempRepo.path);
|
||||
createdProjectIds.add(project.projectKey);
|
||||
const worktree = await createWorktreeViaDaemon(worktreeClient, {
|
||||
cwd: tempRepo.path,
|
||||
slug: `restore-inplace-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
createdProjectIds.add(worktree.projectKey);
|
||||
createdWorktreeDirectories.add(worktree.workspaceDirectory);
|
||||
|
||||
const agent = await createIdleAgent(client, {
|
||||
cwd: worktree.workspaceDirectory,
|
||||
workspaceId: worktree.workspaceId,
|
||||
title: `restore-inplace-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
expect(existsSync(worktree.workspaceDirectory)).toBe(true);
|
||||
@@ -90,15 +98,18 @@ test.describe("Worktree restore", () => {
|
||||
page,
|
||||
}) => {
|
||||
const serverId = getServerId();
|
||||
await openProjectViaDaemon(worktreeClient, tempRepo.path);
|
||||
const project = await openProjectViaDaemon(worktreeClient, tempRepo.path);
|
||||
createdProjectIds.add(project.projectKey);
|
||||
const worktree = await createWorktreeViaDaemon(worktreeClient, {
|
||||
cwd: tempRepo.path,
|
||||
slug: `restore-recreate-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
createdProjectIds.add(worktree.projectKey);
|
||||
createdWorktreeDirectories.add(worktree.workspaceDirectory);
|
||||
|
||||
const agent = await createIdleAgent(client, {
|
||||
cwd: worktree.workspaceDirectory,
|
||||
workspaceId: worktree.workspaceId,
|
||||
title: `restore-recreate-${randomUUID().slice(0, 8)}`,
|
||||
});
|
||||
expect(existsSync(worktree.workspaceDirectory)).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user