Files
kandev/apps/web/e2e/tests/chat/message-queue-pin.spec.ts
T
João Salavisa 3c8ff8ab27 test(e2e): replace unconditional sleeps in chat and task specs with reactive waits (#2637)
Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 19:11:58 +01:00

106 lines
3.6 KiB
TypeScript

import { type Page } from "@playwright/test";
import { test, expect } from "../../fixtures/test-base";
import type { SeedData } from "../../fixtures/test-base";
import type { ApiClient } from "../../helpers/api-client";
import { typeWhileBusy, waitForComposerQueueMode } from "../../helpers/type-while-busy";
import { SessionPage } from "../../pages/session-page";
/**
* Creates a task whose agent stays busy for 30s (via `/slow 30s`) and queues
* one message, returning the open task route. The long busy window keeps the
* queued entry alive across the navigation below.
*/
async function seedPinnedQueueTask(
testPage: Page,
apiClient: ApiClient,
seedData: SeedData,
title: string,
): Promise<{ taskId: string }> {
const task = await apiClient.createTaskWithAgent(
seedData.workspaceId,
title,
seedData.agentProfileId,
{
description: "/e2e:simple-message",
workflow_id: seedData.workflowId,
workflow_step_id: seedData.startStepId,
repository_ids: [seedData.repositoryId],
},
);
await testPage.goto(`/t/${task.id}`);
const session = new SessionPage(testPage);
await session.waitForLoad();
await session.waitForChatIdle({ timeout: 30_000 });
await session.sendMessage("/slow 30s");
await expect(session.agentStatus()).toBeVisible({ timeout: 15_000 });
await waitForComposerQueueMode(testPage);
const editor = testPage.locator(".tiptap.ProseMirror").first();
await typeWhileBusy(testPage, editor, "queued while pinned");
await testPage.getByTestId("submit-message-button").click();
await expect(testPage.getByTestId("queue-chip")).toBeVisible({ timeout: 10_000 });
return { taskId: task.id };
}
test.describe("Message queue pin", () => {
test.describe.configure({ retries: 1 });
test("pinned queue stays expanded across navigation", async ({
testPage,
apiClient,
seedData,
}) => {
test.setTimeout(120_000);
const { taskId } = await seedPinnedQueueTask(
testPage,
apiClient,
seedData,
"Pinned queue navigation",
);
// Expand the panel and pin it.
await testPage.getByTestId("queue-chip").click();
await expect(testPage.getByTestId("queued-ghost-list")).toBeVisible({ timeout: 5_000 });
await testPage.getByTestId("queue-pin").click();
await expect(testPage.getByTestId("queue-pin")).toHaveAttribute("aria-pressed", "true");
// Navigate away and back — the panel must already be expanded, with no
// chip click required.
await testPage.goto("/");
await testPage.waitForLoadState("networkidle");
await testPage.goto(`/t/${taskId}`);
await expect(testPage.getByTestId("queued-ghost-list")).toBeVisible({ timeout: 15_000 });
await expect(testPage.getByTestId("queue-chip")).not.toBeVisible();
});
test("unpinned queue stays collapsed across navigation", async ({
testPage,
apiClient,
seedData,
}) => {
test.setTimeout(120_000);
const { taskId } = await seedPinnedQueueTask(
testPage,
apiClient,
seedData,
"Unpinned queue navigation",
);
// Open the panel (without pinning), then navigate away and back.
await testPage.getByTestId("queue-chip").click();
await expect(testPage.getByTestId("queued-ghost-list")).toBeVisible({ timeout: 5_000 });
await testPage.goto("/");
await testPage.waitForLoadState("networkidle");
await testPage.goto(`/t/${taskId}`);
// Without a pin the queue starts collapsed: chip visible, panel hidden.
await expect(testPage.getByTestId("queue-chip")).toBeVisible({ timeout: 15_000 });
await expect(testPage.getByTestId("queued-ghost-list")).not.toBeVisible();
});
});