import { describe, expect, it } from 'vitest'; import { AsyncMutex } from './async-mutex.js'; const tick = () => new Promise((r) => setTimeout(r, 5)); describe('AsyncMutex', () => { it('runs exclusive sections serially, never overlapping', async () => { const m = new AsyncMutex(); const log: string[] = []; const section = (name: string) => m.runExclusive(async () => { log.push(`${name}:enter`); await tick(); log.push(`${name}:exit`); }); await Promise.all([section('A'), section('B'), section('C')]); // every enter is immediately followed by its own exit (no interleave) expect(log).toEqual(['A:enter', 'A:exit', 'B:enter', 'B:exit', 'C:enter', 'C:exit']); }); it('continues the chain after a rejection', async () => { const m = new AsyncMutex(); const a = m.runExclusive(async () => { throw new Error('boom'); }); await expect(a).rejects.toThrow('boom'); const b = await m.runExclusive(async () => 42); expect(b).toBe(42); }); it('returns the section result', async () => { const m = new AsyncMutex(); expect(await m.runExclusive(async () => 'ok')).toBe('ok'); }); });