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");
});
});