import { test } from 'node:test'; import assert from 'node:assert/strict'; const { coalesce } = await import('../src/coalesce.js'); const tick = (ms = 5) => new Promise((r) => setTimeout(r, ms)); test('coalesce: nie mehr als ein Lauf gleichzeitig pro Key', async () => { let active = 0, maxActive = 0, runs = 0; const fn = async () => { active++; maxActive = Math.max(maxActive, active); await tick(10); runs++; active--; return runs; }; // 5 gleichzeitige Aufrufe. await Promise.all(Array.from({ length: 5 }, () => coalesce('k1', fn))); assert.equal(maxActive, 1, 'parallele Läufe'); // Erster Lauf bedient den ersten Aufruf; die 4 während des Laufs eingetroffenen // teilen sich GENAU EINEN nachgelagerten Lauf → insgesamt 2. assert.equal(runs, 2); }); test('coalesce: Wartende teilen sich das Ergebnis des nachgelagerten Laufs', async () => { let n = 0; const fn = async () => { await tick(10); return ++n; }; const first = coalesce('k2', fn); // startet sofort → Ergebnis 1 await tick(2); // sicherstellen, dass er läuft const a = coalesce('k2', fn); // wartet → nachgelagerter Lauf const b = coalesce('k2', fn); // wartet → selber Lauf wie a assert.equal(await first, 1); const [ra, rb] = await Promise.all([a, b]); assert.equal(ra, 2); assert.equal(rb, 2); // a und b teilen sich Lauf 2 }); test('coalesce: Fehler wird an die Wartenden propagiert, Key bleibt nutzbar', async () => { let fail = true; const fn = async () => { await tick(5); if (fail) throw new Error('boom'); return 'ok'; }; await assert.rejects(() => coalesce('k3', fn), /boom/); fail = false; assert.equal(await coalesce('k3', fn), 'ok'); // danach wieder verwendbar }); test('coalesce: verschiedene Keys laufen unabhängig', async () => { const fn = async () => { await tick(5); return 'done'; }; const [x, y] = await Promise.all([coalesce('kA', fn), coalesce('kB', fn)]); assert.equal(x, 'done'); assert.equal(y, 'done'); });