repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
scripts/readme/banner.test.ts
Rawimport { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { ROOT } from "../lib/common.ts";
import {
DEFAULT_BANNER,
FONT_CHARS,
initials,
type NuguPalette,
renderBanner,
} from "./banner.ts";
import { extensionDirs } from "./banners.ts";
const palette = JSON.parse(
readFileSync(join(ROOT, "assets", "nugu.json"), "utf8"),
) as NuguPalette;
/** Geometry only: strip every colour so two renders can be compared for shape. */
const shape = (svg: string) =>
svg.replaceAll(/fill="[^"]*"/g, "").replaceAll(/#(?:dark|light)/g, "");
describe("README banner", () => {
it("executes CLI entrypoint and rejects an unknown extension", () => {
const result = spawnSync(
process.execPath,
[join(ROOT, "scripts/readme/banners.ts"), "__missing_banner_cli_probe__"],
{ cwd: ROOT, encoding: "utf8", timeout: 10_000 },
);
expect(result.error).toBeUndefined();
expect(result.status).not.toBe(0);
expect(result.stderr).toContain(
"unknown extension: __missing_banner_cli_probe__",
);
});
it("derives initials from the first and last hyphen part", () => {
expect(initials("klaus")).toEqual(["k"]);
expect(initials("git-safe")).toEqual(["g", "s"]);
expect(initials("the-system")).toEqual(["t", "s"]);
expect(initials("nu-bang")).toEqual(["n", "b"]);
});
it("is deterministic and theme-complete", () => {
const a = renderBanner("ultra", palette);
expect(renderBanner("ultra", palette)).toBe(a);
expect(a).toContain('id="dark"');
expect(a).toContain('id="light"');
expect(a).toContain("prefers-color-scheme: light");
expect(a).toMatch(/^<svg xmlns="http:\/\/www\.w3\.org\/2000\/svg"/);
expect(a.trimEnd().endsWith("</svg>")).toBe(true);
expect(a).not.toContain("<text");
});
it("changes colour but never geometry across versions", () => {
const v0 = renderBanner("ultra", palette, { version: 0 });
const v5 = renderBanner("ultra", palette, { version: 5 });
expect(v5).not.toBe(v0);
expect(shape(v5)).toBe(shape(v0));
});
it("changes geometry with the seed", () => {
const a = renderBanner("ultra", palette, { seed: 1 });
const b = renderBanner("ultra", palette, { seed: 2 });
expect(shape(a)).not.toBe(shape(b));
});
it("uses only palette-derived colours", () => {
const svg = renderBanner("the-system", palette);
const fills = [...svg.matchAll(/fill="([^"]+)"/g)].map((m) => m[1]);
const allowed = new Set([
...Object.values(palette.dark.content),
...Object.values(palette.dark.ui),
...Object.values(palette.light.content),
...Object.values(palette.light.ui),
]);
for (const fill of fills)
expect(
fill === undefined || allowed.has(fill) || fill.startsWith("hsl("),
).toBe(true);
});
it("can set every extension name in its pixel font", () => {
for (const name of extensionDirs())
for (const ch of name)
expect(FONT_CHARS.has(ch), `${name}: ${ch}`).toBe(true);
});
it("keeps the agreed defaults", () => {
expect(DEFAULT_BANNER).toEqual({
seed: 193_581,
mutation: 4,
version: 0,
drift: 0.5,
cell: 10,
});
});
});