import { describe, expect, test } from "bun:test";
import { animatedLavaLampSvg, lavaLamp, lavaLampDataUrl, lavaLampSvg, lavaMotion } from "./lava-lamp";
const stripAnimation = (svg: string) =>
svg.replace(/<animate [^>]*\/>/g, "").replace(/<ellipse ([^>]*)><\/ellipse>/g, "<ellipse $1/>");
describe("lavaLamp", () => {
test("is deterministic and case-insensitive", () => {
expect(lavaLampSvg("Taigrr")).toBe(lavaLampSvg("taigrr"));
expect(lavaLampDataUrl("taigrr")).toBe(lavaLampDataUrl("TAIGRR"));
expect(lavaLampDataUrl("taigrr", true)).toBe(lavaLampDataUrl("TAIGRR", true));
});
test("keeps shipped lamps stable", () => {
expect(lavaLamp("taigrr").blobs.length).toBeGreaterThanOrEqual(3);
expect(Bun.hash(lavaLampSvg("taigrr")).toString(16)).toMatchSnapshot();
});
test("gives distinct handles distinct lamps", () => {
const handles = Array.from({ length: 2000 }, (_, i) => `user${i}`);
expect(new Set(handles.map(lavaLampSvg)).size).toBe(handles.length);
});
test("animated lamp starts and loops on the static frame", () => {
for (const handle of ["taigrr", "alice", "x", "gitfor"]) {
const animated = animatedLavaLampSvg(handle);
expect(animated).toContain("<animate ");
expect(stripAnimation(animated)).toBe(lavaLampSvg(handle));
for (const [, values] of animated.matchAll(/values="([^"]+)"/g)) {
const frames = values.split(";");
expect(frames[0]).toBe(frames.at(-1) ?? "");
}
}
});
test("rising wax clears the top of the glass before sinking back", () => {
for (const handle of Array.from({ length: 200 }, (_, i) => `rise${i}`)) {
const moving = lavaLamp(handle).blobs.slice(1);
lavaMotion(handle, moving).forEach((motion, index) => {
const blob = moving[index];