73 lines
5.8 KiB
TypeScript
73 lines
5.8 KiB
TypeScript
import { expect, type Page, test } from "@playwright/test";
|
|
import JSZip from "jszip";
|
|
|
|
async function upload(page: Page, files: Record<string, string>, name = "测试导图.xmind") {
|
|
const zip = new JSZip();
|
|
for (const [path, content] of Object.entries(files)) zip.file(path, content);
|
|
await page.locator('input[type=file][accept*=xmind]').setInputFiles({
|
|
name, mimeType: "application/octet-stream", buffer: await zip.generateAsync({ type: "nodebuffer" }),
|
|
});
|
|
}
|
|
|
|
test("modern XMind preserves sheets, free topics, summaries, boundaries, relationships and style", async ({ page }) => {
|
|
const errors: string[] = [];
|
|
page.on("pageerror", (error) => errors.push(error.message));
|
|
await page.goto("/dev/flow-board-preview", { waitUntil: "commit" });
|
|
const root = { id: "root", title: "新品项目", structureClass: "org.xmind.ui.logic.right", children: {
|
|
attached: [{ id: "research", title: "市场调研", style: { properties: { "svg:fill": "#fff4cc", "fo:font-size": 22, "fo:font-weight": "bold" } }, children: { attached: [{ id: "a", title: "用户访谈" }, { id: "b", title: "竞品分析" }] } }, { id: "design", title: "产品设计" }],
|
|
summary: [{ id: "summary", title: "启动阶段" }],
|
|
detached: [{ id: "free", title: "待讨论", position: { x: 450, y: 300 } }],
|
|
}, summaries: [{ range: "(0,1)", topicId: "summary" }], boundaries: [{ range: "(0,1)" }] };
|
|
await upload(page, { "content.json": JSON.stringify([
|
|
{ title: "产品计划", rootTopic: root, relationships: [{ end1Id: "research", end2Id: "design", title: "输入设计" }] },
|
|
{ title: "上线清单", rootTopic: { id: "root2", title: "正式上线", structureClass: "org.xmind.ui.org-chart.down", children: { attached: [{ id: "qa", title: "质量验收" }] } } },
|
|
]) });
|
|
const canvas = page.locator(".drawnix");
|
|
for (const label of ["新品项目", "用户访谈", "竞品分析", "启动阶段", "待讨论", "输入设计"]) await expect(canvas.getByText(label, { exact: true })).toBeVisible();
|
|
await expect(page.locator("[plait-geometry=true]")).toHaveCount(1);
|
|
await expect(page.locator("[plait-arrow-line=true]")).toHaveCount(1);
|
|
await expect(canvas.getByText("市场调研", { exact: true })).toHaveCSS("font-size", "22px");
|
|
await canvas.getByText("市场调研", { exact: true }).click();
|
|
await expect(page.getByLabel("节点字号")).toHaveValue("22");
|
|
await expect(page.getByRole("button", { name: "向右逻辑", exact: true })).toHaveAttribute("aria-pressed", "true");
|
|
await page.getByRole("button", { name: "上线清单", exact: true }).click();
|
|
await expect(canvas.getByText("质量验收", { exact: true })).toBeVisible();
|
|
await expect(canvas.getByText("新品项目", { exact: true })).toHaveCount(0);
|
|
await page.getByRole("button", { name: "产品计划", exact: true }).click();
|
|
await expect(canvas.getByText("输入设计", { exact: true })).toBeVisible();
|
|
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: 100, y: 100 } });
|
|
await expect(canvas.getByText("设计已更新", { exact: true })).toBeVisible();
|
|
expect(errors).toEqual([]);
|
|
});
|
|
|
|
test("legacy XML XMind retains separate sheets and folded branches", async ({ page }) => {
|
|
await page.goto("/dev/flow-board-preview", { waitUntil: "commit" });
|
|
await upload(page, { "content.xml": `<?xml version="1.0"?><xmap-content xmlns="urn:xmind:xmap:xmlns:content:2.0">
|
|
<sheet id="s1"><title>旧版计划</title><topic id="r1" structure-class="org.xmind.ui.logic.right"><title>旧版中心</title><children><topics type="attached"><topic id="c1" branch="folded" style-id="yellow"><title>折叠分支</title><children><topics type="attached"><topic id="c2"><title>内部任务</title></topic></topics></children></topic></topics></children></topic></sheet>
|
|
<sheet id="s2"><title>旧版归档</title><topic id="r2"><title>归档中心</title></topic></sheet></xmap-content>`,
|
|
"styles.xml": `<xmap-styles xmlns="urn:xmind:xmap:xmlns:style:2.0" xmlns:svg="http://www.w3.org/2000/svg"><styles><style id="yellow"><topic-properties svg:fill="#fff4cc" /></style></styles></xmap-styles>`,
|
|
});
|
|
const canvas = page.locator(".drawnix");
|
|
await expect(canvas.getByText("折叠分支", { exact: true })).toBeVisible();
|
|
await expect(canvas.getByText("内部任务", { exact: true })).toHaveCount(0);
|
|
await canvas.getByText("折叠分支", { exact: true }).click();
|
|
await page.keyboard.press("ControlOrMeta+/");
|
|
await expect(canvas.getByText("内部任务", { exact: true })).toBeVisible();
|
|
await page.getByRole("button", { name: "旧版归档", exact: true }).click();
|
|
await expect(canvas.getByText("归档中心", { exact: true })).toBeVisible();
|
|
});
|
|
|
|
test("invalid import preserves the existing workbook and gives a readable error", async ({ page }) => {
|
|
await page.goto("/dev/flow-board-preview", { waitUntil: "commit" });
|
|
await upload(page, { "content.json": JSON.stringify([{ title: "保留画布", rootTopic: { id: "root", title: "已有内容" } }]) });
|
|
await expect(page.locator(".drawnix").getByText("已有内容", { exact: true })).toBeVisible();
|
|
await upload(page, { "content.json": "broken json" }, "损坏文件.xmind");
|
|
await expect(page.getByText("XMind 内容解析失败,请在 XMind 中重新保存后再导入", { exact: true })).toBeVisible();
|
|
await expect(page.locator(".drawnix").getByText("已有内容", { exact: true })).toBeVisible();
|
|
await page.locator('input[type=file][accept*=xmind]').setInputFiles({ name: "伪装文件.xmind", mimeType: "application/octet-stream", buffer: Buffer.from("not a zip") });
|
|
await expect(page.getByText("无法打开 XMind 文件,请确认文件完整且未加密", { exact: true })).toBeVisible();
|
|
});
|