Files
next-ai-draw-io/tests/e2e/chat.spec.ts
T
dayuan.jiang 1333ed68c6 test: shared e2e helpers, vi.stubEnv, drop placeholder specs
- tests/e2e/lib: openApp(page, { path, config }), MODEL_CONFIGS_KEY,
  savedModelConfigs, settingsDialog, chunkedReplies, sse() and
  toolCallEvents() replace about 70 copies of goto + wait for iframe,
  three local openApp functions, 14 window.fetch overrides and the
  Node-side SSE serialisers; unused fixtures removed
- delete theme, save, history, model-config, upload and copy-paste
  specs (the copy-button test moves to chat.spec.ts); trim
  iframe-interaction, history-restore, keyboard and smoke to tests that
  can fail; file-upload asserts on the preview image
- settings-review-fixes.spec.ts split by topic into settings-bedrock,
  settings-tabs-sync and settings-providers
- unit tests use vi.stubEnv with unstubEnvs: true instead of
  hand-written process.env save and restore loops
2026-10-12 09:11:25 +09:00

123 lines
4.4 KiB
TypeScript

import {
chunkedReplies,
expect,
getChatInput,
openApp,
sendMessage,
test,
} from "./lib/fixtures"
import { createTextOnlyResponse, sse } from "./lib/helpers"
test.describe("Crossing the mobile breakpoint", () => {
test.beforeEach(async ({ page }) => {
// A text answer that arrives in parts over a few seconds
await chunkedReplies(
page,
[
[
sse([{ type: "start" }], false),
sse([{ type: "text-start", id: "t" }], false),
sse(
[{ type: "text-delta", id: "t", delta: "Once upon" }],
false,
),
sse(
[{ type: "text-delta", id: "t", delta: " a time." }],
false,
),
sse([{ type: "text-end", id: "t" }], false),
sse([{ type: "finish" }]),
],
],
{ gapMs: 1500 },
)
await page.setViewportSize({ width: 1280, height: 800 })
await openApp(page)
})
test("keeps the chat and its streaming answer", async ({ page }) => {
await sendMessage(page, "Tell me a story")
await expect(page.getByText("Once upon")).toBeVisible({
timeout: 10000,
})
// Phones show the canvas or the chat, one at a time
await page.setViewportSize({ width: 600, height: 900 })
await page.getByRole("button", { name: "Chat", exact: true }).click()
await expect(page.getByText("Tell me a story")).toBeVisible()
await page.setViewportSize({ width: 1280, height: 800 })
await expect(page.getByText("Once upon a time.")).toBeVisible({
timeout: 10000,
})
await expect(page.getByText("Tell me a story")).toBeVisible()
})
test("reaches a chat hidden on desktop", async ({ page }) => {
// The start screen has no chat panel yet
await page.getByTestId("draw-yourself").click()
await page.getByRole("button", { name: "Hide chat panel" }).click()
await expect(getChatInput(page)).toBeHidden()
await page.setViewportSize({ width: 600, height: 900 })
await page.getByRole("button", { name: "Chat", exact: true }).click()
await expect(getChatInput(page)).toBeVisible()
await page.setViewportSize({ width: 1280, height: 800 })
await page.getByTestId("show-panel").click()
await expect(getChatInput(page)).toBeVisible()
})
})
test.describe("Sending", () => {
test("a double Enter sends the message once", async ({ page }) => {
let requests = 0
await page.route("**/api/chat", async (route) => {
requests++
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: createTextOnlyResponse("Hello there."),
})
})
await openApp(page)
const input = getChatInput(page)
await input.fill("Hi")
// The second press comes while the diagram is being exported
await input.press("ControlOrMeta+Enter")
await input.press("ControlOrMeta+Enter")
await expect(page.getByText("Hello there.")).toBeVisible({
timeout: 10000,
})
await page.waitForTimeout(1500)
expect(requests).toBe(1)
await expect(page.getByText("Hello there.")).toHaveCount(1)
})
})
test.describe("Answers", () => {
test("copy button copies response text", async ({ page }) => {
await page.route("**/api/chat", async (route) => {
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: createTextOnlyResponse(
"Here is your diagram with a test box.",
),
})
})
await openApp(page)
await sendMessage(page, "Create a test box")
await expect(
page.getByText("Here is your diagram with a test box."),
).toBeVisible({ timeout: 15000 })
// The user's message has one too: the answer's is the last
await page.getByRole("button", { name: "Copy response" }).last().click()
// The button shows a check mark for a moment
await expect(page.getByRole("button", { name: "Copied!" })).toBeVisible(
{ timeout: 3000 },
)
})
})