Umsetzung des "Website Masterplan" (16 Seiten) unter /webdesign. Zugangsschutz mit EIGENER Schranke (server/webdesign-gate.js) statt gate.js: gate.js laesst seit dem oeffentlichen Start am 21.08.2026 jeden durch, weil die Pruefung auf SITE_PUBLIC_LAUNCH_AT als allererste Zeile steht. Haette man /webdesign dahintergehaengt, waere der ausdruecklich nicht-oeffentliche Bereich inklusive Preisen und spaeteren Kundendaten ab der ersten Sekunde fuer jeden lesbar gewesen. Eigenes Sitzungs-Cookie, bereich="webdesign" im Token, damit ein gueltiges Universe-Cookie hier NICHT gilt. 37/37 Tests. Sieben oeffentliche Seiten in fuenf Sprachen (de, de-CH mit echtem Dialekt, en, fr, pt). Preise, Zeitrahmen, Paketnamen und die 30-%-Regel stehen an genau EINER Stelle in wd-core.js -- der Masterplan verlangt "ueberall widerspruchsfrei", und vier Kopien laufen bei der ersten Preisaenderung auseinander. Als App installierbar auf Handy und PC. Der Service Worker speichert bewusst KEINE HTML-Seite zwischen: nach dem Abmelden wuerden sonst geschuetzte Seiten weiter ausgeliefert, ohne dass der Server je gefragt wird. 18/18 Tests. Handy-Abnahme ueber alle Seiten in fuenf Breiten (320-1440) und fuenf Sprachen: 40/40. Der Test fand 35 echte Fehler (Touch-Ziele unter 44px), behoben im Designsystem statt einzeln pro Seite. PayPal (Wunsch 22.08.2026 "sofort auf meinem paypal"): Orders API mit intent=CAPTURE, also sofortiger Einzug statt blosser Reservierung. Gebuehr und Nettobetrag getrennt gespeichert. Betraege durchgehend als Ganzzahl in Cent. Gefaelschte Webhooks werden abgewiesen. Fail closed solange Zugangsdaten fehlen. 28/28 Tests gegen einen nachgebauten PayPal-Server. Datenbank: 15 Tabellen mit Praefix wd_, fachlich vollstaendig vom Universe getrennt. Co-Authored-By: Claude Opus 5 <[email protected]>
44 lines
1.9 KiB
JavaScript
44 lines
1.9 KiB
JavaScript
/* Prüft den Steuerzeichen-Filter aus webdesign-helfer.js isoliert.
|
|
Bewusst mit String.fromCharCode statt echten Steuerzeichen im Quelltext. */
|
|
const f = (w, max = 2000) =>
|
|
String(w).replace(/[^\P{Cc}\n\t]/gu, "").trim().slice(0, max);
|
|
|
|
const NUL = String.fromCharCode(0);
|
|
const BELL = String.fromCharCode(7);
|
|
const CR = String.fromCharCode(13);
|
|
const ESC = String.fromCharCode(27);
|
|
const DEL = String.fromCharCode(127);
|
|
const NL = "\n";
|
|
const TAB = "\t";
|
|
|
|
const proben = [
|
|
["einfacher Text", "Hallo Welt", "Hallo Welt"],
|
|
["Zeilenumbruch bleibt", "Zeile1" + NL + "Zeile2", "Zeile1" + NL + "Zeile2"],
|
|
["Tabulator bleibt", "Tab" + TAB + "hier", "Tab" + TAB + "hier"],
|
|
["Nullbyte raus", "Text" + NUL + "mehr", "Textmehr"],
|
|
["Bell raus", "Bell" + BELL + "X", "BellX"],
|
|
["Escape raus (Terminal-Trick)", ESC + "[31mrot", "[31mrot"],
|
|
["DEL raus", "A" + DEL + "B", "AB"],
|
|
/* Erwartung bewusst ohne führenden Umbruch: der Filter entfernt zwar nur
|
|
den Wagenrücklauf, das anschließende trim() räumt den dann alleine
|
|
stehenden Zeilenumbruch am Rand aber mit weg. Genau so ist es gewollt. */
|
|
["Wagenruecklauf raus", CR + NL + "Text" + CR, "Text"],
|
|
["Randleerzeichen weg", " Rand ", "Rand"],
|
|
["Umlaute bleiben", "Umlaute äöüß bleiben", "Umlaute äöüß bleiben"],
|
|
["Emoji bleibt", "Emoji \u{1F43A} bleibt", "Emoji \u{1F43A} bleibt"],
|
|
];
|
|
|
|
let ok = 0, schlecht = 0;
|
|
for (const [name, ein, erwartet] of proben) {
|
|
const raus = f(ein);
|
|
if (raus === erwartet) { ok++; console.log(" ok " + name); }
|
|
else { schlecht++; console.log(" FEHLT " + name + " -> " + JSON.stringify(raus) + " statt " + JSON.stringify(erwartet)); }
|
|
}
|
|
|
|
const lang = f("x".repeat(5000), 10);
|
|
if (lang.length === 10) { ok++; console.log(" ok Laengenbegrenzung greift"); }
|
|
else { schlecht++; console.log(" FEHLT Laengenbegrenzung: " + lang.length); }
|
|
|
|
console.log(`\n=== ${ok} ok, ${schlecht} falsch ===`);
|
|
process.exit(schlecht === 0 ? 0 : 1);
|