keyed-queue.test.ts
1 import { describe, it } from 'node:test' 2 import assert from 'node:assert/strict' 3 import { KeyedAsyncQueue } from './keyed-queue' 4 5 describe('KeyedAsyncQueue', () => { 6 it('serializes tasks within the same key', async () => { 7 const queue = new KeyedAsyncQueue() 8 const order: number[] = [] 9 const delay = (ms: number) => new Promise(r => setTimeout(r, ms)) 10 11 const p1 = queue.enqueue('a', async () => { await delay(30); order.push(1) }) 12 const p2 = queue.enqueue('a', async () => { order.push(2) }) 13 await Promise.all([p1, p2]) 14 assert.deepEqual(order, [1, 2]) 15 }) 16 17 it('runs different keys in parallel', async () => { 18 const queue = new KeyedAsyncQueue() 19 const order: string[] = [] 20 const delay = (ms: number) => new Promise(r => setTimeout(r, ms)) 21 22 const p1 = queue.enqueue('a', async () => { await delay(30); order.push('a') }) 23 const p2 = queue.enqueue('b', async () => { order.push('b') }) 24 await Promise.all([p1, p2]) 25 assert.deepEqual(order, ['b', 'a']) 26 }) 27 28 it('isolates errors between tasks', async () => { 29 const queue = new KeyedAsyncQueue() 30 const p1 = queue.enqueue('a', async () => { throw new Error('fail') }) 31 const p2 = queue.enqueue('a', async () => 'ok') 32 await assert.rejects(p1, /fail/) 33 assert.equal(await p2, 'ok') 34 }) 35 36 it('cleans up keys when queue drains', async () => { 37 const queue = new KeyedAsyncQueue() 38 assert.equal(queue.activeKeys, 0) 39 const p = queue.enqueue('x', async () => 42) 40 assert.equal(queue.activeKeys, 1) 41 await p 42 // Allow microtask for cleanup 43 await new Promise(r => setTimeout(r, 0)) 44 assert.equal(queue.activeKeys, 0) 45 }) 46 47 it('returns the value produced by the enqueued function', async () => { 48 const queue = new KeyedAsyncQueue() 49 const result = await queue.enqueue('k', async () => 'hello') 50 assert.equal(result, 'hello') 51 }) 52 })