import { test } from 'node:test' import assert from 'node:assert/strict' import { installFakeDom } from './support/fakeDom.js' import { h } from '../public/neu/dom.js' import { baueEtage } from '../public/neu/etage.js' import { lies, handyTeil } from './support/knHuelle.js' const teile = () => ({ blatt: h('div', { hidden: true }, h('section', { 'data-etage': 'termine' })), haupt: h('main'), zeile: h('div'), zurueckSlot: h('div'), titel: h('h1'), brot: h('nav'), reiterSlot: h('div') }) const REITER = ['Termine', 'Leistungen', 'Team & Plätze', 'Einstellungen', 'Kalender', 'Rechnungen'].map((label, i) => ({ key: `r${i}`, label, kurz: label.split(' ')[0] })) const EL = { label: 'Funktionen', hash: '#funktionen' } test('oeffne und schliesse: Titel, Zurück oben rechts mit Ziel, Brotkrume, Hauptseite gesperrt', async () => { const fx = installFakeDom() try { const t = teile(); let zu = 0; const e = baueEtage({ ...t, istHandy: () => true, onZurueck: () => { zu += 1 } }) e.oeffne({ titel: 'Terminplaner', eltern: EL, seite: 'termine' }) assert.deepEqual([t.blatt.hidden, t.haupt.getAttribute('inert'), e.istOffen(), t.titel.textContent], [false, '', true, 'Terminplaner']) assert.deepEqual([fx.text(t.brot), fx.finde(t.brot, 'a').getAttribute('href')], ['Funktionen / Terminplaner', '#funktionen']) const z = fx.finde(t.zurueckSlot, 'button'); assert.deepEqual([z.textContent, z.getAttribute('aria-label'), t.zeile.children.length], ['Zurück', 'Zurück zu Funktionen', 0]) await fx.klick(z); assert.equal(zu, 1) e.schliesse(); assert.deepEqual([t.blatt.hidden, t.haupt.hasAttribute('inert'), fx.alle(t.zurueckSlot, 'button').length], [true, false, 0]) } finally { fx.restore() } }) test('kn:reiter vom Inhalt: Handy Kurzlabels als Wasser-Leiste in der Zeile, Desktop Unterstrich im Slot, ohne Reiter bleibt die Zeile leer (C2)', async () => { const fx = installFakeDom() try { const gew = []; let handy = true; const t = teile(); const e = baueEtage({ ...t, istHandy: () => handy, onZurueck() {} }) e.oeffne({ titel: 'Terminplaner', eltern: EL, seite: 'termine' }); const kind = t.blatt.children[0] await fx.sende(kind, 'kn:reiter', { detail: { eintraege: REITER, aktiv: 'r0', bei: (k) => gew.push(k) } }) const tabs = fx.alle(t.zeile, '[role=tab]') assert.deepEqual(tabs.map((x) => x.textContent), ['Termine', 'Leistungen', 'Team', 'Einstellungen', 'Kalender', 'Rechnungen']); assert.equal(tabs[2].getAttribute('aria-label'), 'Team & Plätze') assert.deepEqual([fx.finde(t.zeile, '.kn-wl').getAttribute('data-art'), fx.alle(t.zeile, 'button:not([role=tab])').length], ['reiter', 0]) // unten kein Zurück await fx.klick(tabs[2]); assert.deepEqual(gew, ['r2']) await fx.sende(kind, 'kn:reiter', { detail: { eintraege: [], aktiv: '', bei() {} } }) assert.deepEqual([t.zeile.children.length, fx.alle(t.zurueckSlot, '.kn-zurueck').length], [0, 1]) handy = false; e.neuZeichnen(); await fx.sende(kind, 'kn:reiter', { detail: { eintraege: REITER, aktiv: 'r0', bei() {} } }) assert.deepEqual([fx.alle(t.reiterSlot, '[role=tab]').length, fx.alle(t.zeile, '[role=tab]').length], [6, 0]) await fx.sende(kind, 'kn:titel', { detail: { text: 'Kalender' } }); assert.equal(t.titel.textContent, 'Kalender') } finally { fx.restore() } }) test('Chat-Punkt am Zurück', () => { const fx = installFakeDom() try { const t = teile(); const e = baueEtage({ ...t, istHandy: () => true, onZurueck() {} }) e.oeffne({ titel: 'Webshop', eltern: EL, seite: 'webshop' }); e.setzeChatPunkt(true) assert.ok(fx.finde(t.zurueckSlot, '.kn-punkt')); assert.equal(fx.finde(t.zurueckSlot, 'button').getAttribute('aria-label'), 'Zurück zu Funktionen, neue Nachricht im Chat') } finally { fx.restore() } }) test('Blatt am Handy: ganzer Bildschirm, mit Unschärfe eingeblendet, Zurück als Glasknopf oben rechts (Glas nur in wasser-leiste.css), Desktop ohne', () => { const css = lies('huelle.css'); const handy = handyTeil(css); const wl = handyTeil(lies('wasser-leiste.css')) assert.match(handy, /\.kn-blatt\s*\{(?=[^}]*inset:\s*calc\(var\(--kn-banner-h\) \+ env\(safe-area-inset-top\)\) 0 0)(?=[^}]*opacity:\s*0)/s) assert.doesNotMatch(handy, /translateY\(100%\)\s*;\s*transition:\s*transform 550ms/) // fährt nicht mehr hoch assert.match(handy, /\.kn-blatt-zurueck\s*\{(?=[^}]*position:\s*fixed)(?=[^}]*right:\s*max\(16px, env\(safe-area-inset-right\)\))/s) assert.match(handy, /\.kn-blatt--auf ~ \.kn-blatt-zurueck\s*\{[^}]*visibility:\s*visible/) assert.match(css.slice(0, css.indexOf('@media')), /\.kn-blatt-zurueck\s*\{\s*display:\s*none/) // Desktop: Brotkrume statt Zurück assert.match(wl, /\.kn-blatt\s*\{\s*filter:\s*blur\(14px\);\s*transition:[^}]*filter/) assert.match(wl, /\.kn-blatt--auf\s*\{\s*filter:\s*none/) assert.match(wl, /\.kn-blatt-zurueck \.kn-zurueck\s*\{[^}]*backdrop-filter:\s*blur/) assert.match(lies('wasser-leiste.css'), /@media \(prefers-reduced-motion: reduce\)[\s\S]*\.kn-blatt\s*\{\s*filter:\s*none/) assert.match(lies('dashboard.html'), /<\/div>\s*