import { render } from "@solidjs/testing-library"; import { describe, expect, test } from "vitest"; import GraphLanes from "../../src/components/GraphLanes"; import { edge, row } from "../fixtures/rows"; /** Every path the component drew, in order. */ function paths(container: HTMLElement): string[] { return [...container.querySelectorAll("path")].map((path) => path.getAttribute("d") ?? ""); } /** The lane index each path was given, which is what drives its colour. */ function lanes(container: HTMLElement): (string | null)[] { return [...container.querySelectorAll("path")].map((path) => path.style.getPropertyValue("--lane"), ); } describe("GraphLanes", () => { test("is hidden from assistive technology", () => { // The row's text already says everything the graph shows; the drawing is // decoration on top of it. const { container } = render(() => ); expect(container.querySelector("svg")?.getAttribute("aria-hidden")).toBe("true"); }); test("is as wide as the columns the row uses", () => { const { container } = render(() => ); // Four columns at fourteen pixels each. expect(container.querySelector("svg")?.getAttribute("width")).toBe("56"); }); test("widens for a commit sitting past the reported width", () => { // Defensive: a row whose column is outside its own width would otherwise // draw its dot beyond the edge of the SVG, where it would be clipped. const { container } = render(() => ); expect(container.querySelector("svg")?.getAttribute("width")).toBe("56"); }); test("draws a line passing the row as a straight vertical", () => { const { container } = render(() => ( )); const [line] = paths(container); // Same x at both ends, and both control points share it, so the curve has // nothing to bend towards. expect(line).toBe("M 7 0 C 7 14 7 14 7 28"); }); test("curves a line that arrives from another column into the dot", () => { const { container } = render(() => ( )); const [line] = paths(container); // Starts at column 1's centre on the top edge, ends at column 0's centre // halfway down, where the dot is. expect(line).toBe("M 21 0 C 21 7 7 7 7 14"); }); test("draws a line leaving the dot towards a parent", () => { const { container } = render(() => ( )); expect(paths(container)[0]).toBe("M 7 14 C 7 21 21 21 21 28"); }); test("passes each line its own lane, so a merge is two colours", () => { const { container } = render(() => ( )); expect(lanes(container)).toEqual(["3", "7"]); }); test("gives the dot the row's lane", () => { const { container } = render(() => ); expect(container.querySelector("circle")?.style.getPropertyValue("--lane")).toBe("5"); }); test("draws a merge as a ring so it is not size alone that distinguishes it", () => { const { container } = render(() => ); const dot = container.querySelector("circle"); expect(dot?.getAttribute("class")).toContain("graph-dot-merge"); expect(dot?.getAttribute("r")).toBe("5"); }); test("draws an ordinary commit as a plain dot", () => { const { container } = render(() => ); const dot = container.querySelector("circle"); expect(dot?.getAttribute("class")).not.toContain("graph-dot-merge"); expect(dot?.getAttribute("r")).toBe("4"); }); test("puts the dot in the row's column", () => { const { container } = render(() => ); const dot = container.querySelector("circle"); expect(dot?.getAttribute("cx")).toBe("35"); expect(dot?.getAttribute("cy")).toBe("14"); }); });