vitest + happy-dom tests of the UI-SPEC backstops: E1 status thresholds (29/30 characters, 580/581 px; 119/120 and 920/921 for descriptions) with a mocked measureText and the counter's wrap contract; the E2 grammar over every directive combination, the emitted values and the stacking contract with unclipped en and pl labels; the E3 effective title, word-boundary truncation and keyphrase stem matching; each E4 lint rule and a clean file; E6 apply gating. happy-dom has no layout engine, so the narrow-width rows check the stylesheet's layout contract.
28 lines
1.1 KiB
TypeScript
28 lines
1.1 KiB
TypeScript
/// <reference types="node" />
|
|
import { readFileSync } from 'node:fs'
|
|
|
|
// The element stylesheet for layout backstops. Vitest stubs CSS imports, so
|
|
// the file is read from disk (vitest runs from the plugin root). happy-dom
|
|
// has no layout engine: the backstops check the layout contract instead.
|
|
|
|
export const css = readFileSync(`${process.cwd()}/assets/src/elements/styles.css`, 'utf8')
|
|
|
|
/** The declarations of every rule (outside @media) whose selector list names selector. */
|
|
export function rule(selector: string, sheet = css): Record<string, string> {
|
|
const out: Record<string, string> = {}
|
|
const body = sheet.replace(/\/\*[\s\S]*?\*\//g, '').replace(/@media[^{]*\{(?:[^{}]*\{[^{}]*\})*[^{}]*\}/g, '')
|
|
for (const match of body.matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
|
|
const selectors = match[1].split(',').map((s) => s.trim())
|
|
if (!selectors.includes(selector)) {
|
|
continue
|
|
}
|
|
for (const decl of match[2].split(';')) {
|
|
const colon = decl.indexOf(':')
|
|
if (colon > 0) {
|
|
out[decl.slice(0, colon).trim()] = decl.slice(colon + 1).trim()
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|