168 lines
6.2 KiB
TypeScript
168 lines
6.2 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import {
|
|
arrangeSpecialMind,
|
|
specialNodeRect,
|
|
specialSubtreeBounds,
|
|
type SpecialLayoutNode,
|
|
} from "@/lib/flow-board/mind-special-layout";
|
|
const node = (
|
|
x: number,
|
|
y: number,
|
|
width = 100,
|
|
height = 40,
|
|
children: SpecialLayoutNode[] = []
|
|
): SpecialLayoutNode => ({
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
hGap: 0,
|
|
vGap: 0,
|
|
children,
|
|
origin: {},
|
|
});
|
|
const tree = () =>
|
|
node(0, 0, 120, 60, [
|
|
node(200, -100, 100, 40, [
|
|
node(400, -150, 180, 40),
|
|
node(400, -50, 110, 40),
|
|
]),
|
|
node(200, 0, 130, 40),
|
|
node(200, 100, 200, 40),
|
|
node(200, 200, 100, 40),
|
|
]);
|
|
|
|
test("fishbone places whole subtrees above/below a stable spine without overlap", () => {
|
|
const root = tree();
|
|
arrangeSpecialMind(root, "fishbone");
|
|
expect(specialNodeRect(root)).toEqual({ x: 0, y: 0, width: 120, height: 60 });
|
|
const a = specialSubtreeBounds(root.children[0]),
|
|
b = specialSubtreeBounds(root.children[1]),
|
|
c = specialSubtreeBounds(root.children[2]);
|
|
expect(a.y + a.height).toBeLessThan(30);
|
|
expect(b.y).toBeGreaterThan(30);
|
|
expect(c.x).toBeGreaterThan(a.x + a.width);
|
|
for (const branch of root.children)
|
|
expect(specialNodeRect(branch).x).toBeGreaterThan(120);
|
|
});
|
|
|
|
test("timeline milestones alternate on distinct increasing positions", () => {
|
|
const root = tree();
|
|
arrangeSpecialMind(root, "timeline");
|
|
const rects = root.children.map(specialNodeRect);
|
|
for (let i = 1; i < rects.length; i++)
|
|
expect(rects[i].x).toBeGreaterThan(rects[i - 1].x);
|
|
expect(rects[0].y).toBeLessThan(rects[1].y);
|
|
expect(rects[2].y).toBeLessThan(rects[3].y);
|
|
});
|
|
|
|
test("long titles and descendants reserve column space and brace preserves native tree layout", () => {
|
|
const root = tree();
|
|
root.children[0].children[0].width = 900;
|
|
arrangeSpecialMind(root, "timeline");
|
|
const first = specialSubtreeBounds(root.children[0]);
|
|
expect(specialNodeRect(root.children[2]).x).toBeGreaterThan(
|
|
first.x + first.width
|
|
);
|
|
const brace = tree(),
|
|
before = JSON.stringify(brace);
|
|
arrangeSpecialMind(brace, "brace");
|
|
expect(JSON.stringify(brace)).toBe(before);
|
|
});
|
|
|
|
test("root summaries remain outside the packed branch columns", () => {
|
|
const root = tree();
|
|
const summary = node(300, 10, 150, 40);
|
|
summary.origin = { start: 0, end: 1 };
|
|
root.children.push(summary);
|
|
arrangeSpecialMind(root, "fishbone");
|
|
const right = Math.max(
|
|
...root.children.slice(0, 4).map((child) => {
|
|
const rect = specialSubtreeBounds(child);
|
|
return rect.x + rect.width;
|
|
})
|
|
);
|
|
expect(specialNodeRect(summary).x).toBeGreaterThan(right);
|
|
});
|
|
|
|
test("vertical timeline alternates whole subtrees, keeps row order and mirrors descendants", () => {
|
|
const root = tree();
|
|
root.children[1].children.push(node(400, 0, 700, 120));
|
|
arrangeSpecialMind(root, "verticalTimeline");
|
|
const bounds = root.children.map(specialSubtreeBounds);
|
|
expect(bounds[0].x).toBeGreaterThan(60);
|
|
expect(bounds[1].x + bounds[1].width).toBeLessThan(60);
|
|
expect(specialNodeRect(root.children[1].children[0]).x).toBeLessThan(
|
|
specialNodeRect(root.children[1]).x
|
|
);
|
|
for (let i = 1; i < bounds.length; i++)
|
|
expect(bounds[i].y).toBeGreaterThan(bounds[i - 1].y + bounds[i - 1].height);
|
|
expect(specialNodeRect(root)).toEqual({ x: 0, y: 0, width: 120, height: 60 });
|
|
});
|
|
|
|
test("tree table creates aligned columns and lets parents span their descendant rows", () => {
|
|
const root = tree();
|
|
arrangeSpecialMind(root, "treeTable");
|
|
const [first, second] = root.children;
|
|
const [firstChild, secondChild] = first.children;
|
|
|
|
expect(root.tableCell).toMatchObject({ depth: 0, x: 0, y: 0 });
|
|
expect(root.tableCell!.width).toBeGreaterThan(root.tableCell!.height);
|
|
expect(first.tableCell).toMatchObject({ depth: 1, branch: 0 });
|
|
expect(first.tableCell!.height).toBe(
|
|
firstChild.tableCell!.height + secondChild.tableCell!.height
|
|
);
|
|
expect(firstChild.tableCell!.x).toBe(secondChild.tableCell!.x);
|
|
expect(firstChild.tableCell!.width).toBe(secondChild.tableCell!.width);
|
|
expect(second.tableCell!.y).toBeGreaterThanOrEqual(
|
|
secondChild.tableCell!.y + secondChild.tableCell!.height
|
|
);
|
|
expect(specialNodeRect(first).x).toBeGreaterThanOrEqual(first.tableCell!.x);
|
|
expect(specialNodeRect(first).x + specialNodeRect(first).width).toBeLessThanOrEqual(
|
|
first.tableCell!.x + first.tableCell!.width
|
|
);
|
|
});
|
|
|
|
test("side-title tree table spans the root beside every leaf row", () => {
|
|
const root = tree();
|
|
arrangeSpecialMind(root, "treeTableSide");
|
|
const [first, second] = root.children;
|
|
const leaves = root.children.flatMap((branch) =>
|
|
branch.children.length ? branch.children : [branch]
|
|
);
|
|
expect(root.tableCell).toMatchObject({ depth: 0, x: 0, y: 0 });
|
|
expect(root.tableCell!.height).toBe(78 * leaves.length);
|
|
expect(first.tableCell!.x).toBe(root.tableCell!.x + root.tableCell!.width);
|
|
expect(first.tableCell!.y).toBe(root.tableCell!.y);
|
|
expect(second.tableCell!.y).toBeGreaterThan(first.tableCell!.y);
|
|
expect(first.tableCell!.height).toBe(156);
|
|
});
|
|
|
|
test("spreadsheet uses XMind columns and stacks entries that share a labelled cell", () => {
|
|
const mondayA = node(400, 0, 100, 40);
|
|
mondayA.origin.xmind = { labels: ["Monday"] };
|
|
const mondayB = node(400, 50, 100, 40);
|
|
mondayB.origin.xmind = { labels: ["Monday"] };
|
|
const friday = node(400, 100, 100, 40);
|
|
friday.origin.xmind = { labels: ["Friday"] };
|
|
const happy = node(200, 0, 120, 40, [mondayA, mondayB, friday]);
|
|
const calmTuesday = node(400, 0, 100, 40);
|
|
calmTuesday.origin.xmind = { labels: ["Tuesday"] };
|
|
const calm = node(200, 100, 120, 40, [calmTuesday]);
|
|
const root = node(0, 0, 150, 60, [happy, calm]);
|
|
root.origin.spreadsheetColumns = ["Monday", "Tuesday", "Friday"];
|
|
|
|
arrangeSpecialMind(root, "spreadsheet");
|
|
|
|
expect(root.tableGrid?.columns).toEqual(["Monday", "Tuesday", "Friday"]);
|
|
expect(root.tableCell!.width).toBe(root.tableGrid!.width);
|
|
expect(happy.tableCell!.x).toBe(root.tableGrid!.x);
|
|
expect(mondayA.tableCell!.x).toBe(mondayB.tableCell!.x);
|
|
expect(mondayB.tableCell!.y).toBeGreaterThan(mondayA.tableCell!.y);
|
|
expect(friday.tableCell!.x).toBeGreaterThan(mondayA.tableCell!.x);
|
|
expect(calmTuesday.tableCell!.x).toBeGreaterThan(mondayA.tableCell!.x);
|
|
expect(calm.tableCell!.y).toBeGreaterThan(
|
|
happy.tableCell!.y + happy.tableCell!.height - 1
|
|
);
|
|
});
|