// The digital rain's arithmetic: columns, how they start and step, the glyph // drawn, and the fade colour. The random source is passed in, so each case is // exact. Run by `npm test`. import assert from "node:assert/strict"; import { test } from "node:test"; import { CELL, GLYPHS, columnsFor, fadeColorOf, glyphFor, rainAllowed, startDrops, stepDrops, } from "../src/shell/rain.ts"; const always = (n) => () => n; test("the app's reduce setting stops the rain whatever the OS says", () => { assert.equal(rainAllowed("reduce", false), false); assert.equal(rainAllowed("reduce", true), false); }); test("the app's allow setting runs the rain even on a reduce-motion OS", () => { assert.equal(rainAllowed("allow", true), true); assert.equal(rainAllowed("allow", false), true); }); test("with no app setting the rain follows the OS", () => { assert.equal(rainAllowed(undefined, false), true); assert.equal(rainAllowed(undefined, true), false); assert.equal(rainAllowed("", true), false); }); test("a canvas gets one column per cell, rounded up, and at least one", () => { assert.equal(columnsFor(CELL * 10), 10); assert.equal(columnsFor(CELL * 10 + 1), 11); assert.equal(columnsFor(0), 1); }); test("columns start above the top, spread over 40 cells", () => { assert.deepEqual( startDrops(3, always(0)).map((row) => row === 0), [true, true, true], ); assert.deepEqual(startDrops(2, always(0.5)), [-20, -20]); for (const row of startDrops(200, Math.random)) { assert.ok(row <= 0 && row >= -40, String(row)); } }); test("a step moves every column down one row", () => { assert.deepEqual(stepDrops([-3, 0, 5], 10_000, always(0)), [-2, 1, 6]); }); test("a column past the bottom restarts only on a high enough roll", () => { const past = [Math.ceil(100 / CELL) + 1]; assert.deepEqual(stepDrops(past, 100, always(0.99)), [1]); assert.deepEqual(stepDrops(past, 100, always(0.5)), [past[0] + 1]); }); test("a column still on the canvas never restarts", () => { assert.deepEqual(stepDrops([2], 100, always(0.99)), [3]); }); test("a step does not change the array it was given", () => { const drops = [1, 2]; stepDrops(drops, 100, always(0.99)); assert.deepEqual(drops, [1, 2]); }); test("the glyph comes from the set, first and last at the ends of the roll", () => { assert.equal(glyphFor(always(0)), GLYPHS[0]); assert.equal(glyphFor(always(0.999999)), GLYPHS[GLYPHS.length - 1]); }); test("the fade colour keeps the background's channels at a low alpha", () => { assert.equal(fadeColorOf("rgb(30, 30, 46)"), "rgba(30, 30, 46, 0.09)"); assert.equal(fadeColorOf("rgb(239,241,245)"), "rgba(239, 241, 245, 0.09)"); assert.equal(fadeColorOf("rgba(1, 2, 3, 0.5)"), "rgba(1, 2, 3, 0.09)"); }); test("a colour with no channels fades from the default background", () => { assert.equal(fadeColorOf("transparent"), "rgba(30, 30, 46, 0.09)"); assert.equal(fadeColorOf(""), "rgba(30, 30, 46, 0.09)"); });