Analyse: Portal-Texte, Verantwortlichen-Vorschau und Bestätigungen nach geprüftem Wortlaut
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ddb91a9950
commit
3bac4093af
8 files changed
+253
-25
No files matched your search
@@ -0,0 +1,108 @@
|
||||
// Playwright-Check Analyse-Panel (Einschalten-Dialog + aktives Panel): statischer Server fuer public/ + gemockte API.
|
||||
// Nicht Teil von npm test. Aufruf: node test/ui/analyse.ui.mjs [Ausgabeordner]
|
||||
import http from 'node:http'
|
||||
import { readFile, mkdir } from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { chromium } from '/root/.npm/_npx/db89d7302a373f10/node_modules/playwright-core/index.mjs'
|
||||
|
||||
const pub = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../public')
|
||||
const SHOTS = process.argv[2] || '/root/reports/website-analyse-2026-10-01'
|
||||
await mkdir(SHOTS, { recursive: true })
|
||||
const TYPES = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.svg': 'image/svg+xml', '.png': 'image/png', '.ico': 'image/x-icon', '.webmanifest': 'application/json' }
|
||||
const server = http.createServer(async (req, res) => {
|
||||
const url = new URL(req.url, 'http://x')
|
||||
try {
|
||||
const file = path.join(pub, url.pathname === '/' ? 'dashboard.html' : url.pathname)
|
||||
const data = await readFile(file)
|
||||
res.writeHead(200, { 'content-type': TYPES[path.extname(file)] || 'application/octet-stream' })
|
||||
res.end(data)
|
||||
} catch { res.writeHead(404); res.end('nicht gefunden') }
|
||||
})
|
||||
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve))
|
||||
const base = `http://127.0.0.1:${server.address().port}`
|
||||
|
||||
const legal = { avv: '/rechtliches/avv-website-analyse-2026-10-02.html', lb: '/rechtliches/leistungsbeschreibung-website-analyse-2026-10-02.html' }
|
||||
const controller = { ok: true, company: 'Bäckerei Berg GmbH', address: 'Hauptstraße 1, 12345 Musterstadt', email: 'info@baeckerei-berg.example' }
|
||||
const base1 = { projectId: 'p1', projectName: 'Bäckerei Berg', liveUrl: 'https://baeckerei.example', features: { news: { state: 'off' } } }
|
||||
const SCENARIOS = {
|
||||
off: { ...base1, analyse: { state: 'off', eligible: true, accentColor: '#1d4ed8', avvVersion: '2026-10-02', legal, controller } },
|
||||
missing: { ...base1, analyse: { state: 'off', eligible: true, accentColor: '#1d4ed8', avvVersion: '2026-10-02', legal, controller: { ok: false, company: '', address: '', email: '', missing: ['firma'] } } },
|
||||
active: { ...base1, analyse: { state: 'active', eligible: true, accentColor: '#1d4ed8', avvVersion: '2026-10-02', legal, controller } },
|
||||
}
|
||||
const days = Array.from({ length: 14 }, (_, i) => ({ day: `2026-09-${String(17 + i).padStart(2, '0')}`, pv: 20 + ((i * 7) % 13) * 4 }))
|
||||
const stats = {
|
||||
totals: { pv: 612, visitors: 214, contacts: 18, consentRate: 0.62 }, series: days,
|
||||
pages: [{ key: '/', count: 300 }, { key: '/kontakt', count: 120 }], refs: [{ key: '', count: 200 }, { key: 'google.com', count: 90 }],
|
||||
countries: [{ key: 'DE', count: 500 }], devices: [{ key: 'm', count: 380 }, { key: 'd', count: 230 }], contacts: [{ key: 'tel', count: 12 }],
|
||||
banner: { shown: 300, accept: 186, reject: 114 },
|
||||
}
|
||||
let scenario = 'off'
|
||||
const browser = await chromium.launch()
|
||||
let failed = 0
|
||||
const check = (name, ok) => { console.log(`${ok ? 'OK ' : 'FAIL'} ${name}`); if (!ok) failed += 1 }
|
||||
try {
|
||||
for (const [label, viewport] of [['desktop', { width: 1280, height: 900 }], ['phone', { width: 390, height: 844 }]]) {
|
||||
const ctx = await browser.newContext({ viewport })
|
||||
const page = await ctx.newPage()
|
||||
const errors = []
|
||||
page.on('pageerror', (e) => errors.push(e.message))
|
||||
await page.route('**/api/**', async (route) => {
|
||||
const p = new URL(route.request().url()).pathname
|
||||
const json = (b) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(b) })
|
||||
if (p === '/api/auth/me') return json({ authenticated: true, role: 'customer', customer: { id: 'c1', code: '1001', name: 'Berta Berg', email: 'b@example.test' } })
|
||||
if (p === '/api/projects') return json({ projects: [{ id: 'p1', name: 'Bäckerei Berg', status: 'live' }] })
|
||||
if (p === '/api/features') return json({ features: [] })
|
||||
if (p === '/api/activity') return json({ tickets: [] })
|
||||
if (p === '/api/funktionen') return json({ projects: [SCENARIOS[scenario]] })
|
||||
if (p === '/api/funktionen/analyse/stats') return json(stats)
|
||||
if (p === '/api/funktionen/analyse/deactivate') return json({ ok: true })
|
||||
return json({})
|
||||
})
|
||||
const open = async (sc) => {
|
||||
scenario = sc
|
||||
await page.goto('about:blank')
|
||||
await page.goto(`${base}/dashboard.html#analyse`)
|
||||
await page.waitForSelector('#analyse-body .kb-panel')
|
||||
await page.waitForTimeout(900)
|
||||
}
|
||||
const shot = async (name) => {
|
||||
const height = await page.evaluate(() => Math.min(document.documentElement.scrollHeight, 3200))
|
||||
await page.setViewportSize({ width: viewport.width, height: Math.max(viewport.height, height) })
|
||||
await page.waitForTimeout(150)
|
||||
await page.screenshot({ path: `${SHOTS}/task-7-${label}-${name}.png` })
|
||||
await page.setViewportSize(viewport)
|
||||
}
|
||||
const noScroll = async (n) => check(`${label} kein_horizontaler_scroll ${n}`, await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth))
|
||||
|
||||
await open('off')
|
||||
const text = await page.textContent('#analyse-body')
|
||||
check(`${label} verantwortlicher`, text.includes('Bäckerei Berg GmbH') && text.includes('info@baeckerei-berg.example'))
|
||||
check(`${label} links`, (await page.$$eval('#analyse-body a[href^="/rechtliches/"]', (a) => a.map((x) => x.getAttribute('href')))).join() === `${legal.avv},${legal.lb}`)
|
||||
check(`${label} knopf_gesperrt_ohne_haken`, await page.isDisabled('#an-on'))
|
||||
await page.check('#an-avv')
|
||||
check(`${label} knopf_frei_mit_haken`, !(await page.isDisabled('#an-on')))
|
||||
await noScroll('einschalten')
|
||||
await shot('einschalten')
|
||||
|
||||
await open('missing')
|
||||
await page.check('#an-avv')
|
||||
check(`${label} gesperrt_ohne_angaben`, (await page.isDisabled('#an-on')) && Boolean(await page.$('#an-missing')))
|
||||
|
||||
await open('active')
|
||||
await page.waitForSelector('.an-kpis')
|
||||
await noScroll('aktiv')
|
||||
await shot('aktiv')
|
||||
await page.click('#an-off-ask')
|
||||
await page.click('#an-off-yes')
|
||||
await page.waitForSelector('#an-off-done')
|
||||
check(`${label} ausschalten_bestaetigung`, (await page.textContent('#an-off-done')).includes('Ab jetzt werden keine Daten mehr gespeichert'))
|
||||
await shot('ausgeschaltet')
|
||||
check(`${label} keine_js_fehler`, errors.length === 0)
|
||||
await ctx.close()
|
||||
}
|
||||
} finally {
|
||||
await browser.close()
|
||||
server.close()
|
||||
}
|
||||
process.exit(failed ? 1 : 0)
|
||||
Reference in new issue
Block a user