Kundenansicht neu P1: h(), api() mit ApiFehler und Quelltext-Regel
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
46edb7c418
commit
6f0808647f
4 files changed
+140
No files matched your search
@@ -0,0 +1,42 @@
|
||||
import { test } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { installFakeDom } from './support/fakeDom.js'
|
||||
import { h, leeren, text } from '../public/neu/dom.js'
|
||||
import { api, ApiFehler } from '../public/neu/api.js'
|
||||
|
||||
test('h: Kundentext bleibt Text; on, boolesche und fehlende Attribute; leeren, text', async () => {
|
||||
const fx = installFakeDom()
|
||||
try {
|
||||
let klicks = 0
|
||||
const k = h('button', { class: 'kn-knopf', hidden: false, 'data-x': true, on: { click: () => { klicks += 1 } } }, '<b>x</b>', [null, 'y'])
|
||||
await fx.klick(k)
|
||||
assert.deepEqual([klicks, k.className, k.hasAttribute('hidden'), k.getAttribute('data-x')], [1, 'kn-knopf', false, ''])
|
||||
assert.deepEqual([fx.text(k), k.children.length], ['<b>x</b>y', 0])
|
||||
assert.equal(leeren(k).childNodes.length, 0); assert.equal(text(k, null).textContent, '')
|
||||
} finally { fx.restore() }
|
||||
})
|
||||
|
||||
test('api: JSON, ApiFehler, Netzfehler und roh (Review Focus 5)', async () => {
|
||||
const fx = installFakeDom({ antworten: [{ body: { ok: 1 } }, { status: 409, body: { error: 'Schon da', code: 'bereits_eingeschaltet', field: 'x', extra: 1 } }, { status: 502, body: {} }] })
|
||||
try {
|
||||
assert.deepEqual(await api('/api/x', { method: 'POST', body: { a: 1 } }), { ok: 1 })
|
||||
assert.deepEqual(fx.fetchLog[0], { method: 'POST', url: '/api/x', body: { a: 1 } })
|
||||
const e = await api('/api/x').catch((x) => x)
|
||||
assert.ok(e instanceof ApiFehler); assert.deepEqual([e.status, e.code, e.message, e.field, e.body.extra], [409, 'bereits_eingeschaltet', 'Schon da', 'x', 1])
|
||||
assert.equal((await api('/api/x').catch((x) => x)).message, 'Server nicht erreichbar. Bitte kurz warten und noch einmal versuchen.')
|
||||
globalThis.fetch = async () => { throw new TypeError('Failed to fetch') }
|
||||
const n = await api('/api/x').catch((x) => x); assert.deepEqual([n.status, n.message], [0, 'Keine Verbindung. Bitte versuch es gleich noch einmal.'])
|
||||
let init; globalThis.fetch = async (_u, i) => { init = i; return { ok: true, status: 200, json: async () => ({}) } }
|
||||
const blob = new Blob(['abc']); await api('/api/up', { method: 'POST', roh: blob })
|
||||
assert.deepEqual([init.headers['Content-Type'], init.body], ['application/octet-stream', blob])
|
||||
} finally { fx.restore() }
|
||||
})
|
||||
|
||||
test('api: session_revoked leitet genau einmal zur Anmeldung (letzter Test der Datei)', async () => {
|
||||
const weg = { status: 401, body: { error: 'Sitzung beendet', code: 'session_revoked' } }
|
||||
const fx = installFakeDom({ antworten: [weg, weg] })
|
||||
try {
|
||||
await api('/api/x').catch(() => {}); assert.equal(fx.window.location.href, '/login.html?error=Sitzung%20beendet')
|
||||
fx.window.location.href = 'anderswo'; await api('/api/x').catch(() => {}); assert.equal(fx.window.location.href, 'anderswo')
|
||||
} finally { fx.restore() }
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
import { test } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync, existsSync } from 'node:fs'
|
||||
|
||||
const P1 = ['dom', 'api', 'routen', 'router', 'reiter', 'etage', 'zaehler', 'fristen-streifen', 'konto', 'leiste', 'huelle'].map((n) => `${n}.js`)
|
||||
const pfad = (f) => new URL(`../public/neu/${f}`, import.meta.url)
|
||||
const ohneKommentare = (t) => t.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|\s)\/\/.*$/gm, '')
|
||||
|
||||
test('P1-Module: kein innerHTML, nur relative Importe, keine Verweise auf entfernte Seiten', () => {
|
||||
for (const f of P1.filter((d) => existsSync(pfad(d)))) {
|
||||
const q = ohneKommentare(readFileSync(pfad(f), 'utf8'))
|
||||
assert.doesNotMatch(q, /innerHTML|insertAdjacentHTML|outerHTML|document\.write|\beval\(/, f)
|
||||
assert.doesNotMatch(q, /admin\.html|kalkulation\.html|\/api\/portal-admin/, f)
|
||||
for (const m of q.matchAll(/from '([^']+)'/g)) assert.match(m[1], /^\.\//, `${f}: nur relative Importe`)
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user