Files

105 lines
7.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test } from 'node:test'
import assert from 'node:assert/strict'
import {
fmtEuro, fmtDatum, fmtDatumZeit, fmtTagMonat, fmtStd, fmtMinuten, fmtBytes, legacyRequest, meldeZaehlerNeu, merkeHinweis, nimmHinweis,
setzeChatVorgabe, nimmChatVorgabe, fmtUhrzeit, berlinTag, ersetze, sichereAdresse, wechselFunktionAus, zuAnsicht, meldeTitel, K, ABO_NICHT_GELADEN, navigiere, ladeAbo, safeUrl,
} from '../public/neu/ansicht-hilfen.js'
import { mit, mitDom, abo, aboAntwort, me, projekt, rechnung, nachricht, angebot, ledger, anfrageGutschrift, VORSCHAU, VORSCHAU_SPEICHER, LIMITS, neueWurzel } from './support/knDaten.js'
test('Formate: Euro mit geschütztem Leerzeichen, Daten in Berliner Zeit', () => {
assert.equal(fmtEuro(50), '50,00 €')
assert.equal(fmtDatum('2026-10-17T10:00:00Z'), '17.10.2026')
assert.equal(fmtDatum('17.10.2026'), '17.10.2026')
assert.equal(fmtDatum(''), '–')
assert.equal(fmtDatumZeit('2026-10-17T10:00:00Z'), '17.10.26, 12:00')
assert.equal(fmtTagMonat('2026-10-17T21:59:59Z'), '17.10.')
assert.equal(fmtTagMonat('2026-10-17T22:00:00Z'), '18.10.')
assert.equal(fmtTagMonat('kaputt'), '')
})
test('Formate: Uhrzeit und Kalendertag in Berliner Zeit', () => {
assert.equal(fmtUhrzeit('2026-10-17T10:05:00Z'), '12:05'); assert.equal(fmtUhrzeit('kaputt'), '')
assert.deepEqual(berlinTag('2026-10-15T22:30:00Z'), { j: 2026, m: 10, t: 16 }); assert.equal(berlinTag(''), null)
})
test('ersetze überspringt null, undefined und false, statt „null“ anzuhängen', () => mitDom((fx) => {
const el = fx.document.createElement('div'); el.append('alt')
ersetze(el, null, 'a', [undefined, fx.document.createElement('b'), false], 'c')
assert.equal(el.textContent, 'ac'); assert.equal(el.childNodes.length, 3)
}))
test('Formate: Stunden, Minuten, Bytes', () => {
assert.deepEqual([150, 120, 45, 0].map(fmtStd), ['2,5 Std.', '2 Std.', '0,75 Std.', '0 Std.'])
assert.deepEqual([0, 45, 120, 150].map(fmtMinuten), ['', '45 min', '2 h', '2 h 30 min'])
assert.deepEqual([12, 1536, 5 * 1024 * 1024].map(fmtBytes), ['12 B', '1,5 KB', '5,0 MB'])
})
test('legacyRequest: String-Body wird zum Objekt, Objekt und fehlender Body bleiben', async () => {
const aufrufe = []
const alt = legacyRequest(async (pfad, opts) => { aufrufe.push([pfad, opts]); return {} })
await alt('/a', { method: 'POST', body: '{"x":1}' }); await alt('/b', { method: 'POST', body: { y: 2 } }); await alt('/c')
assert.deepEqual(aufrufe, [['/a', { method: 'POST', body: { x: 1 } }], ['/b', { method: 'POST', body: { y: 2 } }], ['/c', {}]])
})
test('meldeZaehlerNeu ohne Dokument tut nichts, Hinweis und Chat-Vorgabe gelten einmal', () => {
assert.doesNotThrow(() => meldeZaehlerNeu('chat'))
merkeHinweis('Gespeichert.'); assert.equal(nimmHinweis(), 'Gespeichert.'); assert.equal(nimmHinweis(), '')
setzeChatVorgabe('Hallo'); assert.equal(nimmChatVorgabe(), 'Hallo'); assert.equal(nimmChatVorgabe(), '')
})
test('wechselFunktionAus: nur vollständige Werte zählen (V11)', () => {
assert.deepEqual(wechselFunktionAus({ wechselFunktion: { key: 'termine', projectId: 'p1', extra: 1 } }), { key: 'termine', projectId: 'p1' })
for (const sub of [undefined, null, {}, { wechselFunktion: null }, { wechselFunktion: { key: 'termine' } }, { wechselFunktion: { key: '', projectId: 'p1' } }, { wechselFunktion: { key: 1, projectId: 'p1' } }]) assert.equal(wechselFunktionAus(sub), null)
})
test('zuAnsicht ist die Brücke der Hülle, meldeTitel steigt zu den Eltern auf', () => mitDom((fx) => {
assert.deepEqual(zuAnsicht('takeover'), { href: '#gutschrift', 'data-view': 'takeover' })
assert.deepEqual(zuAnsicht('projekt', 'p1'), { href: '#projekt?projekt=p1', 'data-view': 'projekt', 'data-project': 'p1' })
assert.equal(zuAnsicht('invoices').href, '#rechnungen')
const aussen = fx.document.createElement('div'); const innen = fx.document.createElement('p'); aussen.append(innen); const titel = []
aussen.addEventListener('kn:titel', (e) => titel.push(e.detail.text)); meldeTitel(innen, 'Zwei'); assert.deepEqual(titel, ['Zwei'])
}))
test('Bausteinklassen K tragen die Klassen aus basis.css', () => {
assert.equal(K.knopf, 'kn-knopf'); assert.equal(K.primaer, 'kn-knopf-primaer'); assert.equal(K.zweit, 'kn-knopf-zweit'); assert.equal(K.textknopf, 'kn-textknopf')
assert.equal(K.versteckt, 'hidden'); assert.equal(K.pille.gruen, 'kn-pille kn-pille-gruen'); assert.equal(K.pille.rot, 'kn-pille kn-pille-rot')
assert.match(ABO_NICHT_GELADEN, /nicht geladen werden/)
})
test('ladeAbo liefert das Objekt, navigiere wirft ohne Router nicht', mit({ 'GET /api/abo': aboAntwort() }, async (fx) => {
const antwort = await ladeAbo()
assert.equal(antwort.subscription, null)
assert.equal(antwort.termsVersion, '2026-09-30-v5')
assert.doesNotThrow(() => navigiere('#chat'))
assert.equal(fx.window.location.hash, '#chat') // ohne laufenden Router trägt der Hash die Adresse
}))
test('ladeAbo bei Fehler: null', mit({ 'GET /api/abo': () => ({ status: 500, body: { error: 'kaputt' } }) }, async () => {
assert.equal(await ladeAbo(), null)
}))
test('Testdaten: Bauer liefern die Formen der Schnittstellen', () => {
assert.equal(me().customer.email, 'anna@example.com')
assert.equal(abo().productKey, 'wartung'); assert.equal(abo({ produkt: 'hosting' }).productKey, 'hosting')
assert.equal(abo().status, 'active'); assert.equal(abo().storage.units, 0)
assert.equal(aboAntwort().products.length, 2); assert.equal(aboAntwort().mailStorage.includedGb, 5)
assert.equal(projekt().id.length > 0, true); assert.equal(rechnung().balance, 0); assert.equal(typeof nachricht().text, 'string')
assert.equal(angebot().months > 0, true); assert.equal(ledger().balanceMinutes >= 0, true); assert.equal(typeof anfrageGutschrift().status, 'string')
assert.equal(VORSCHAU.amountDueCents, 3000); assert.equal(VORSCHAU_SPEICHER.direction, 'down'); assert.equal(LIMITS.maxFiles, 3)
assert.equal(safeUrl('javascript:alert(1)'), ''); assert.equal(safeUrl('https://a.de/x'), 'https://a.de/x')
})
test('mit(): unbekannte Pfade antworten 404, Funktionen liefern Status und Body, Neuaufbau je Test', mit({ '/api/x': { a: 1 }, 'POST /api/y': (aufruf) => ({ status: 201, body: { echo: aufruf.body } }) }, async (fx) => {
const w = neueWurzel(fx)
assert.equal(w.parentNode, fx.document.body)
const a = await fetch('/api/x'); assert.equal(a.status, 200); assert.deepEqual(await a.json(), { a: 1 })
const b = await fetch('/api/y', { method: 'POST', body: JSON.stringify({ q: 1 }) }); assert.equal(b.status, 201); assert.deepEqual(await b.json(), { echo: { q: 1 } })
const c = await fetch('/api/z'); assert.equal(c.status, 404); assert.deepEqual(await c.json(), { error: 'unbekannt' })
const ev = new CustomEvent('x', { detail: 1 }); assert.equal(ev.detail, 1); ev.target = 'frei'; assert.equal(ev.target, 'frei')
}))
test('sichereAdresse: http(s) und Pfade auf derselben Herkunft, sonst leer', () => {
assert.equal(sichereAdresse('https://a.de/x'), 'https://a.de/x'); assert.equal(sichereAdresse('/vorschau-hinweis.html'), '/vorschau-hinweis.html')
for (const v of ['javascript:alert(1)', 'data:text/html,x', '//evil.example/x', '/\\evil.example/x', 'vorschau.html', '', null, undefined, 5]) assert.equal(sichereAdresse(v), '', String(v))
})