diff --git a/app/src/lib/polls/__tests__/beleg.test.ts b/app/src/lib/polls/__tests__/beleg.test.ts index 4439891..70e3bcc 100644 --- a/app/src/lib/polls/__tests__/beleg.test.ts +++ b/app/src/lib/polls/__tests__/beleg.test.ts @@ -59,10 +59,14 @@ describe("Beleg-Code Format (Unit)", () => { } }); - it("streut breit (CSPRNG) — keine Kollisionen über 5000 Codes", () => { + // Siehe verification/__tests__/booking.test.ts: geprüft wird die Streuung des + // CSPRNG, nicht die Eindeutigkeit — für die sorgt der UNIQUE-Constraint mit + // Retry. toBe(5000) wäre bei 40 Bit Entropie im Schnitt alle 88.000 Läufe + // grundlos rot geworden (Geburtstagsproblem). + it("streut breit (CSPRNG) — praktisch kollisionsfrei über 5000 Codes", () => { const set = new Set(); for (let i = 0; i < 5000; i++) set.add(generateBelegCode()); - expect(set.size).toBe(5000); + expect(set.size).toBeGreaterThanOrEqual(4995); }); }); diff --git a/app/src/lib/verification/__tests__/booking.test.ts b/app/src/lib/verification/__tests__/booking.test.ts index aa83e60..62d45d2 100644 --- a/app/src/lib/verification/__tests__/booking.test.ts +++ b/app/src/lib/verification/__tests__/booking.test.ts @@ -60,10 +60,19 @@ describe("Termin-Code Format (Unit)", () => { expect(c.replace(/^TERMIN-/, "")).not.toMatch(/[ILOU]/); } }); - it("streut breit (keine Kollision über 5000)", () => { + // Prüft die STREUUNG des Generators, nicht die Eindeutigkeit der Codes — die + // garantiert nicht er, sondern UNIQUE + Retry in booking-core.ts (fünf + // Versuche mit onConflictDoNothing auf den Code-Constraint). + // + // toBe(5000) war deshalb die falsche Erwartung und dazu flaky: Bei 40 Bit + // Entropie liegt die Kollisionswahrscheinlichkeit über 5000 Ziehungen bei + // rund 1:88.000 pro Lauf (Geburtstagsproblem) — der Test wäre im Schnitt alle + // 88.000 Läufe grundlos rot geworden. Die Schranke lässt einzelne Kollisionen + // zu und schlägt trotzdem an, wenn die Streuung wirklich zusammenbricht. + it("streut breit (praktisch kollisionsfrei über 5000 Codes)", () => { const set = new Set(); for (let i = 0; i < 5000; i++) set.add(generateBookingCode()); - expect(set.size).toBe(5000); + expect(set.size).toBeGreaterThanOrEqual(4995); }); }); diff --git a/app/vitest.config.ts b/app/vitest.config.ts index 837127d..a044606 100644 --- a/app/vitest.config.ts +++ b/app/vitest.config.ts @@ -12,6 +12,14 @@ export default defineConfig({ alias: { "@": path.resolve(__dirname, "./src"), }, + // Setup-Hooks der Integrationstests werfen das Schema weg und fahren die + // gesamte Migrationskette neu hoch. Deren Dauer wächst mit jeder Migration, + // der Standard-Timeout von 10 s aber nicht — email-change.test.ts lief + // deshalb sporadisch in einen beforeAll-Timeout, einzeln aber grün. Ein + // roter Lauf ohne echten Fehler ist teurer als eine großzügige Schranke: + // Er wird beim nächsten Mal weggeklickt, und dann fällt ein echter Fehler + // auch nicht mehr auf. + hookTimeout: 60_000, // Sequentielle Ausführung: Integrationstests teilen dieselbe Test-DB // und würden sich bei paralleler Ausführung gegenseitig beim Schema-Reset stören. pool: "forks",