import { chooseXmindLayout, clickXmindAction, openXmindStructures } from "./editor-actions"; import { expect, test } from "@playwright/test"; import JSZip from "jszip"; test("special layouts change geometry and connectors, edit normally and round-trip their structure", async ({ page, }) => { const errors: string[] = []; page.on("pageerror", (error) => errors.push(error.message)); await page.goto("/dev/flow-board-preview", { waitUntil: "commit" }); const zip = new JSZip(); zip.file( "content.json", JSON.stringify([ { title: "结构试验", relationships: [{ end1Id: "a", end2Id: "b", title: "关联" }], rootTopic: { id: "root", title: "中心主题", structureClass: "org.xmind.ui.fishbone.leftHeaded", children: { attached: [ { id: "a", title: "分支一", children: { attached: [ { id: "a1", title: "细分任务一" }, { id: "a2", title: "细分任务二" }, ], }, }, { id: "b", title: "分支二" }, { id: "c", title: "分支三" }, { id: "d", title: "分支四" }, ], }, }, }, ]) ); await page.locator("input[accept*=xmind]").setInputFiles({ name: "特殊布局.xmind", mimeType: "application/octet-stream", buffer: await zip.generateAsync({ type: "nodebuffer" }), }); const canvas = page.locator(".drawnix"); await expect(page.locator('[plait-arrow-line="true"]')).toHaveCount(1); await expect(canvas.locator('[data-special-axis="fishbone"]')).toHaveCount(1); await expect( canvas.locator('[data-special-connector="fishbone"]') ).toHaveCount(4); await clickXmindAction(page, "适应画布"); const rect = async (title: string) => (await canvas.getByText(title, { exact: true }).boundingBox())!; const center = await rect("中心主题"); const a = await rect("分支一"); const b = await rect("分支二"); const c = await rect("分支三"); expect(a.y + a.height).toBeLessThan(center.y); expect(b.y).toBeGreaterThan(center.y + center.height); expect(c.x).toBeGreaterThan(a.x + a.width); await canvas.getByText("中心主题", { exact: true }).click(); await openXmindStructures(page); await expect( page.getByRole("button", { name: "鱼骨图", exact: true }) ).toHaveAttribute("aria-pressed", "true"); await page.screenshot({ path: test.info().outputPath("fishbone-preview.png"), animations: "disabled", }); await chooseXmindLayout(page, "水平时间轴"); await expect(canvas.locator('[data-special-axis="timeline"]')).toHaveCount(1); await expect( canvas.locator('[data-special-connector="timeline"] circle') ).toHaveCount(4); await expect(canvas.locator('[data-special-axis="fishbone"]')).toHaveCount(0); await clickXmindAction(page, "撤销"); await expect(canvas.locator('[data-special-axis="fishbone"]')).toHaveCount(1); await clickXmindAction(page, "重做"); await expect(canvas.locator('[data-special-axis="timeline"]')).toHaveCount(1); await canvas.getByText("分支二", { exact: true }).dblclick(); await page.keyboard.press("ControlOrMeta+A"); await page.keyboard.insertText("已编辑的时间节点"); await page .locator(".flow-board-canvas-shell") .click({ position: { x: 80, y: 80 } }); await expect( canvas.getByText("已编辑的时间节点", { exact: true }) ).toBeVisible(); await canvas.getByText("分支三", { exact: true }).click(); await page.getByRole("button", { name: "子主题", exact: true }).click(); await expect(canvas.locator('[contenteditable="true"]')).toBeFocused(); await page.keyboard.press("ControlOrMeta+A"); await page.keyboard.insertText("新增时间任务"); await page .locator(".flow-board-canvas-shell") .click({ position: { x: 80, y: 80 } }); await expect(canvas.getByText("新增时间任务", { exact: true })).toBeVisible(); await canvas.getByText("中心主题", { exact: true }).click(); await chooseXmindLayout(page, "括号图"); await expect( canvas.locator('[data-special-structure="brace"] path') ).toHaveCount(3); await expect(canvas.locator("[data-special-axis]")).toHaveCount(0); await page.screenshot({ path: test.info().outputPath("brace-preview.png"), animations: "disabled", }); const downloading = page.waitForEvent("download"); await page.getByRole("button", { name: "导出 XMind", exact: true }).click(); const download = await downloading; const stream = await download.createReadStream(); const chunks = []; for await (const chunk of stream!) chunks.push(chunk); const exported = await JSZip.loadAsync(Buffer.concat(chunks)); const content = JSON.parse( await exported.file("content.json")!.async("string") ); expect(content[0].rootTopic.structureClass).toBe("org.xmind.ui.brace.right"); await chooseXmindLayout(page, "向右逻辑"); await expect(canvas.locator("[data-special-structure]")).toHaveCount(0); expect(errors).toEqual([]); });