mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
77 lines
3.8 KiB
TypeScript
77 lines
3.8 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import { serveExport, read } from './export'
|
|
|
|
/**
|
|
* Zen is the family, and there is ONE place that says so.
|
|
*
|
|
* `@hanzo/design`'s `tokens/fonts.css` declares the two @font-face rules against
|
|
* the woff2 files inside the package and names them as `--font-sans` and
|
|
* `--font-mono`; every token in design and @hanzo/ui reads those two names, and
|
|
* this app names no face of its own.
|
|
*
|
|
* Asserted against the EXPORT and after `document.fonts.ready`, because the way
|
|
* this breaks is invisible in the source. A binding reads correctly in the
|
|
* source whether or not it WINS: @hanzo/ui carries an inlined copy of an older
|
|
* token sheet and loads after design's, so a plain `:root` ties and loses
|
|
* on order, and the whole site paints the previous family while the source says
|
|
* Zen. Only the computed value shows which side won, and only a rendered element
|
|
* shows that the winner is what the reader sees.
|
|
*
|
|
* This app used to override those three names at `html:root` to outrank the
|
|
* package sheet, with a note to delete them the day @hanzo/ui shipped Zen. It
|
|
* has (8.3.4, against design 0.5.21), they are gone, and this is the check that
|
|
* said so — so it does not have to be re-derived by hand each time.
|
|
*/
|
|
test('the shipped page renders Zen, through the one binding', async ({ page }) => {
|
|
const server = await serveExport()
|
|
try {
|
|
await page.goto(server.url, { waitUntil: 'load' })
|
|
const seen = await page.evaluate(async () => {
|
|
await document.fonts.ready
|
|
const cs = getComputedStyle(document.documentElement)
|
|
const h1 = document.querySelector('h1')
|
|
return {
|
|
sans: cs.getPropertyValue('--font-sans').trim(),
|
|
display: cs.getPropertyValue('--font-sans').trim(),
|
|
mono: cs.getPropertyValue('--font-mono').trim(),
|
|
body: getComputedStyle(document.body).fontFamily,
|
|
heading: h1 ? getComputedStyle(h1).fontFamily : '',
|
|
// A face reports "loaded" only once something on the page rendered in
|
|
// it, so this is the half that a token read cannot fake.
|
|
zenLoaded: [...document.fonts].some((f) => f.family === 'Zen' && f.status === 'loaded'),
|
|
}
|
|
})
|
|
// Zen leads every stack. What follows it is the fallback a reader gets in
|
|
// the moment before the woff2 lands, and it stays.
|
|
expect(seen.sans).toMatch(/^'?"?Zen'?"?,/)
|
|
expect(seen.mono).toMatch(/^'?"?Zen Mono'?"?,/)
|
|
expect(seen.display).toContain('Zen')
|
|
// …and the page actually resolves to it. This is the assertion that would
|
|
expect(seen.body).toMatch(/^Zen\b/)
|
|
expect(seen.heading).toMatch(/^Zen\b/)
|
|
expect(seen.zenLoaded).toBe(true)
|
|
} finally {
|
|
await server.close()
|
|
}
|
|
})
|
|
|
|
test('no font loader, and the app names no family of its own', () => {
|
|
// Read past the prose: a gate that matches on a word fails on its own
|
|
// explanation, and these files explain at length. Strip BLOCK comments too —
|
|
// the old stripper only caught a line whose first character was `*`, so a
|
|
// wrapped sentence inside `/* … */` still counted as source.
|
|
const code = (path: string) =>
|
|
read(path).replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '')
|
|
|
|
const layout = code('../app/layout.tsx')
|
|
expect(layout).not.toMatch(/from\s+['"]next\/font/)
|
|
expect(layout).not.toMatch(/\bGeist(_Mono)?\s*\(/)
|
|
|
|
// The FACE is @hanzo/design's to name, and since @hanzo/ui 8.3.4 its inlined
|
|
// copy of that token block says Zen too — so this app names no family at all,
|
|
// and it authors no stylesheet to name one in: every sheet the layout imports
|
|
// is a package's, or gui's sheet generated from lib/gui.ts.
|
|
const own = [...layout.matchAll(/import\s+['"](\.[^'"]*\.css)['"]/g)].map((m) => m[1])
|
|
expect(own.filter((s) => s !== './gui.css'), 'the layout imports a stylesheet of our own').toEqual([])
|
|
})
|