import { describe, expect, it } from "vitest"; import { buildRoutePath, ROUTE_CORNER_RADIUS } from "@/components/admin/tech-tree/edgeRoutes"; import { routeAroundObstacles, segmentCrossesRect, type RouteRect, } from "@/components/admin/tech-tree/edgeRouting"; describe("tech tree edge route path", () => { it("returns nothing for fewer than two points", () => { expect(buildRoutePath([])).toBe(""); expect(buildRoutePath([{ x: 0, y: 0 }])).toBe(""); }); it("draws a straight line for two points", () => { expect(buildRoutePath([{ x: 0, y: 0 }, { x: 100, y: 0 }])).toBe("M 0,0 L 100,0"); }); it("rounds each interior corner with a quadratic curve", () => { const d = buildRoutePath([ { x: 0, y: 0 }, { x: 100, y: 0 }, { x: 100, y: 100 }, ]); expect(d.startsWith("M 0,0")).toBe(true); expect(d).toContain("Q 100,0"); expect(d.endsWith("L 100,100")).toBe(true); // The straight run stops short of the corner by the radius. expect(d).toContain(`L ${100 - ROUTE_CORNER_RADIUS},0`); }); it("shrinks the radius on short segments so it never overshoots", () => { const d = buildRoutePath([ { x: 0, y: 0 }, { x: 10, y: 0 }, { x: 10, y: 10 }, ]); // Half of the 10px segment, not the full default radius. expect(d).toContain("L 5,0"); expect(d).toContain("Q 10,0 10,5"); }); }); describe("tech tree edge obstacle routing", () => { const box = (id: number, x: number, y: number, width: number, height: number): RouteRect => ({ id, x, y, width, height, }); it("leaves a clear path unchanged", () => { const points = [ { x: 0, y: 0 }, { x: 200, y: 0 }, ]; // The box sits well below the line. expect(routeAroundObstacles(points, [box(1, 0, 100, 60, 40)])).toEqual(points); }); it("returns the input untouched when there are no obstacles", () => { const points = [ { x: 0, y: 0 }, { x: 100, y: 50 }, ]; expect(routeAroundObstacles(points, [])).toBe(points); }); it("detours around a box that blocks the segment", () => { const obstacle = box(1, 80, -20, 40, 40); const points = [ { x: 0, y: 0 }, { x: 200, y: 0 }, ]; const routed = routeAroundObstacles(points, [obstacle]); expect(routed.length).toBeGreaterThan(2); expect(routed[0]).toEqual({ x: 0, y: 0 }); expect(routed[routed.length - 1]).toEqual({ x: 200, y: 0 }); // Every resulting segment clears the box. for (let i = 0; i < routed.length - 1; i += 1) { expect(segmentCrossesRect(routed[i], routed[i + 1], obstacle)).toBe(false); } }); });