37 lines
1.6 KiB
TypeScript
37 lines
1.6 KiB
TypeScript
import { existsSync, readFileSync } from 'node:fs'
|
||
import { fileURLToPath } from 'node:url'
|
||
import { describe, expect, it } from 'vitest'
|
||
|
||
// Every showcase visit 404'd on both /favicon.ico and /favicon.svg (stage sweep,
|
||
// 2026-10-11) because the template shipped no favicon at all. `app/favicon.ico` is
|
||
// Next's own file convention for /favicon.ico; `public/favicon.svg` is a plain static
|
||
// file for /favicon.svg, which Next's convention does not cover (it only serves
|
||
// `icon.svg` at /icon.svg). The root layout's `metadata.icons` must name both, so the
|
||
// rendered <link> tags match what is actually shipped.
|
||
describe('favicon', () => {
|
||
it('ships a valid favicon.ico for Next’s /favicon.ico convention', () => {
|
||
const path = fileURLToPath(new URL('../app/favicon.ico', import.meta.url))
|
||
expect(existsSync(path)).toBe(true)
|
||
const bytes = readFileSync(path)
|
||
// ICO header: reserved=0, type=1 (icon), at least one image.
|
||
expect(bytes.readUInt16LE(0)).toBe(0)
|
||
expect(bytes.readUInt16LE(2)).toBe(1)
|
||
expect(bytes.readUInt16LE(4)).toBeGreaterThan(0)
|
||
})
|
||
|
||
it('ships public/favicon.svg, served verbatim at /favicon.svg', () => {
|
||
const path = fileURLToPath(new URL('../public/favicon.svg', import.meta.url))
|
||
expect(existsSync(path)).toBe(true)
|
||
expect(readFileSync(path, 'utf8')).toContain('<svg')
|
||
})
|
||
|
||
it('names both favicons in the root layout’s metadata', () => {
|
||
const layout = readFileSync(
|
||
new URL('../src/app/layouts/root.tsx', import.meta.url),
|
||
'utf8',
|
||
)
|
||
expect(layout).toMatch(/\/favicon\.svg/)
|
||
expect(layout).toMatch(/\/favicon\.ico/)
|
||
})
|
||
})
|