import test from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..') const css = readFileSync(path.join(root, 'src/styles/chat.css'), 'utf8') const thread = readFileSync(path.join(root, 'src/components/chat/ChatThread.jsx'), 'utf8') // Quelltext ohne Kommentare: der Kopfkommentar darf "!important" und "720 px" nennen, ohne die Prüfungen zu reißen const rules = css.replace(/\/\*[\s\S]*?\*\//g, '') // Alle Selektoren (ohne @-Regeln), Kommas gesplittet const selectors = [...rules.matchAll(/([^{}]+)\{/g)] .map((m) => m[1].trim()) .filter((s) => s && !s.startsWith('@')) .flatMap((s) => s.split(',').map((x) => x.trim())) // Fremde Klassen des Portal-Bausteins (chat-composer.css): jede Regel darüber braucht das Präfix .woms-chat const FREMD = /\.chat-(bubble|meta|messages|notice|input-row|icon-btn|send|menu|tray|rec|audio|att|file|composer|drop-active)\b/ test('chat.css: jede Regel für Klassen des Portal-Bausteins beginnt mit .woms-chat', () => { const bad = selectors.filter((s) => FREMD.test(s) && !s.startsWith('.woms-chat')) assert.deepEqual(bad, []) }) test('chat.css: kein !important (Spezifität statt Gewalt, Portal-CSS lädt zuletzt)', () => { assert.doesNotMatch(rules, /!important/) }) test('chat.css: Umschaltung Liste/Verlauf bei 860 px, kein 720-px-Wert mehr', () => { assert.match(rules, /@media \(max-width: 860px\)/) assert.doesNotMatch(rules, /720px/) }) test('ChatThread: die drei Container des Portal-Bausteins bleiben unverändert', () => { assert.ok(thread.includes('className="woms-chat" ref={zoneRef}')) assert.ok(thread.includes('className="chat-messages" ref={boxRef}')) assert.ok(thread.includes('
')) }) test('chat.css: .chat-page .chat-back ist außerhalb der Handyansicht verborgen (schlägt .btn aus global.css)', () => { assert.match(rules, /\.chat-page \.chat-back\s*\{[^}]*display:\s*none/) })