105 lines
7.1 KiB
JavaScript
105 lines
7.1 KiB
JavaScript
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))
|
||
})
|