Files
Webklar-Kundenbereich/test/adminPanelGone.test.js
T

97 lines
5.3 KiB
JavaScript

import { test, after } from 'node:test'
import assert from 'node:assert/strict'
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
import path from 'node:path'
import { Router } from 'express'
import { startAppwriteMock } from './support/appwriteMock.js'
import { startFakeStripe } from './support/fakeStripe.js'
import { useTestEnv } from './support/testEnv.js'
// Etappe 4: Admin-Panel, Rechnungsanalyse und alte Admin-Schnittstellen sind weg; was das Ticketsystem nutzt, bleibt
const aw = await startAppwriteMock()
const st = await startFakeStripe()
useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
const { config } = await import('../server/config.js')
const { startTestApp } = await import('./support/testApp.js')
const { viewAsCookie } = await import('./support/fixtures.js')
const { kundenansichtGuard } = await import('../server/middleware/kundenansichtGuard.js')
const { default: legacyAdminRedirect } = await import('../server/routes/legacyAdminRedirect.js')
// Hinter dem Waechter: eine Lese- und eine Schreib-Route, die selbst immer 200 liefern
const probe = Router()
probe.get('/', (_req, res) => res.json({ ok: true }))
probe.post('/', (_req, res) => res.json({ ok: true }))
const app = await startTestApp({ '/': kundenansichtGuard, '/api/projects': probe, '/admin.html': legacyAdminRedirect.admin, '/kalkulation.html': legacyAdminRedirect.kalkulation })
after(() => Promise.all([app.close(), aw.close(), st.close()]))
const root = new URL('..', import.meta.url).pathname
const clears = (res, name) => res.headers.getSetCookie().some((c) => c.startsWith(`${name}=`) && /Expires=Thu, 01 Jan 1970/.test(c))
function filesUnder(dir) {
const out = []
for (const name of readdirSync(dir)) {
const full = path.join(dir, name)
if (statSync(full).isDirectory()) out.push(...filesUnder(full))
else if (/\.(js|mjs|html|css)$/.test(name)) out.push(full)
}
return out
}
test('Admin-Panel und alte Admin-Schnittstellen sind weg', () => {
for (const f of [
'public/admin.html', 'public/admin.js', 'public/kalkulation.html', 'public/kalkulation.js', 'public/kalkulation.css',
'server/routes/portalAdmin.js', 'server/routes/admin/switchLink.js', 'server/routes/admin/previewOpen.js', 'server/services/appointments.js',
]) {
assert.equal(existsSync(path.join(root, f)), false, f)
}
const index = readFileSync(path.join(root, 'server/index.js'), 'utf8')
for (const mount of ['/api/portal-admin', '/api/admin/switch-link', '/api/admin/preview-open']) assert.ok(!index.includes(`'${mount}'`), mount)
for (const f of ['public/chat-composer.js', 'public/chat-composer.css', 'public/kundenansicht.js', 'server/services/staffPreviewLink.js']) {
assert.ok(existsSync(path.join(root, f)), `${f} muss bleiben`)
}
})
test('keine Verweise mehr auf admin.html, kalkulation.html oder /api/portal-admin in server/ und public/', () => {
// einzige Ausnahme: die Weiterleitung alter Mail-Links ins Ticketsystem (Modul und seine zwei Mounts)
const allowed = [path.join(root, 'server/routes/legacyAdminRedirect.js')]
const allowedLines = ["app.use('/admin.html', legacyAdminRedirect.admin)", "app.use('/kalkulation.html', legacyAdminRedirect.kalkulation)"]
const hits = []
for (const file of [...filesUnder(path.join(root, 'server')), ...filesUnder(path.join(root, 'public'))]) {
if (allowed.includes(file)) continue
readFileSync(file, 'utf8').split('\n').forEach((line, i) => {
if (allowedLines.includes(line.trim())) return
if (/admin\.html|kalkulation\.html|\/api\/portal-admin/.test(line)) hits.push(`${path.relative(root, file)}:${i + 1}`)
})
}
assert.deepEqual(hits, [])
})
test('Alt-Ansicht ohne Kennung: Lesen und Schreiben 401 view_expired, Cookies geloescht', async () => {
for (const method of ['GET', 'POST']) {
const res = await fetch(`${app.url}/api/projects`, {
method,
headers: { cookie: viewAsCookie('c1'), ...(method === 'POST' ? { 'content-type': 'application/json' } : {}) },
body: method === 'POST' ? '{}' : undefined,
})
assert.equal(res.status, 401, method)
assert.equal((await res.json()).code, 'view_expired', method)
assert.ok(clears(res, config.cookieName), `${method}: Portal-Cookie geloescht`)
assert.ok(clears(res, 'preview_session'), `${method}: Preview-Cookie geloescht`)
}
})
test('alte Mail-Links (/admin.html, /kalkulation.html) leiten ins Ticketsystem, Antrag direkt geoeffnet', async () => {
const location = async (p) => {
const res = await fetch(`${app.url}${p}`, { redirect: 'manual' })
assert.equal(res.status, 302, p)
return res.headers.get('location')
}
assert.equal(await location('/admin.html?gutschrift=6f1c2d3e-aaaa-4bbb-8ccc-123456789abc'), 'https://ticket.webklar.com/customers/gutschriften?antrag=6f1c2d3e-aaaa-4bbb-8ccc-123456789abc')
assert.equal(await location('/admin.html'), 'https://ticket.webklar.com/customers')
assert.equal(await location('/admin.html?gutschrift=%3Cscript%3E'), 'https://ticket.webklar.com/customers')
assert.equal(await location('/kalkulation.html'), 'https://ticket.webklar.com/customers')
const index = readFileSync(path.join(root, 'server/index.js'), 'utf8')
assert.ok(index.includes("app.use('/admin.html', legacyAdminRedirect.admin)"), 'in server/index.js eingehaengt')
assert.ok(index.indexOf("app.use('/admin.html'") < index.indexOf('express.static(publicDir)'), 'vor den statischen Dateien')
})