Files
Rogeeandrogee eda4889d85 HH-549: serve the default favicon (#147)
* chore(agent): baseline — uncommitted work from the local directory

* HH-549: serve the default favicon

* Revert "chore(agent): baseline — uncommitted work from the local directory"

This reverts commit 4a3fabe624bfdc52bf935b62cb9871b7de9b3083.

---------

Co-authored-by: Rogee <rogee@ipao.vip>
2026-08-24 10:09:24 +08:00

67 lines
2.2 KiB
JavaScript

import assert from 'node:assert/strict';
import { existsSync, readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
const dist = fileURLToPath(new URL('../dist/', import.meta.url));
const html = readFileSync(
new URL('../dist/index.html', import.meta.url),
'utf8'
);
const assets = [...html.matchAll(/(?:href|src)="(\/assets\/[^"]+)"/g)].map(
match => match[1]
);
const manifest = JSON.parse(
readFileSync(new URL('../dist/manifest.json', import.meta.url), 'utf8')
);
assert.match(html, /<div id="app"><\/div>/);
assert.match(html, /<link\s+rel="manifest"\s+href="\/manifest\.json"\s*\/?>/);
assert.match(
html,
/<script\b[^>]*\bsrc="\/runtime-config\.js"[^>]*><\/script>/
);
assert.ok(
readFileSync(new URL('../dist/favicon.ico', import.meta.url)).equals(
readFileSync(new URL('../public/favicon-32x32.png', import.meta.url))
),
'favicon.ico must reuse the GoChat favicon'
);
assert.ok(
html.indexOf('/runtime-config.js') < html.indexOf('type="module"'),
'runtime config must load before the app module'
);
assert.ok(
assets.some(asset => asset.endsWith('.js')),
'missing JS asset'
);
assert.ok(
assets.some(asset => asset.endsWith('.css')),
'missing CSS asset'
);
assert.ok(!/<script(?![^>]*\bsrc=)[^>]*>/i.test(html), 'inline script found');
assets.forEach(asset => assert.ok(existsSync(dist + asset.slice(1)), asset));
for (const size of [192, 512]) {
const dimensions = `${size}x${size}`;
const icon = manifest.icons.find(item => item.sizes === dimensions);
assert.equal(icon?.type, 'image/png', `missing ${dimensions} PNG icon`);
const png = readFileSync(dist + icon.src.slice(1));
assert.deepEqual(
[...png.subarray(0, 8)],
[137, 80, 78, 71, 13, 10, 26, 10]
);
assert.equal(png.readUInt32BE(16), size, `${icon.src} width`);
assert.equal(png.readUInt32BE(20), size, `${icon.src} height`);
}
const dashboard = assets
.filter(asset => asset.endsWith('.js'))
.map(asset => readFileSync(dist + asset.slice(1), 'utf8'))
.join('\n');
assert.doesNotMatch(
dashboard,
/=\(?function\(\)\{return this\}\)?\(\);try\{([A-Za-z_$][\w$]*)=\1\|\|new Function\("return this"\)\(\)/,
'dashboard contains a CSP-blocked UMD global shim'
);