import { expect, test } from "@playwright/test"; import { PRIMARY_THREAD_ID, THREAD_WITH_ARTIFACTS, THREAD_WITH_HTML_ARTIFACT, THREAD_WITH_IMAGE_ARTIFACT, openChat, reuseThreadChatEntry, sendMessage, skipIfMissingThread, waitForAnyMessages, waitForMessageListReady, } from "./support/chat-helpers"; test.describe("聊天工作台 / Artifact 面板", () => { test("DF-ART-001 含 artifacts 的线程展示入口并可打开文件列表", async ({ page, }, testInfo) => { skipIfMissingThread( testInfo, THREAD_WITH_ARTIFACTS, "FRONTEND_E2E_ARTIFACTS_THREAD_ID", ); await openChat(page, reuseThreadChatEntry(THREAD_WITH_ARTIFACTS!)); await waitForMessageListReady(page, { requireMessages: false }); const messageCount = await waitForAnyMessages(page); testInfo.skip(messageCount === 0, "当前线程没有可见历史消息。"); testInfo.skip( (await page.getByTestId("artifacts-open-button").count()) === 0, "当前线程未展示 artifacts 入口。", ); await expect(page.getByTestId("artifacts-open-button")).toBeVisible(); await page.getByTestId("artifacts-open-button").click(); await expect(page.getByTestId("artifact-file-list").first()).toBeVisible(); }); test("DF-ART-002 可打开图片 artifact 详情", async ({ page }, testInfo) => { skipIfMissingThread( testInfo, THREAD_WITH_IMAGE_ARTIFACT, "FRONTEND_E2E_IMAGE_ARTIFACT_THREAD_ID", ); await openChat(page, reuseThreadChatEntry(THREAD_WITH_IMAGE_ARTIFACT!)); await waitForMessageListReady(page, { requireMessages: false }); const messageCount = await waitForAnyMessages(page); testInfo.skip(messageCount === 0, "当前线程没有可见历史消息。"); testInfo.skip( (await page.getByTestId("artifacts-open-button").count()) === 0, "当前线程未展示 artifacts 入口。", ); await page.getByTestId("artifacts-open-button").click(); const imageFile = page .locator( "[data-testid='artifact-file-list'] [data-testid='artifact-file-card']", ) .filter({ hasText: /\.(png|jpe?g|gif|webp|svg)/i }) .first(); testInfo.skip( (await imageFile.count()) === 0, "当前线程没有可预览的图片 artifact。", ); await imageFile.click(); await expect(page.getByTitle(/Artifact preview(?::.*)?$/i)).toBeVisible(); }); test("DF-ART-003 可打开 HTML artifact 详情", async ({ page }, testInfo) => { skipIfMissingThread( testInfo, THREAD_WITH_HTML_ARTIFACT, "FRONTEND_E2E_HTML_ARTIFACT_THREAD_ID", ); await openChat(page, reuseThreadChatEntry(THREAD_WITH_HTML_ARTIFACT!)); await waitForMessageListReady(page, { requireMessages: false }); const messageCount = await waitForAnyMessages(page); testInfo.skip(messageCount === 0, "当前线程没有可见历史消息。"); testInfo.skip( (await page.getByTestId("artifacts-open-button").count()) === 0, "当前线程未展示 artifacts 入口。", ); await page.getByTestId("artifacts-open-button").click(); const htmlFile = page .locator( "[data-testid='artifact-file-list'] [data-testid='artifact-file-card']", ) .filter({ hasText: /\.html?/i }) .first(); testInfo.skip( (await htmlFile.count()) === 0, "当前线程没有 HTML artifact。", ); const htmlArtifactResponsePromise = page.waitForResponse((response) => { const url = decodeURIComponent(response.url()); return ( response.status() === 200 && /\/api\/threads\/[^/]+\/artifacts\//.test(url) && /\.html?($|\?)/i.test(url) ); }); await htmlFile.click(); const htmlArtifactResponse = await htmlArtifactResponsePromise; expect( htmlArtifactResponse.headers()["content-disposition"] ?? "", ).toContain("attachment;"); await expect(page.getByTitle(/Artifact preview(?::.*)?$/i)).toBeVisible(); }); test("DF-ART-004 关闭 artifact 面板后恢复聊天主视图", async ({ page, }, testInfo) => { skipIfMissingThread( testInfo, THREAD_WITH_ARTIFACTS, "FRONTEND_E2E_ARTIFACTS_THREAD_ID", ); await openChat(page, reuseThreadChatEntry(THREAD_WITH_ARTIFACTS!)); await waitForMessageListReady(page, { requireMessages: false }); const messageCount = await waitForAnyMessages(page); testInfo.skip(messageCount === 0, "当前线程没有可见历史消息。"); testInfo.skip( (await page.getByTestId("artifacts-open-button").count()) === 0, "当前线程未展示 artifacts 入口。", ); await page.getByTestId("artifacts-open-button").click(); await expect(page.getByTestId("artifact-file-list").first()).toBeVisible(); await page.getByTestId("artifacts-panel-close").click(); await expect(page.getByTestId("artifacts-open-button")).toBeVisible(); await expect(page.getByRole("log").first()).toBeVisible(); }); test("DF-ART-005 生成简单 HTML 后出现 artifact-file-card", async ({ page, }, testInfo) => { test.setTimeout(180_000); skipIfMissingThread(testInfo, PRIMARY_THREAD_ID, "FRONTEND_E2E_THREAD_ID"); await openChat(page, reuseThreadChatEntry(PRIMARY_THREAD_ID!)); await waitForMessageListReady(page, { requireMessages: false }); await sendMessage(page, "生成一个简单的html文件"); await expect .poll( async () => await page.getByTestId("artifacts-open-button").count(), { timeout: 120_000 }, ) .toBeGreaterThan(0); await page.getByTestId("artifacts-open-button").click(); await expect .poll(async () => await page.getByTestId("artifact-file-card").count(), { timeout: 30_000, }) .toBeGreaterThan(0); }); });