tests/icons.test.js (2323 bytes)
1 import assert from 'node:assert/strict'; 2 import fs from 'node:fs'; 3 import { test } from 'node:test'; 4 import { fileURLToPath } from 'node:url'; 5 import { inflateSync } from 'node:zlib'; 6 import { icon, ICONS } from '../dashboard/icons.mjs'; 7 8 /** The pixels of a PNG that icons.mjs wrote: signature, size, and RGBA rows without a filter. */ 9 function decode(png) { 10 assert.deepEqual([...png.subarray(0, 8)], [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a], 'PNG signature'); 11 assert.equal(png.subarray(12, 16).toString('ascii'), 'IHDR'); 12 const width = png.readUInt32BE(16); 13 const height = png.readUInt32BE(20); 14 assert.equal(png.subarray(37, 41).toString('ascii'), 'IDAT'); 15 const rows = inflateSync(png.subarray(41, 41 + png.readUInt32BE(33))); 16 const at = (x, y) => { 17 const start = y * (width * 4 + 1); 18 assert.equal(rows[start], 0, 'each row says "no filter"'); 19 return [...rows.subarray(start + 1 + x * 4, start + 5 + x * 4)]; 20 }; 21 return { width, height, at }; 22 } 23 24 test('each icon in the repository is the PNG that the drawing makes now', () => { 25 for (const [name, wanted, opts] of ICONS) { 26 const made = icon(wanted, opts); 27 const { width, height } = decode(made); 28 assert.deepEqual([width, height], [wanted, wanted], name); 29 const file = fs.readFileSync(fileURLToPath(new URL(`../dashboard/${name}`, import.meta.url))); 30 assert.ok(made.equals(file), `${name} differs from the drawing. Run: node dashboard/icons.mjs`); 31 } 32 }); 33 34 test('the icon is a blue lamp on a dark tile with round corners, and the maskable icon is a full square', () => { 35 const plain = decode(icon(192)); 36 assert.deepEqual(plain.at(0, 0), [0, 0, 0, 0], 'the corner is outside the rounded tile'); 37 assert.deepEqual(plain.at(96, 4), [11, 11, 11, 255], 'the top middle is the dark tile'); 38 const middle = Math.round(192 * 0.44); 39 const inside = Math.round(96 + 0.75 * 0.21 * 192); // in the glass, beside the filament 40 assert.deepEqual(plain.at(inside, middle), [57, 135, 229, 255], 'the glass of the lamp is the accent colour'); 41 assert.deepEqual(plain.at(96, middle), [11, 11, 11, 255], 'the filament crosses the middle and is dark'); 42 43 const maskable = decode(icon(512, { maskable: true })); 44 assert.equal(maskable.at(0, 0)[3], 255, 'a maskable icon fills its square, so a phone can cut any shape'); 45 });