diff --git a/canvas/e2e/chat-desktop.spec.ts b/canvas/e2e/chat-desktop.spec.ts index 908bbef0..29b01786 100644 --- a/canvas/e2e/chat-desktop.spec.ts +++ b/canvas/e2e/chat-desktop.spec.ts @@ -43,8 +43,16 @@ test.describe("Desktop ChatTab", () => { if (await skipGuide.isVisible().catch(() => false)) { await skipGuide.click(); } - // Click the workspace node by its exact name label. - await page.getByText(workspaceName, { exact: true }).first().click(); + // Click the workspace node by its exact name label — scoped to the + // React Flow canvas: ConciergeShell stays mounted (hidden) on the map + // view and renders a matching wsName div, so an unscoped getByText + // .first() can resolve to the invisible concierge node (DOM-order + // dependent → alternating green/red on main). + await page + .locator(".react-flow__node") + .getByText(workspaceName, { exact: true }) + .first() + .click(); // Wait for the side panel chat tab to be clickable, then click it. await page.locator('#tab-chat').click(); await page.waitForSelector("[data-testid='chat-panel']", { timeout: 5_000 }); @@ -77,7 +85,11 @@ test.describe("Desktop ChatTab", () => { await page.reload(); await enterMapView(page); await page.waitForSelector(".react-flow__node", { timeout: 10_000 }); - await page.getByText(workspaceName, { exact: true }).first().click(); + await page + .locator(".react-flow__node") + .getByText(workspaceName, { exact: true }) + .first() + .click(); await page.locator('#tab-chat').click(); await page.waitForSelector("[data-testid='chat-panel']", { timeout: 5_000 }); // Wait for the workspace status to flip to online and the textarea to be enabled. @@ -158,7 +170,11 @@ test.describe("Desktop ChatTab — Markdown rendering", () => { if (await skipGuide2.isVisible().catch(() => false)) { await skipGuide2.click(); } - await page.getByText(workspaceName, { exact: true }).first().click(); + await page + .locator(".react-flow__node") + .getByText(workspaceName, { exact: true }) + .first() + .click(); await page.locator('#tab-chat').click(); await page.waitForSelector("[data-testid='chat-panel']", { timeout: 5_000 }); // Wait for the workspace status to flip to online and the textarea to be enabled. diff --git a/canvas/src/components/tabs/__tests__/ChatTab.autoscroll.test.tsx b/canvas/src/components/tabs/__tests__/ChatTab.autoscroll.test.tsx index 2549042a..8714ce8f 100644 --- a/canvas/src/components/tabs/__tests__/ChatTab.autoscroll.test.tsx +++ b/canvas/src/components/tabs/__tests__/ChatTab.autoscroll.test.tsx @@ -64,6 +64,13 @@ let currentClientHeight = 200; beforeEach(() => { apiGet.mockClear(); apiPost.mockReset(); + // useChatSend chains api.post(...).then(...) — a bare vi.fn() returns + // undefined and the .then throws an UNHANDLED TypeError that vitest + // surfaces nondeterministically (run-order/teardown timing), flipping + // the Canvas job red on unrelated PRs. A never-resolving promise keeps + // the send in-flight, which is exactly the state the scroll assertions + // exercise. + apiPost.mockImplementation(() => new Promise(() => {})); scrollIntoView = vi.fn(); scrollEventListeners = []; currentScrollTop = 0;