Files
Webklar-Kundenbereich/test/knHuelleRouten.test.js
T
ClaudeandClaude Opus 5.5 83ac903ab3 Navigation leichter: Handy-Leiste, Schwarz nur für die Hauptaktion, Verträge mit zwei Reitern, kürzeres Konto (V3, V5, V7, V8)
V3: In der Fahrstuhl-Zeile läuft unter dem aktiven Wort eine dünne Linie statt des schwarzen Blocks; das Wort wird dunkel und fett. Die weiße Overlay-Kopie bleibt im Baum, wird aber nicht mehr gezeigt.
V5: Terminplaner: Tag/Woche/Monat als hellgrauer Umschalter mit weißer Auswahl, Filter als leise Chips. „Einschalten“ in der Liste Entdecken ist ein heller Knopf; schwarz bleibt der Knopf der Bestätigungsseite.
V7: Verträge nur noch mit Abo und Rechnungen. Das Stundenkonto steht beim Wartungs-Abo als Abschnitt unter dem Abo (ohne doppelte Warnungen), #stunden springt dorthin. Der E-Mail-Speicher ist die Unterseite #speicher (Link „ändern“ in der Abo-Zeile), ohne Widerrufsstreifen wie die anderen Bestellseiten. Alte Links bleiben gültig.
V8: Konto mit vier Zeilen (Passwort, Verträge kündigen, Vertrag widerrufen, Abmelden), Datenschutz und Impressum klein darunter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 17:27:30 +00:00

75 lines
6.9 KiB
JavaScript

import { test } from 'node:test'
import assert from 'node:assert/strict'
import { BEREICHE, ROUTEN, routeAusHash, hashFuerRoute, hashFuerAnsicht, startHash, ankerKette, elternVon, titelFuer, zeigtWiderrufsstreifen } from '../public/neu/routen.js'
const FAELLE = [ // Alte Links (Review Focus 1)
['', { bereich: 'website', query: '' }],
['#termine?bestellt=1&projekt=x', { bereich: 'funktionen', etage: 'termine', query: 'bestellt=1&projekt=x' }],
['#webshop?stripe=zurueck&projekt=x', { bereich: 'funktionen', etage: 'webshop', query: 'stripe=zurueck&projekt=x' }],
['#buchungen?stripe=neu&projekt=x', { bereich: 'funktionen', etage: 'buchungen', query: 'stripe=neu&projekt=x' }],
['#news?bestellt=1', { bereich: 'funktionen', etage: 'news', query: 'bestellt=1' }],
['#funktionen', { bereich: 'funktionen', reiter: 'meine', query: '' }], ['#entdecken', { bereich: 'funktionen', reiter: 'entdecken', query: '' }],
['#rechnungen', { bereich: 'vertraege', reiter: 'rechnungen', query: '' }], ['#stunden', { bereich: 'vertraege', reiter: 'stunden', query: '' }],
['#speicher', { bereich: 'vertraege', etage: 'speicher', query: '' }], // Navigation leichter V7: Unterseite statt Reiter E-Mail
['#gutschrift', { bereich: 'vertraege', etage: 'gutschrift', query: '' }],
['#wartung', { bereich: 'vertraege', reiter: 'abo', query: '' }], ['#abo', { bereich: 'vertraege', reiter: 'abo', query: '' }], ['#vertraege', { bereich: 'vertraege', query: '' }], // #vertraege ohne Reiter: die Ansicht wählt den Standardreiter
['#fortschritt', { bereich: 'website', scroll: 'aktivitaet', query: '' }], ['#projekt?id=p1', { bereich: 'website', etage: 'projekt', query: 'id=p1' }],
['#Chat', { bereich: 'chat', query: '' }], ['#passwort', { bereich: 'website', etage: 'passwort', query: '' }],
['#bestellen-wartung', { bereich: 'vertraege', etage: 'bestellen', produkt: 'wartung', query: '' }],
['#bestellen-hosting', { bereich: 'vertraege', etage: 'bestellen', produkt: 'hosting', query: '' }],
['#gibtesnicht', { bereich: 'website', query: '' }],
]
test('Alte Links: Ziel und Query stimmen (Review Focus 1), V2-Beispiel', () => {
for (const [hash, soll] of FAELLE) assert.deepEqual(routeAusHash(hash), soll, hash)
assert.deepEqual(routeAusHash('#termine?bestellt=1'), { bereich: 'funktionen', etage: 'termine', query: 'bestellt=1' })
})
test('hashFuerRoute ist die Umkehrung: Query bleibt, #wartung wird #abo, #vertraege und #abo fallen nicht zusammen; Hash-Namen nur [a-z]', () => {
const kanon = { '#wartung': '#abo', '#Chat': '#chat', '#gibtesnicht': '#', '': '#' }
for (const [hash] of FAELLE) assert.equal(hashFuerRoute(routeAusHash(hash)), kanon[hash] ?? hash, hash)
assert.deepEqual(['#vertraege', '#abo', '#wartung'].map((hash) => hashFuerRoute(routeAusHash(hash))), ['#vertraege', '#abo', '#abo']) // Review Focus 1: Reiterklick auf Abo darf nie #vertraege schreiben
assert.equal('reiter' in routeAusHash('#vertraege'), false); assert.equal(routeAusHash('#abo').reiter, 'abo')
assert.deepEqual(BEREICHE, ['website', 'funktionen', 'chat', 'vertraege'])
for (const k of Object.keys(ROUTEN).filter((k) => !k.startsWith('bestellen-'))) assert.match(k, /^[a-z]*$/, k) // Login-Whitelist app.js:466
})
test('data-view-Brücke: jeder Name aus VIEW_HASHES (app.js:1933 wörtlich) führt zum gleichen Hash', () => {
const ALT = { projects: '', funktionen: 'funktionen', news: 'news', analyse: 'analyse', termine: 'termine', invoices: 'rechnungen', chat: 'chat', vertraege: 'vertraege', stunden: 'stunden', 'bestellen-hosting': 'bestellen-hosting', 'bestellen-wartung': 'bestellen-wartung', wechsel: 'wechsel', takeover: 'gutschrift', projekt: 'projekt', passwort: 'passwort', webshop: 'webshop', buchungen: 'buchungen', zeiten: 'zeiten' }
for (const [name, hash] of Object.entries(ALT)) assert.equal(hashFuerAnsicht(name), `#${hash}`, name)
assert.equal(hashFuerAnsicht('unbekannt'), null)
})
test('startHash: ?abo= führt zum Reiter Abo (die Query bleibt in search), #wartung wird #abo, #vertraege bleibt, sonstige Query bleibt', () => {
assert.equal(startHash({ search: '?abo=success', hash: '' }), '#abo')
assert.equal(startHash({ search: '?abo=cancel', hash: '#chat' }), '#abo')
assert.equal(startHash({ search: '', hash: '#wartung' }), '#abo')
assert.equal(startHash({ search: '', hash: '#vertraege' }), '#vertraege')
assert.equal(startHash({ search: '?x=1', hash: '#termine?bestellt=1&projekt=p1' }), '#termine?bestellt=1&projekt=p1')
assert.equal(startHash({ search: '', hash: '' }), '#')
})
test('ankerKette, elternVon, titelFuer', () => {
const r = routeAusHash
assert.deepEqual(ankerKette(r('#termine?bestellt=1')), ['#', '#funktionen', '#termine?bestellt=1'])
assert.deepEqual(ankerKette(r('#chat')), ['#', '#chat']); assert.deepEqual(ankerKette(r('#gutschrift')), ['#', '#vertraege', '#gutschrift'])
assert.deepEqual(ankerKette(r('#abo')), ['#', '#abo']); assert.deepEqual(ankerKette(r('#vertraege')), ['#', '#vertraege'])
assert.deepEqual(ankerKette(r('#passwort')), ['#', '#passwort']); assert.deepEqual(ankerKette(r('#fortschritt')), ['#fortschritt'])
assert.deepEqual(elternVon(r('#termine')), { bereich: 'funktionen', reiter: 'meine', query: '' })
assert.deepEqual(elternVon(r('#gutschrift')), { bereich: 'vertraege', query: '' }) // Bereichs-Anker #vertraege, kein Reiter
assert.deepEqual(elternVon(r('#passwort'), '#chat'), { bereich: 'chat', query: '' }); assert.equal(elternVon(r('#passwort')).bereich, 'website'); assert.equal(elternVon(r('#chat')), null)
assert.deepEqual(['#termine', '#zeiten', '#bestellen-wartung', '#passwort', '#chat'].map((h) => titelFuer(r(h))), ['Terminplaner', 'Öffnungszeiten', 'Abo bestellen', 'Passwort ändern', 'Chat'])
})
// E-Fix F1 (Nachkorrektur): Auf den Bestellseiten stehen Kerninfo und Knopf auf einem Bildschirm; der Widerrufsstreifen gehört auf die Hauptseiten (Spec 5.2)
test('zeigtWiderrufsstreifen: nicht auf Abo bestellen, Wechsel, Zusatzspeicher und Gutschrift; auf allen anderen Seiten schon', () => {
const ohne = ['#bestellen-wartung', '#bestellen-hosting', '#wechsel', '#speicher', '#gutschrift', '#wechsel?x=1', '#bestellen-hosting?abo=cancel']
for (const hash of ohne) assert.equal(zeigtWiderrufsstreifen(routeAusHash(hash)), false, hash)
const mit = ['', '#projekt', '#fortschritt', '#passwort', '#funktionen', '#entdecken', '#news', '#termine', '#webshop', '#buchungen', '#zeiten', '#analyse', '#chat', '#vertraege', '#abo', '#wartung', '#rechnungen', '#stunden']
for (const hash of mit) assert.equal(zeigtWiderrufsstreifen(routeAusHash(hash)), true, hash)
assert.equal(zeigtWiderrufsstreifen(undefined), true) // ohne Route nichts verstecken
// jede Etage der Tabelle ist entschieden: versteckt sind genau die Bestellseiten
const versteckt = [...new Set(Object.values(ROUTEN).filter((r) => !zeigtWiderrufsstreifen(r)).map((r) => r.etage ?? `reiter:${r.reiter}`))].sort()
assert.deepEqual(versteckt, ['bestellen', 'gutschrift', 'speicher', 'wechsel'])
})