- gelöscht: components/workers/engine/* (10 Dateien), WorkersStage, WorkersBoard, WorkerCard, WorkerList, WorkersKpis, die neun Engine-Tests samt workersSmoke (211 Tests) und die Helfer engineVm.mjs und fakeCtx.mjs (nur die Engine-Tests brauchten sie) - workers.css (310 -> 60 Zeilen) behält nur Einstellungen-Dialog und Interessenten-Panel; @font-face für Pixelify Sans steht jetzt in hustler/schrift.css - workersComponents: kein innerHTML und kein Kanvas rekursiv unter components/workers/**, jeder Knopf mit type, Links nur aus geprüften Feldern (externe mit noopener), keine Anmeldung in den Bildschirmen, alte Dateien weg und nirgends mehr importiert - workersCss: jede wk-Klasse im Code hat eine Regel, keine Regel ohne Nutzer; workersFont: Pixelify Sans genau einmal in schrift.css - hustlerAssets: Pixelify Sans in schrift.css erlaubt; hustlerDialog: Link-Ziele nur aus safeLink, Knöpfe mit type; hustlerSeite: Laden/Fehler/bereit am selben Einhängepunkt Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
39 lines
2.8 KiB
JavaScript
39 lines
2.8 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
import path from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
test('Schrift: woff2-Magic-Bytes, plausible Größe, OFL-Lizenztext', () => {
|
|
const buf = readFileSync(new URL('../../public/fonts/PixelifySans-Variable.woff2', import.meta.url)); assert.equal(buf.subarray(0, 4).toString('latin1'), 'wOF2'); assert.ok(buf.length > 10000 && buf.length < 400000, String(buf.length))
|
|
const lic = readFileSync(new URL('../../public/fonts/OFL-PixelifySans.txt', import.meta.url), 'utf8'); assert.match(lic, /SIL OPEN FONT LICENSE Version 1\.1/); assert.match(lic, /Pixelify Sans/)
|
|
})
|
|
|
|
// Seit T11 (Pixelwelt) steht die Einbindung von Pixelify Sans neben Press Start 2P in styles/hustler/schrift.css; workers.css hat keine Schrift mehr.
|
|
const stylesDir = fileURLToPath(new URL('../../src/styles/', import.meta.url))
|
|
const walk = (dir) => readdirSync(dir, { withFileTypes: true }).flatMap((e) => (e.isDirectory() ? walk(path.join(dir, e.name)) : [path.join(dir, e.name)]))
|
|
const ohneKommentare = (css) => css.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
const fontFaces = () => walk(stylesDir)
|
|
.filter((f) => f.endsWith('.css'))
|
|
.flatMap((f) => [...ohneKommentare(readFileSync(f, 'utf8')).matchAll(/@font-face\s*\{[^}]*\}/g)].map((m) => ({ datei: path.relative(stylesDir, f), regel: m[0] })))
|
|
|
|
test('Pixelify Sans: genau eine @font-face-Regel in src/styles, in hustler/schrift.css (selbst gehostet, swap, Gewichte 400-700)', () => {
|
|
const pixelify = fontFaces().filter((r) => /font-family:\s*["']Pixelify Sans["']/.test(r.regel))
|
|
assert.equal(pixelify.length, 1, 'genau eine Einbindung')
|
|
assert.equal(pixelify[0].datei, 'hustler/schrift.css')
|
|
const regel = pixelify[0].regel
|
|
assert.match(regel, /src:\s*url\(["']?\/fonts\/PixelifySans-Variable\.woff2["']?\)\s*format\(["']woff2["']\)/)
|
|
assert.match(regel, /font-display:\s*swap/)
|
|
assert.match(regel, /font-weight:\s*400 700/)
|
|
assert.doesNotMatch(regel, /googleapis|gstatic|https?:/)
|
|
// workers.css bindet keine Schrift mehr ein
|
|
assert.doesNotMatch(ohneKommentare(readFileSync(path.join(stylesDir, 'workers.css'), 'utf8')), /@font-face/)
|
|
})
|
|
|
|
test('jede selbst gehostete Schrift in src/styles liegt unter public/fonts und hat dort ihren Lizenztext', () => {
|
|
const dateien = fontFaces().flatMap((r) => [...r.regel.matchAll(/url\(\s*["']?(\/fonts\/[\w.-]+)["']?\s*\)/g)].map((m) => m[1]))
|
|
assert.ok(dateien.length >= 2, 'mindestens Press Start 2P und Pixelify Sans')
|
|
for (const datei of dateien) assert.ok(existsSync(fileURLToPath(new URL('../../public' + datei, import.meta.url))), `${datei} fehlt in public/`)
|
|
for (const lizenz of ['OFL-PressStart2P.txt', 'OFL-PixelifySans.txt']) assert.ok(existsSync(fileURLToPath(new URL('../../public/fonts/' + lizenz, import.meta.url))), lizenz)
|
|
})
|