Kundenansicht neu P10: Umschalt-Weiche liefert öffentliche Seiten, Manifest und Fassung-6-Adresse bei on

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-29 12:07:57 +00:00
1 parent 4a75d7aba0
commit 416ebee18a
3 files changed
+220

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
import { test, after } from 'node:test'
import assert from 'node:assert/strict'
import express from 'express'
import { mkdtempSync, readFileSync, rmdirSync, unlinkSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
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 3: Umschalt-Weiche – erst bei KUNDENANSICHT_NEU=on liefert sie die neuen öffentlichen Seiten, das Manifest und die Fassung-6-Adresse
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, fassung6Aus } = await import('../server/routes/umschaltSeiten.js')
const publicDir = fileURLToPath(new URL('../public/', import.meta.url))
let modus = 'off'
let fassung6 = null
const router = express.Router()
router.use(umschaltSeitenRouter({ publicDir, modus: () => modus, fassung6: () => fassung6 }))
router.use(express.static(publicDir))
const app = await startTestApp({ '/': router })
after(() => Promise.all([app.close(), aw.close(), st.close()]))
const holen = async (pfad, basis = app.url, methode = 'GET') => {
const r = await fetch(basis + pfad, { method: methode, redirect: 'manual' })
return { status: r.status, bytes: Buffer.from(await r.arrayBuffer()), headers: r.headers }
}
const datei = (rel) => readFileSync(path.join(publicDir, rel))
for (const [pfad, neu] of Object.entries(UMSCHALT_SEITEN)) {
test(`${pfad}: off und pilot liefern die Datei von heute, on die neue (no-cache)`, async () => {
for (const m of ['off', 'pilot']) {
modus = m
const r = await holen(pfad)
assert.ok(r.status === 200 && r.bytes.equals(datei(pfad.slice(1))), `${m} ${pfad}`)
}
modus = 'on'
const r = await holen(pfad)
assert.ok(r.status === 200 && r.bytes.equals(datei(neu)), pfad)
assert.equal(r.headers.get('cache-control'), 'no-cache')
})
}
test('Manifest bei on ist JSON', async () => {
modus = 'on'
assert.match((await holen('/manifest.webmanifest')).headers.get('content-type'), /json/)
})
test('Fassung 6: Seite und PDF kommen bei on aus der Neu-Fassung, sonst bleibt die Datei von heute', async () => {
fassung6 = { url: '/neu/oeffentlich/offline.html', pdfFile: 'WEBklar-Wartungs-Abo-Vertragsunterlagen.pdf' } // Stellvertreter-Dateien
modus = 'pilot'
assert.ok((await holen('/abo-bedingungen.html')).bytes.equals(datei('abo-bedingungen.html')))
modus = 'on'
assert.ok((await holen('/abo-bedingungen.html')).bytes.equals(datei('neu/oeffentlich/offline.html')))
assert.ok((await holen('/WEBklar-Abo-Vertragsunterlagen.pdf')).bytes.equals(datei('WEBklar-Wartungs-Abo-Vertragsunterlagen.pdf')))
fassung6 = null
assert.ok((await holen('/abo-bedingungen.html')).bytes.equals(datei('abo-bedingungen.html')))
})
test('Standard-Fassung 6 (fassung6Aus): bei on kommen Seite und PDF der Fassung 6 aus public/neu/rechtliches/', async () => {
const f6 = fassung6Aus()
assert.deepEqual([f6.url, f6.pdfFile], ['/neu/rechtliches/abo-bedingungen.html', 'neu/rechtliches/WEBklar-Abo-Vertragsunterlagen.pdf'])
const echt = express.Router()
echt.use(umschaltSeitenRouter({ publicDir, modus: () => modus }))
echt.use(express.static(publicDir))
const a3 = await startTestApp({ '/': echt })
try {
modus = 'pilot'
assert.ok((await holen('/abo-bedingungen.html', a3.url)).bytes.equals(datei('abo-bedingungen.html')))
modus = 'on'
assert.ok((await holen('/abo-bedingungen.html', a3.url)).bytes.equals(datei('neu/rechtliches/abo-bedingungen.html')))
assert.ok((await holen('/WEBklar-Abo-Vertragsunterlagen.pdf', a3.url)).bytes.equals(datei('neu/rechtliches/WEBklar-Abo-Vertragsunterlagen.pdf')))
} finally {
await a3.close()
}
})
test('Pfadwächter: eine Adresse außerhalb von public/ wird nie geliefert', async () => {
modus = 'on'
fassung6 = { url: '/../../package.json', pdfFile: '../../server/config.js' }
for (const p of ['/abo-bedingungen.html', '/WEBklar-Abo-Vertragsunterlagen.pdf']) assert.ok((await holen(p)).bytes.equals(datei(p.slice(1))), p)
})
test('fehlende neue Datei: Rückfall auf die alte statt 500', async () => {
const tmp = mkdtempSync(path.join(tmpdir(), 'kn-weiche-'))
writeFileSync(path.join(tmp, 'login.html'), 'ALT')
const a2 = express()
a2.use(umschaltSeitenRouter({ publicDir: tmp, modus: () => 'on', fassung6: () => null }))
a2.use(express.static(tmp))
const srv = await new Promise((res) => {
const s = a2.listen(0, '127.0.0.1', () => res(s))
})
try {
const r = await holen('/login.html', `http://127.0.0.1:${srv.address().port}`)
assert.deepEqual([r.status, r.bytes.toString()], [200, 'ALT'])
// der Rückfall erbt kein no-cache der Weiche (die Datei von heute behält ihren eigenen Cache-Kopf)
assert.notEqual(r.headers.get('cache-control'), 'no-cache')
} finally {
srv.close()
unlinkSync(path.join(tmp, 'login.html'))
rmdirSync(tmp)
}
})
test('nur GET und HEAD: HEAD liefert die neue Seite ohne Inhalt, POST bleibt unberührt', async () => {
modus = 'on'
fassung6 = null
const kopf = await holen('/login.html', app.url, 'HEAD')
assert.deepEqual([kopf.status, kopf.bytes.length, kopf.headers.get('cache-control')], [200, 0, 'no-cache'])
assert.equal(Number(kopf.headers.get('content-length')), datei('neu/oeffentlich/login.html').length)
const post = await holen('/login.html', app.url, 'POST')
assert.equal(post.status, 404)
})
test('Groß- und Kleinschreibung: /Login.html wird nicht umgeleitet (wie express.static)', async () => {
modus = 'on'
assert.equal((await holen('/Login.html')).status, 404)
})
test('server/index.js hängt die Weiche hinter P0s Weichen und vor express.static ein', () => {
const index = readFileSync(new URL('../server/index.js', import.meta.url), 'utf8')
const reihe = ["app.get('/dashboard.html', dashboardWeiche(", 'app.use(umschaltSeitenRouter(', 'app.use(express.static(publicDir))'].map((s) => index.indexOf(s))
assert.ok(reihe[0] > -1 && reihe.every((n, i) => i === 0 || n > reihe[i - 1]), reihe.join(','))
})