Files
Webklar-Kundenbereich/test/knUmschaltNachpruefung.test.js
T
ClaudeandClaude Opus 5.5 17317ada05 Kundenansicht neu P10: Korrekturen aus der Pruefung (Task 4)
Zeile /auftrag.html in neu und alt (Übersicht N40), Test mit der echten Weiche bleibt auch nach dem Festschreiben (Task 14) grün

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:07:57 +00:00

139 lines
7.6 KiB
JavaScript
Raw 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, after } from 'node:test'
import assert from 'node:assert/strict'
import express from 'express'
import { fileURLToPath } from 'node:url'
import { startAppwriteMock } from './support/appwriteMock.js'
import { startFakeStripe } from './support/fakeStripe.js'
import { useTestEnv } from './support/testEnv.js'
import { schemaKeys } from './support/schema.js'
// P10 Task 4: Nachprüf-Skript – prüft die ausgelieferten Seiten per HTTP gegen „alt“ oder „neu“ (nur lesend, kein Appwrite)
const aw = await startAppwriteMock({ schema: { customerViewLog: schemaKeys('customerViewLog') } })
const st = await startFakeStripe()
useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
const { startTestApp } = await import('./support/testApp.js')
const { umschaltSeitenRouter, UMSCHALT_SEITEN } = await import('../server/routes/umschaltSeiten.js')
const { config } = await import('../server/config.js')
const { PRUEFUNGEN, parseArgs, nachpruefen } = await import('../scripts/umschalten-nachpruefung.mjs')
after(() => Promise.all([aw.close(), st.close()]))
const publicDir = fileURLToPath(new URL('../public/', import.meta.url))
// Stellvertreter-Antworten werden aus den Markern der Tabelle gebaut (Zeichenketten aus `enthaelt`, Manifest als JSON)
const MANIFEST = { id: '/dashboard.html', start_url: '/dashboard.html', scope: '/', background_color: '#ffffff', theme_color: '#ffffff', shortcuts: [{ name: 'Chat' }, { name: 'Rechnungen' }, { name: 'Verträge' }] }
const antwort = (p, erwartet) =>
p.typ === 'json'
? { status: 200, type: 'application/manifest+json', body: JSON.stringify(erwartet === 'neu' ? MANIFEST : { ...MANIFEST, background_color: '#000000', theme_color: '#000000' }) }
: p.typ === 'pdf'
? { status: 200, type: 'application/pdf', body: '%PDF-1.7 …' }
: { status: 200, type: 'text/html', body: p.enthaelt.join(' ') }
const stub = (erwartet, aendern = () => null) => async (url) => {
const pfad = new URL(url).pathname
const a = aendern(pfad) ?? antwort(PRUEFUNGEN[erwartet].find((x) => x.pfad === pfad), erwartet)
if (a instanceof Error) throw a
return new Response(a.body, { status: a.status, headers: { 'content-type': a.type } })
}
test('neu und alt: alle Zeilen grün, eine Zeile je Prüfung', async () => {
for (const e of ['neu', 'alt']) {
const r = await nachpruefen('https://stub.invalid', e, { fetchFn: stub(e) })
assert.deepEqual([r.ok, r.zeilen.length], [true, PRUEFUNGEN[e].length], e)
}
})
test('Übersicht N40: /auftrag.html hat in neu und alt eine Zeile (neu: oeffentlich.css ja, auftrag.css nein)', async () => {
const zeile = (e) => PRUEFUNGEN[e].find((p) => p.pfad === '/auftrag.html')
assert.deepEqual([zeile('neu').enthaelt, zeile('neu').enthaeltNicht, zeile('alt').enthaelt], [['/neu/oeffentlich/oeffentlich.css'], ['/auftrag.css'], ['/auftrag.css']])
// die alte Auftragsseite, wo die neue erwartet wird: genau diese Zeile ist rot
const r = await nachpruefen('https://stub.invalid', 'neu', { fetchFn: stub('neu', (p) => (p === '/auftrag.html' ? { status: 200, type: 'text/html', body: '/neu/oeffentlich/oeffentlich.css /auftrag.css' } : null)) })
assert.deepEqual(r.zeilen.filter((z) => !z.ok).map((z) => z.pfad), ['/auftrag.html'])
assert.match(r.zeilen.find((z) => z.pfad === '/auftrag.html').grund, /verboten: \/auftrag\.css/)
})
test('neu gegen alte Seiten ist rot und nennt die Seiten', async () => {
const r = await nachpruefen('https://stub.invalid', 'neu', { fetchFn: async (u) => stub('alt')(u).catch(() => new Response('', { status: 404 })) })
assert.equal(r.ok, false)
assert.ok(r.zeilen.filter((z) => !z.ok).map((z) => z.pfad).includes('/login.html'))
})
test('Status 500, Netzfehler und verbotener Marker färben genau ihre Zeile rot', async () => {
const r = await nachpruefen('https://stub.invalid', 'neu', {
fetchFn: stub('neu', (p) =>
p === '/offline.html'
? { status: 500, type: 'text/html', body: '' }
: p === '/kuendigen.html'
? new Error('ECONNRESET')
: p === '/login.html'
? { status: 200, type: 'text/html', body: 'content="#ffffff" /neu/tokens.css #9d3dfe' }
: null
),
})
assert.deepEqual(r.zeilen.filter((z) => !z.ok).map((z) => z.pfad).sort(), ['/kuendigen.html', '/login.html', '/offline.html'])
assert.match(r.zeilen.find((z) => z.pfad === '/offline.html').grund, /500/)
})
test('gegen die echten Dateien der Weiche: alt bei off, neu bei on (ohne die Fassung-6-Zeilen)', async () => {
let modus = 'off'
const router = express.Router()
router.use(umschaltSeitenRouter({ publicDir, modus: () => modus, fassung6: () => null }))
router.use(express.static(publicDir))
const app = await startTestApp({ '/': router })
try {
const OHNE = ['/abo-bedingungen.html', '/WEBklar-Abo-Vertragsunterlagen.pdf']
assert.deepEqual((await nachpruefen(app.url, 'alt', { ohne: OHNE })).zeilen.filter((z) => !z.ok), [])
modus = 'on'
const r = await nachpruefen(app.url, 'neu', { ohne: OHNE })
assert.deepEqual(r.zeilen.filter((z) => !z.ok), [])
assert.equal(r.zeilen.length, PRUEFUNGEN.neu.length - 2)
} finally {
await app.close()
}
})
test('mit der echten Fassung 6 der Weiche: alle Zeilen, alt bei pilot, neu bei on', async () => {
// P10 Task 14: Mit dem Festschreiben (termsVersion = termsVersionNeu) steht Fassung 6 unter /abo-bedingungen.html, auch bei
// pilot; die Zeile "Version 5 · Stand" von alt gibt es dann nicht mehr, und die Weiche hat keine Fassung-6-Zeilen mehr.
const fassung5Gilt = config.abo.termsVersion !== config.abo.termsVersionNeu
const ohneAlt = fassung5Gilt ? [] : ['/abo-bedingungen.html']
let modus = 'pilot'
const router = express.Router()
router.use(umschaltSeitenRouter({ publicDir, modus: () => modus }))
router.use(express.static(publicDir))
const app = await startTestApp({ '/': router })
try {
const alt = await nachpruefen(app.url, 'alt', { ohne: ohneAlt })
assert.deepEqual(alt.zeilen.filter((z) => !z.ok), [])
assert.equal(alt.zeilen.length, PRUEFUNGEN.alt.length - ohneAlt.length)
modus = 'on'
const neu = await nachpruefen(app.url, 'neu')
assert.deepEqual(neu.zeilen.filter((z) => !z.ok), [])
assert.equal(neu.zeilen.length, PRUEFUNGEN.neu.length)
// und neu gegen den Stand von pilot ist rot: die Prüfung unterscheidet wirklich (jede Seite der Weiche fällt auf)
modus = 'pilot'
const falsch = await nachpruefen(app.url, 'neu')
assert.equal(falsch.ok, false)
const rot = falsch.zeilen.filter((z) => !z.ok).map((z) => z.pfad)
for (const pfad of Object.keys(UMSCHALT_SEITEN)) assert.ok(rot.includes(pfad), pfad)
} finally {
await app.close()
}
})
test('Umleitungen werden nicht verfolgt (302 ist rot) und es werden keine Cookies gesendet', async () => {
const gesehen = []
const fetchFn = async (url, opts = {}) => {
gesehen.push(opts)
return new Response('', { status: 302, headers: { location: '/login.html' } })
}
const r = await nachpruefen('https://stub.invalid', 'neu', { fetchFn })
assert.equal(r.ok, false)
assert.ok(r.zeilen.every((z) => !z.ok && /302/.test(z.grund)))
assert.ok(gesehen.every((o) => o.redirect === 'manual' && !o.headers?.cookie && !o.headers?.Cookie))
})
test('parseArgs', () => {
assert.deepEqual(parseArgs(['https://project.webklar.com', '--erwartet=neu']), { basis: 'https://project.webklar.com', erwartet: 'neu' })
assert.deepEqual(parseArgs(['http://127.0.0.1:3000', '--erwartet=alt']), { basis: 'http://127.0.0.1:3000', erwartet: 'alt' })
for (const schlecht of [[], ['https://x.invalid'], ['ftp://x.invalid', '--erwartet=neu'], ['https://x.invalid/pfad', '--erwartet=neu'], ['https://x.invalid', '--erwartet=beide']]) assert.throws(() => parseArgs(schlecht), /Aufruf/)
})