test(web): pin favicon fallback format, order, and media-query binding

The pwa-manifest e2e now asserts the shipped 32x32 PNG is a valid non-empty
PNG of the declared dimensions, that the PNG link precedes the SVG link in
the built index.html (the spec selects the last equally appropriate icon),
and that the light fill lives inside the dark-scheme media query while the
light-mode default stays black.
This commit is contained in:
_Kerman
2026-08-10 12:56:24 +08:00
parent e8f884ba35
commit c4203677c0
+19 -2
View File
@@ -5,10 +5,17 @@ import { expect, it } from 'vitest'
const DIST_ROOT = fileURLToPath(new URL('../dist', import.meta.url))
/** PNG signature per the PNG specification. */
const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]
it('ships install metadata with the built web application', async () => {
const index = await readFile(join(DIST_ROOT, 'index.html'), 'utf8')
expect(index).toContain('<link rel="manifest" href="/manifest.webmanifest" />')
expect(index).toContain('<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />')
// The SVG must stay declared after the PNG: the HTML spec selects the last
// equally appropriate icon, so SVG-capable browsers get the adaptive SVG
// while Safari versions before 26 fall back to the PNG.
expect(index.indexOf('/favicon-32x32.png')).toBeLessThan(index.indexOf('/favicon.svg'))
const manifest: unknown = JSON.parse(await readFile(join(DIST_ROOT, 'manifest.webmanifest'), 'utf8'))
expect(manifest).toEqual({
@@ -35,8 +42,18 @@ it('ships install metadata with the built web application', async () => {
})
})
it('ships the PNG fallback as a valid non-empty 32x32 image', async () => {
const png = await readFile(join(DIST_ROOT, 'favicon-32x32.png'))
expect([...png.subarray(0, 8)]).toEqual(PNG_SIGNATURE)
expect(png.readUInt32BE(16)).toBe(32)
expect(png.readUInt32BE(20)).toBe(32)
expect(png.length).toBeGreaterThan(0)
})
it('ships a favicon that switches to a light mark under dark color scheme', async () => {
const favicon = await readFile(join(DIST_ROOT, 'favicon.svg'), 'utf8')
expect(favicon).toContain('@media (prefers-color-scheme: dark)')
expect(favicon).toMatch(/path\s*{[^}]*fill:\s*#fff/i)
// The light fill must live inside the dark-scheme media query, so the icon
// stays black in light mode and only turns white under a dark scheme.
expect(favicon).toMatch(/@media \(prefers-color-scheme: dark\)\s*{\s*path\s*{[^}]*fill:\s*#fff/i)
expect(favicon).toContain('fill="#000"')
})