| |
| |
| |
| |
| import { test as base, type Page } from "@playwright/test"; |
| import { mkdtempSync, rmSync } from "fs"; |
| import { join, dirname } from "path"; |
| import { fileURLToPath } from "url"; |
| import type { AddressInfo } from "net"; |
| import { createApp, resetSaveTimers } from "../src/create-app.js"; |
| import { setDataDir } from "../src/utils.js"; |
|
|
| const __filename = fileURLToPath(import.meta.url); |
| const BACKEND_DIR = join(dirname(__filename), ".."); |
|
|
| const STREAM_HEADERS = { |
| "Content-Type": "text/event-stream", |
| "Cache-Control": "no-cache", |
| "Connection": "keep-alive", |
| "X-Accel-Buffering": "no", |
| "X-Vercel-AI-UI-Message-Stream": "v1", |
| }; |
|
|
| function buildFakeStream(text: string): string { |
| const textId = `txt-${Date.now()}`; |
| const events = [ |
| { type: "start" }, |
| { type: "text-start", id: textId }, |
| { type: "text-delta", id: textId, delta: text }, |
| { type: "text-end", id: textId }, |
| { type: "finish-step" }, |
| { type: "finish" }, |
| ]; |
| const lines = events.map((e) => `data: ${JSON.stringify(e)}\n`).join("\n"); |
| return lines + "\ndata: [DONE]\n\n"; |
| } |
|
|
| interface TestFixtures { |
| serverUrl: string; |
| appPage: Page; |
| } |
|
|
| export const test = base.extend<TestFixtures>({ |
| serverUrl: [ |
| async ({}, use) => { |
| |
| const tmpDir = mkdtempSync(join(BACKEND_DIR, ".e2e-data-")); |
| setDataDir(tmpDir); |
|
|
| const { app, httpServer, hocuspocus } = createApp(); |
|
|
| await new Promise<void>((resolve) => httpServer.listen(0, resolve)); |
| const port = (httpServer.address() as AddressInfo).port; |
| const url = `http://localhost:${port}`; |
|
|
| await use(url); |
|
|
| resetSaveTimers(); |
| try { await hocuspocus.destroy(); } catch {} |
| try { httpServer.close(); } catch {} |
| setDataDir(undefined); |
| try { rmSync(tmpDir, { recursive: true, force: true }); } catch {} |
| }, |
| { scope: "test" }, |
| ], |
|
|
| appPage: async ({ page, serverUrl }, use) => { |
| |
| await page.route("**/api/chat", async (route) => { |
| await route.fulfill({ |
| status: 200, |
| headers: STREAM_HEADERS, |
| body: buildFakeStream("Hello! I'm the AI assistant."), |
| }); |
| }); |
|
|
| await page.route("**/api/embed-chat", async (route) => { |
| await route.fulfill({ |
| status: 200, |
| headers: STREAM_HEADERS, |
| body: buildFakeStream("Chart created successfully."), |
| }); |
| }); |
|
|
| await page.goto(serverUrl); |
| |
| await page.waitForSelector("[aria-label='Undo']", { timeout: 15_000 }); |
| await use(page); |
| }, |
| }); |
|
|
| export { expect } from "@playwright/test"; |
|
|