Files
KantSites/scripts/audit.mjs
T
kantarciandClaude Opus 5.5 0ba82b7d33
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
Prepare the Kantarci Markt opening page with offers from the app
- /eroeffnung (noindex, unlinked): opening hero, offers embedded from
  app.kantarci-markt.de without title and app button, app store buttons,
  visit section with route, hours and contact placeholders.
- The height script on the embed asks the app for its height once it runs
  (it is deferred and missed the first report) and scrolls to the offer
  popup when the app reports it outside the viewport.
- audit.mjs takes CMS_HOST_RULES, because the app allows framing only from
  localhost while the server listens on 127.0.0.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 16:02:57 +02:00

61 lines
3.3 KiB
JavaScript

import lighthouse from 'lighthouse';
import desktopConfig from 'lighthouse/core/config/desktop-config.js';
import { chromium } from 'playwright';
import { mkdir, writeFile } from 'node:fs/promises';
import net from 'node:net';
const origin = process.env.CMS_URL || 'http://127.0.0.1:8080';
// Eine Startseite ist nicht die Website. Geprüft wird, was CMS_PATHS nennt - mehrere Adressen mit
// Komma getrennt; ohne Angabe die Startseite.
const paths = (process.env.CMS_PATHS || '/').split(',').map(p => p.trim()).filter(Boolean);
const output = process.env.CMS_AUDIT_DIR || 'reports/lighthouse';
const preflight = await fetch(origin);
if (!preflight.ok || /noindex/i.test(preflight.headers.get('x-robots-tag') || '')) {
throw new Error('Audit requires an indexable HTTP 200 page in production mode. Check APP_ENV and APP_DEBUG.');
}
await mkdir(output, { recursive: true });
const portProbe = net.createServer();
await new Promise(resolve => portProbe.listen(0, '127.0.0.1', resolve));
const port = portProbe.address().port;
await new Promise(resolve => portProbe.close(resolve));
// CMS_HOST_RULES, etwa "MAP localhost 127.0.0.1": für eingebettete Seiten, die das Einbetten nur
// von localhost erlauben, während der Server auf 127.0.0.1 lauscht (Kantarci-Markt-App).
const chrome = await chromium.launch({ args: [`--remote-debugging-port=${port}`, ...(process.env.CMS_HOST_RULES ? [`--host-resolver-rules=${process.env.CMS_HOST_RULES}`] : [])] });
const summary = [];
try {
for (const path of paths) {
const label = '/' === path ? 'home' : path.replace(/^\//, '').replace(/\//g, '-');
for (const profile of ['mobile', 'desktop']) {
const runs = [];
for (let run = 1; run <= 3; run++) {
const result = await lighthouse(origin + ('/' === path ? '' : path), {
port,
output: 'json',
logLevel: 'error',
}, profile === 'desktop' ? desktopConfig : undefined);
const lhr = result.lhr;
if (lhr.configSettings.formFactor !== profile) {
throw new Error(`Requested ${profile}, measured ${lhr.configSettings.formFactor}`);
}
await writeFile(`${output}/${label}-${profile}-${run}.json`, result.report);
runs.push(lhr);
console.log(label, profile, run, Object.fromEntries(Object.entries(lhr.categories).map(([key, value]) => [key, value.score])));
}
const scores = {};
for (const category of Object.keys(runs[0].categories)) {
const values = runs.map(r => r.categories[category].score).filter(v => v !== null).sort((a, b) => a - b);
scores[category] = values.length ? values[Math.floor(values.length / 2)] : null;
}
summary.push({ path, profile, scores, lighthouseVersion: runs[0].lighthouseVersion, settings: runs[0].configSettings, environment: runs[0].environment, note: 'Local prototype only. No customer-site acceptance or field-data claim.' });
}
}
await writeFile(`${output}/summary.json`, JSON.stringify(summary, null, 2));
for (const row of summary) {
console.log(`${row.path} ${row.profile}: ${Object.entries(row.scores).map(([k, v]) => k + ' ' + Math.round(v * 100)).join(', ')}`);
}
const passed = summary.every(r => r.scores.performance >= .95 && ['accessibility', 'best-practices', 'seo'].every(c => r.scores[c] === 1) && (r.scores['agentic-browsing'] === undefined || r.scores['agentic-browsing'] === 1));
if (!passed) process.exitCode = 1;
} finally {
await chrome.close();
}