import { chooseXmindLayout, clickXmindAction, clickXmindSheet } from "./editor-actions"; import { expect, type Locator, type Page, test } from "@playwright/test"; async function importMap(page: Page) { // Exercise the actual Markdown importer with a test-only cloud response. await page.route("**/api/flow-board/files", async (route) => { await route.fulfill({ json: { data: { ...route.request().postDataJSON(), id: "test-map", createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }, }, }); }); await page.goto("/dev/flow-board-preview", { waitUntil: "commit" }); await page.locator("input[type=file][accept*=md]").setInputFiles({ name: "项目计划.md", mimeType: "text/markdown", buffer: Buffer.from( "# 项目计划\n## 产品调研\n### 用户访谈\n### 竞品分析\n## 设计方案\n### 视觉设计\n### 交互设计\n## 开发实现\n### 前端开发\n### 质量验证" ), }); await expect(page.getByText("用户访谈", { exact: true })).toBeVisible(); } function bounds(locator: Locator) { return locator.evaluate((element) => { const box = (element as unknown as SVGGraphicsElement).getBBox(); return { x: box.x, y: box.y, width: box.width, height: box.height }; }); } test("annotations follow layout and collapse, persist across sheets, and undo with deleted topics", async ({ page, }) => { const errors: string[] = []; page.on("pageerror", (error) => errors.push(error.message)); await importMap(page); await page.getByText("用户访谈", { exact: true }).click(); await page.getByRole("button", { name: "联系", exact: true }).click(); await expect( page.getByRole("status").filter({ hasText: "点击另一个主题" }) ).toBeVisible(); await page.getByText("视觉设计", { exact: true }).click(); await page.getByLabel("联系文字", { exact: true }).fill("调研驱动设计"); const relationText = page .locator(".drawnix") .getByText("调研驱动设计", { exact: true }); await expect(relationText).toBeVisible(); await expect(page.locator("[plait-arrow-line=true]")).toHaveCount(1); await page.getByText("产品调研", { exact: true }).click(); await page.getByRole("button", { name: "外框", exact: true }).click(); await page.getByLabel("外框留白").selectOption("24"); const boundary = page.locator("[plait-geometry=true]"); const originalBounds = await bounds(boundary); await page.locator(".drawnix").getByText("项目计划", { exact: true }).click(); await chooseXmindLayout(page, "向下逻辑"); await expect.poll(() => bounds(boundary)).not.toEqual(originalBounds); await chooseXmindLayout(page, "向右逻辑"); await expect.poll(() => bounds(boundary)).toEqual(originalBounds); await page.getByText("产品调研", { exact: true }).click(); const expanded = await bounds(boundary); await page.keyboard.press("ControlOrMeta+/"); await expect(page.getByText("用户访谈", { exact: true })).toHaveCount(0); await expect .poll(async () => (await bounds(boundary)).width) .toBeLessThan(expanded.width); await expect(relationText).toBeVisible(); await page.keyboard.press("ControlOrMeta+/"); await expect(page.getByText("用户访谈", { exact: true })).toBeVisible(); await expect.poll(() => bounds(boundary)).toEqual(expanded); await page.getByRole("button", { name: "新增画布", exact: true }).click(); await expect(relationText).toHaveCount(0); await clickXmindSheet(page, "画布 1"); await expect(relationText).toBeVisible(); await expect(boundary).toHaveCount(1); await page.getByText("视觉设计", { exact: true }).click(); await page.keyboard.press("Backspace"); await expect(relationText).toHaveCount(0); await clickXmindAction(page, "撤销"); await expect(relationText).toBeVisible(); await clickXmindAction(page, "重做"); await expect(relationText).toHaveCount(0); expect(errors).toEqual([]); }); test("summary uses selected branches and relationship creation can be cancelled", async ({ page, }) => { await importMap(page); await page.getByText("开发实现", { exact: true }).click(); await page.getByRole("button", { name: "概要", exact: true }).click(); await expect( page.locator(".drawnix").getByText("摘要", { exact: true }) ).toBeVisible(); await page.getByText("用户访谈", { exact: true }).click(); await page.getByRole("button", { name: "联系", exact: true }).click(); await page.keyboard.press("Escape"); await page.getByText("视觉设计", { exact: true }).click(); await expect(page.locator("[plait-arrow-line=true]")).toHaveCount(0); });