Design-Tokens aus docs/10-design-system.md als CSS-Variablen: Grundpalette, die sechs Klassifizierungsfarben, Eckenradius durchgehend 2 px, keine Schatten ausser dem Fokusring. Der Schwärzungsbalken mit dem einmaligen Durchwischen respektiert prefers-reduced-motion. Vier Tests halten die Tokens gegen das Dokument. IBM Plex selbst gehostet als woff2, latin und latin-ext getrennt über unicode-range, font-display: swap, immutable-Cache. Alle Oberflächentexte in lib/i18n/de.ts. Ein Test durchsucht app/ und components/ nach Umlauten im JSX und schlägt fehl, wenn dort deutscher Text steht. Er hat beim ersten Lauf gleich einen Verstoss gefunden. /api/health prüft Datenbank, Discord-Gateway und ClamAV. Die Gesamtbewertung fällt nur auf "down", wenn die Datenbank weg ist: die anderen Dienste haben eigene Healthchecks im Stack, und ein ausgefallener Virenscanner soll nicht den Web-Container als tot markieren. Strikte CSP mit Nonce, kein unsafe-inline für Skripte. Die erste Route liegt bei 100 kB JavaScript nach Kompression, Budget sind 120 kB.
36 lines
1.3 KiB
TypeScript
36 lines
1.3 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { readFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
|
|
const css = readFileSync(join(process.cwd(), 'app/globals.css'), 'utf8')
|
|
|
|
describe('Design-Tokens', () => {
|
|
it('enthaelt die Grundpalette aus dem Design-System', () => {
|
|
for (const hex of ['#15181a', '#1d2124', '#262b2f', '#3a4147', '#e4e7e4', '#939c99', '#7a97a6']) {
|
|
expect(css).toContain(hex)
|
|
}
|
|
})
|
|
|
|
it('enthaelt alle sechs Klassifizierungsfarben', () => {
|
|
for (const hex of ['#8a918d', '#6d8a9c', '#4e8f72', '#b08637', '#b4543c', '#7e5e96']) {
|
|
expect(css).toContain(hex)
|
|
}
|
|
})
|
|
|
|
it('setzt den Eckenradius durchgehend auf 2 px', () => {
|
|
const radii = [...css.matchAll(/--radius-[\w-]+:\s*([^;]+);/g)].map((m) => m[1]!.trim())
|
|
expect(radii.length).toBeGreaterThan(0)
|
|
for (const value of radii) expect(['0px', '2px']).toContain(value)
|
|
})
|
|
|
|
it('kennt keine Schatten ausser dem Fokusring', () => {
|
|
const shadows = [...css.matchAll(/--shadow-[\w-]+:\s*([^;]+);/g)].map((m) => m[1]!.trim())
|
|
expect(shadows.length).toBeGreaterThan(0)
|
|
for (const value of shadows) expect(value).toBe('none')
|
|
})
|
|
|
|
it('respektiert prefers-reduced-motion bei der Schwaerzung', () => {
|
|
expect(css).toMatch(/@media \(prefers-reduced-motion: reduce\)/)
|
|
})
|
|
})
|