From 1b15f69a96b3d1e99a060e1fc3c33cb800152a8f Mon Sep 17 00:00:00 2001 From: chenhang Date: Fri, 17 Jul 2026 18:34:17 +0800 Subject: [PATCH] feat(tests): add pre-release multi-message lock types test suite --- .../real/multi-message-lock-types.spec.ts | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 e2e/specs/real/multi-message-lock-types.spec.ts diff --git a/e2e/specs/real/multi-message-lock-types.spec.ts b/e2e/specs/real/multi-message-lock-types.spec.ts new file mode 100644 index 00000000..16373bbd --- /dev/null +++ b/e2e/specs/real/multi-message-lock-types.spec.ts @@ -0,0 +1,104 @@ +import { expect, test, type Locator, type Page } from "@playwright/test"; + +import { + defaultCharacterChatUrl, + dismissChatInterruptions, + enterChatFromSplash, +} from "@e2e/fixtures/test-helpers"; + +const preReleaseHost = "frontend-test.banlv-ai.com"; +const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? ""; + +test.describe("pre-release multi-message lock types", () => { + test.setTimeout(120_000); + test.skip( + !baseURL.includes(preReleaseHost), + `Run this test only with PLAYWRIGHT_BASE_URL pointing at ${preReleaseHost}.`, + ); + + test("returns locked image, locked voice, then unlocked text", async ({ + page, + }) => { + await enterChatFromSplash(page, { + expectedUrl: defaultCharacterChatUrl, + timeout: 20_000, + waitUntil: "domcontentloaded", + }); + await dismissChatInterruptions(page); + + const messageInput = page.getByRole("textbox", { name: "Message" }); + await expect(messageInput).toBeEnabled({ timeout: 30_000 }); + + let aiMessageCount = await page + .locator('[aria-label="AI message"]') + .count(); + + const imageReply = await sendMessageAndWaitForAiReply( + page, + messageInput, + "发个图片", + aiMessageCount, + ); + aiMessageCount += 1; + await expect( + imageReply.getByRole("button", { name: "Open image in fullscreen" }), + ).toBeVisible(); + await expect( + imageReply + .getByRole("button", { name: "Open image in fullscreen" }) + .locator("img"), + ).toHaveClass(/blur-sm/); + + const voiceReply = await sendMessageAndWaitForAiReply( + page, + messageInput, + "发送语音", + aiMessageCount, + ); + aiMessageCount += 1; + await expect( + voiceReply.getByRole("button", { name: "Unlock voice message" }), + ).toBeVisible(); + await expect( + voiceReply.getByRole("button", { name: "Play voice message" }), + ).toBeDisabled(); + + const textReply = await sendMessageAndWaitForAiReply( + page, + messageInput, + "你好", + aiMessageCount, + ); + await expect( + textReply.getByRole("button", { name: "Unlock voice message" }), + ).toHaveCount(0); + await expect( + textReply.getByRole("group", { name: "Locked private image" }), + ).toHaveCount(0); + await expect(textReply.getByRole("button", { name: /Unlock/ })).toHaveCount(0); + await expect(textReply).toContainText(/\S/); + }); +}); + +async function sendMessageAndWaitForAiReply( + page: Page, + messageInput: Locator, + message: string, + previousAiMessageCount: number, +): Promise { + const aiMessages = page.locator('[aria-label="AI message"]'); + const sendRequestPromise = page.waitForRequest("**/api/chat/send"); + + await messageInput.fill(message); + await messageInput.press("Enter"); + + const sendRequest = await sendRequestPromise; + expect(sendRequest.postDataJSON()).toMatchObject({ message }); + + await expect + .poll(() => aiMessages.count(), { timeout: 60_000 }) + .toBeGreaterThan(previousAiMessageCount); + const latestReply = aiMessages.last(); + await expect(latestReply).toBeVisible(); + return latestReply; +}