import { expect, test } from "@playwright/test"; import { v4 as uuid } from "uuid"; import { THREAD_FOR_WELCOME, newChatEntry, openChat, reuseThreadChatEntry, sendMessage, skipIfMissingThread, waitForAnyMessages, waitForMessageListReady, } from "./support/chat-helpers"; test.use({ screenshot: "on", video: "on", }); test.describe("线程路由(无 isnew)", () => { test("/new 始终走欢迎态,发送后进入具体 thread 路由", async ({ page }, testInfo) => { skipIfMissingThread(testInfo, THREAD_FOR_WELCOME, "FRONTEND_E2E_THREAD_ID"); await openChat(page, newChatEntry(THREAD_FOR_WELCOME!)); await expect(page.getByTestId("welcome-suggestions")).toBeVisible(); }); test("/chats/:thread_id 直接复用并渲染历史", async ({ page }, testInfo) => { skipIfMissingThread(testInfo, THREAD_FOR_WELCOME, "FRONTEND_E2E_THREAD_ID"); await openChat(page, reuseThreadChatEntry(THREAD_FOR_WELCOME!)); await waitForMessageListReady(page, { requireMessages: false }); const messageCount = await waitForAnyMessages(page); testInfo.skip(messageCount === 0, "当前线程没有可见历史消息。"); await expect(page).toHaveURL(new RegExp(`/workspace/chats/${THREAD_FOR_WELCOME!}`)); await expect(page.locator(".is-user, .is-assistant").first()).toBeVisible(); }); test("/new 使用 uuid thread_id 发送后触发 stream(cod=0) 并进入 thread 路由", async ({ page, }) => { const threadId = uuid(); const text = `e2e-${threadId.slice(0, 8)}`; await openChat(page, newChatEntry(threadId)); await expect(page.getByTestId("welcome-suggestions")).toBeVisible(); const streamRequestPromise = page.waitForRequest( (request) => { const url = request.url(); if (!url.includes("/stream")) return false; if (!url.includes(threadId)) return false; try { const parsed = new URL(url); return parsed.searchParams.get("cancel_on_disconnect") === "0"; } catch { return url.includes("cancel_on_disconnect=0"); } }, { timeout: 30_000 }, ); await sendMessage(page, text); await expect(page.locator(".is-user").filter({ hasText: text })).toHaveCount(1); await expect .poll( async () => await page.locator(".is-assistant").count(), { timeout: 30_000 }, ) .toBeGreaterThan(0); const streamRequest = await streamRequestPromise; expect(streamRequest.url()).toContain("cancel_on_disconnect=0"); await expect(page).toHaveURL( new RegExp(`/workspace/chats/${threadId}\\?is_chatting=true`), { timeout: 30_000 }, ); }); test("streaming 中点击停止可中断输出", async ({ page }) => { const threadId = uuid(); const text = "请逐行输出 1 到 500 的数字,并在每一行前面加上“第N行:”前缀,不要省略。"; await openChat(page, newChatEntry(threadId)); await expect(page.getByTestId("welcome-suggestions")).toBeVisible(); await sendMessage(page, text); const submitButton = page.locator("button[aria-label='Submit']"); await expect(submitButton).toHaveText("停止", { timeout: 30_000 }); await expect(submitButton).toBeEnabled(); await submitButton.click(); // 点击停止后应退出 streaming 态,按钮文本不再是“停止” await expect(submitButton).toHaveText("发送", { timeout: 30_000 }); }); });