30 lines
3.2 KiB
JavaScript
30 lines
3.2 KiB
JavaScript
import { test } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFileSync, existsSync } from 'node:fs'
|
|
import { K } from '../public/neu/ansicht-hilfen.js'
|
|
|
|
const css = (f) => readFileSync(new URL(`../public/neu/${f}`, import.meta.url), 'utf8')
|
|
const lese = (p) => readFileSync(new URL(`../public/${p}`, import.meta.url), 'utf8')
|
|
const A = css('ansichten.css'); const O = css('oeffentlich/oeffentlich.css'); const C = css('chat-composer.css'); const BASIS = css('basis.css'); const TOKENS = css('tokens.css')
|
|
const MODULE = ['ansicht-hilfen', 'rechnung-offen', 'install-hinweis', 'website-details', 'ansicht-website', 'ansicht-chat', 'ansicht-vertraege', 'vertraege-rechnungen', 'vertraege-abo', 'ansicht-stunden', 'ansicht-speicher', 'ansicht-bestellen', 'ansicht-wechsel', 'ansicht-gutschrift', 'ansicht-passwort']
|
|
const existiert = (n) => existsSync(new URL(`../public/neu/${n}.js`, import.meta.url))
|
|
const lies = (n) => css(`${n}.js`).replace(/\/\*[\s\S]*?\*\//g, '')
|
|
const VERBOTEN = /linear-gradient|radial-gradient|conic-gradient|backdrop-filter|prefers-color-scheme:\s*dark|font-weight:\s*800|#9d3dfe|rgba?\(\s*157\s*,\s*61/i
|
|
test('Stil: keine verbotenen Mittel (Verläufe, Glas, Dunkelmodus, Lila, Gewicht 800), auch nicht in der Kopie des Composer-CSS', () => { for (const [n, c] of [['ansichten.css', A], ['oeffentlich.css', O], ['chat-composer.css', C]]) assert.doesNotMatch(c, VERBOTEN, n) })
|
|
test('Stil: Farbliterale nur in Custom-Property-Deklarationen, jedes benutzte Token ist definiert', () => {
|
|
for (const [n, c] of [['ansichten.css', A], ['oeffentlich.css', O]]) for (const z of c.split('\n')) if (!/^\s*--kn-[\w-]+:/.test(z)) assert.doesNotMatch(z, /#[0-9a-f]{3,8}\b|rgba?\(/i, `${n}: ${z.trim()}`)
|
|
const definiert = new Set([...(TOKENS + A + O).matchAll(/(--kn-[\w-]+)\s*:/g)].map((m) => m[1]))
|
|
for (const m of (A + O).matchAll(/var\((--kn-[\w-]+)/g)) assert.ok(definiert.has(m[1]), m[1])
|
|
})
|
|
test('Stil: jede kn-Klasse der P2-Module hat eine Regel', () => {
|
|
const klassen = new Set(); for (const n of MODULE.filter(existiert)) for (const m of lies(n).matchAll(/class:\s*'([^']+)'/g)) m[1].split(/\s+/).filter((k) => k.startsWith('kn-')).forEach((k) => klassen.add(k))
|
|
for (const wert of Object.values(K).flatMap((v) => (typeof v === 'string' ? [v] : Object.values(v)))) wert.split(/\s+/).filter((k) => k.startsWith('kn-')).forEach((k) => klassen.add(k))
|
|
for (const k of klassen) assert.match(BASIS + A, new RegExp(`\\.${k}(?![\\w-])`), `Klasse ohne Regel: ${k}`)
|
|
})
|
|
test('Stil: Aufträge-Abschnitt, Chat-Variablen, hidden und Handy-Abfrage', () => {
|
|
const ab = new Set([...(lese('auftrag-dom.js') + lese('auftrag-portal.js')).matchAll(/\bab-[a-z0-9]+(?:-[a-z0-9]+)*/g)].map((m) => m[0]))
|
|
for (const k of [...ab, 'ab-pille-warn', 'ab-pille-ok', 'ab-pille-rot'].filter((x) => x !== 'ab-portal')) assert.match(A, new RegExp(`\\.kn \\.ab-portal[^{]*\\.${k}(?![\\w-])`), k)
|
|
for (const v of ['accent', 'accent-hover', 'accent-soft', 'accent-line', 'accent-text', 'on-accent', 'line', 'muted', 'surface']) assert.match(A, new RegExp(`\\.kn-chat[^{]*\\{[^}]*--chat-${v}:`), v)
|
|
assert.match(A, /\.kn \.hidden\s*\{[^}]*display:\s*none/); assert.ok(A.includes('(max-width: 880px), (pointer: coarse) and (max-height: 500px)'))
|
|
})
|