Kundenansicht neu P1: Etage 2 mit Zurück, Reiterzeile und Brotkrume
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a51643c4a5
commit
748226d631
3 files changed
+228
No files matched your search
@@ -0,0 +1,79 @@
|
||||
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'), 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 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.zeile, 'button'); assert.deepEqual([z.textContent, z.getAttribute('aria-label')], ['Zurück', 'Zurück zu Funktionen'])
|
||||
await fx.klick(z); assert.equal(zu, 1)
|
||||
e.schliesse(); assert.deepEqual([t.blatt.hidden, t.haupt.hasAttribute('inert'), fx.alle(t.zeile, 'button').length], [true, false, 0])
|
||||
} finally { fx.restore() }
|
||||
})
|
||||
|
||||
test('kn:reiter vom Inhalt: Handy Kurzlabels in der Zeile, Desktop Unterstrich im Slot, ohne Reiter füllt Zurück die Zeile (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')
|
||||
await fx.klick(tabs[2]); assert.deepEqual(gew, ['r2'])
|
||||
await fx.sende(kind, 'kn:reiter', { detail: { eintraege: [], aktiv: '', bei() {} } })
|
||||
assert.deepEqual([fx.alle(t.zeile, '[role=tab]').length, Boolean(fx.finde(t.zeile, '.kn-zurueck--voll'))], [0, true])
|
||||
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.zeile, '.kn-punkt')); assert.equal(fx.finde(t.zeile, 'button').getAttribute('aria-label'), 'Zurück zu Funktionen, neue Nachricht im Chat')
|
||||
} finally { fx.restore() }
|
||||
})
|
||||
|
||||
test('huelle.css (Blatt): Handy fährt von unten ein, Zurück füllt die Zeile', () => {
|
||||
const css = lies('huelle.css')
|
||||
assert.match(handyTeil(css), /\.kn-blatt\s*\{(?=[^}]*border-radius:\s*12px 12px 0 0)(?=[^}]*transition:[^}]*550ms[^}]*var\(--kn-bremse\))/s)
|
||||
assert.match(css, /\.kn-zurueck--voll\s*\{[^}]*flex:\s*1/s)
|
||||
})
|
||||
|
||||
test('Etage: Brotkrume führt wie Zurück, Chat-Punkt bleibt für die nächste Etage, Reiter anderer Seiten und Reste werden verworfen, gleiche Reiter bleiben stehen', async () => {
|
||||
const fx = installFakeDom()
|
||||
try {
|
||||
const t = teile(); t.blatt.append(h('section', { 'data-etage': 'webshop' })); let zu = 0
|
||||
const e = baueEtage({ ...t, istHandy: () => true, onZurueck: () => { zu += 1 } })
|
||||
e.setzeChatPunkt(true) // vor dem Öffnen gemerkt
|
||||
e.oeffne({ titel: 'Terminplaner', eltern: EL, seite: 'termine' }); assert.ok(fx.finde(t.zeile, '.kn-punkt'))
|
||||
assert.deepEqual(t.blatt.children.map((s) => s.hidden), [false, true]) // nur die Seite der Etage ist sichtbar
|
||||
await fx.klick(fx.finde(t.brot, 'a'))
|
||||
assert.equal(zu, 1) // Klick auf die Brotkrume: wie Zurück, ohne Fragment-Navigation
|
||||
const [termine, shop] = t.blatt.children
|
||||
await fx.sende(shop, 'kn:reiter', { detail: { eintraege: REITER, aktiv: 'r0', bei() {} } }) // Reiter einer verborgenen Seite: ignoriert
|
||||
assert.equal(fx.alle(t.zeile, '[role=tab]').length, 0)
|
||||
await fx.sende(termine, 'kn:reiter', { detail: { eintraege: REITER, aktiv: 'r0', bei() {} } })
|
||||
const erster = fx.finde(t.zeile, '[role=tablist]')
|
||||
await fx.sende(termine, 'kn:reiter', { detail: { eintraege: REITER, aktiv: 'r3', bei() {} } })
|
||||
assert.deepEqual([fx.finde(t.zeile, '[role=tablist]') === erster, fx.alle(t.zeile, '[role=tab]').map((x) => x.getAttribute('aria-selected')).indexOf('true')], [true, 3]) // gleiche Reiter: nur die Auswahl wechselt
|
||||
e.oeffne({ titel: 'Webshop', eltern: EL, seite: 'webshop' })
|
||||
assert.deepEqual([fx.alle(t.zeile, '[role=tab]').length, Boolean(fx.finde(t.zeile, '.kn-zurueck--voll')), Boolean(fx.finde(t.zeile, '.kn-punkt'))], [0, true, true]) // neue Etage: alte Reiter weg, Punkt bleibt
|
||||
e.schliesse(); await fx.sende(termine, 'kn:reiter', { detail: { eintraege: REITER, aktiv: 'r0', bei() {} } })
|
||||
assert.equal(fx.alle(t.zeile, '[role=tab]').length, 0) // geschlossen: späte Meldungen tun nichts
|
||||
} finally { fx.restore() }
|
||||
})
|
||||
Reference in new issue
Block a user