// The icon packs of the Store (store/x/icons/): the four the app bundles are published under the same // ids as the same files, the two retro packs are our own drawings and cover X's left rail and action // bar, and every pack the Store lists parses with the app's own parser. import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import test from 'node:test'; import { ICON_LIMITS, compileIcons, parseIconPackJson, type IconName } from '../../../waybetter/packages/runtime/src/themeIcons.ts'; // @ts-expect-error: plain ES module shared with scripts/check-store.mjs import { STORE_ICON_IDS, iconsPreviewSvg, packFile } from '../../../scripts/build-store-icons.mjs'; import { BUILTIN_PACKS } from '../src/inject/packs/index.ts'; import { RETRO_PACKS } from '../src/inject/packs/retro.ts'; import { X_ICONS } from '../src/inject/themeIcons.ts'; const ROOT = join(import.meta.dirname, '../../..'); const read = (id: string, name: string) => readFileSync(join(ROOT, 'store/x/icons', id, name), 'utf8'); test('every bundled pack is in the Store under its own id, as the same file', () => { for (const pack of BUILTIN_PACKS) { assert.ok(STORE_ICON_IDS.includes(pack.id), `${pack.id} is a Store item`); assert.equal(read(pack.id, `${pack.id}.icons.json`), packFile(pack.id), `${pack.id}: run node scripts/build-store-icons.mjs`); assert.equal(read(pack.id, 'preview.svg'), iconsPreviewSvg(pack), `${pack.id}: the preview is current`); } }); test('every Store icon pack parses with the app parser, keeps all its glyphs and is within the limits', () => { for (const id of STORE_ICON_IDS as string[]) { const json = read(id, `${id}.icons.json`); assert.ok(json.length <= ICON_LIMITS.packBytes, `${id}: at most 120 KB`); const parsed = parseIconPackJson(json); assert.ok(!('error' in parsed), `${id} parses`); const { pack, warnings } = parsed as Exclude; assert.equal(pack.id, id); assert.deepEqual(warnings, [], `${id}: nothing is dropped, the license is named`); assert.equal(pack.license, 'own'); const item = JSON.parse(read(id, 'item.json')); assert.equal(item.category, 'icons'); assert.ok(item.license && item.credits, `${id}: item.json names the license and the credits`); } }); test('the retro packs draw X\'s whole left rail and action bar, and the sheet carries every one of them', () => { const needed = Object.keys(X_ICONS).filter(name => ['nav', 'actions'].includes(X_ICONS[name as IconName]!.group)) as IconName[]; for (const pack of RETRO_PACKS) { for (const name of needed) assert.ok(pack.glyphs[name], `${pack.id} draws ${name}`); const css = compileIcons(pack, null, X_ICONS, { allowed: true, colors: null }); for (const name of needed) assert.ok(css.includes(X_ICONS[name]!.ctx!.split(',')[0]!), `${pack.id}: the sheet has a rule for ${name}`); assert.doesNotMatch(css, / { for (const pack of RETRO_PACKS) { for (const [name, glyph] of Object.entries(pack.glyphs)) assert.ok('layers' in glyph!, `${pack.id}.${name} is layers`); } }); test('no retro pack names an outside source for its drawings', () => { for (const pack of RETRO_PACKS) { const text = JSON.stringify(pack) + read(pack.id, 'item.json'); assert.doesNotMatch(text, /shell32|iconarchive|win98icons|msn1999/i, `${pack.id}: our own drawings only`); } });