import { describe, it, expect } from 'vitest'; import { Readable, type Transform } from 'node:stream'; import { pipeline } from 'node:stream/promises'; import { batch, jsonArray } from '../lib/streams.js'; const collect = async (source: Readable, transform: Transform): Promise => { const out: T[] = []; await pipeline(source, transform, async (results: AsyncIterable) => { for await (const item of results) out.push(item); }); return out; }; describe('batch', () => { it('should group items into fixed-size arrays', async () => { const source = Readable.from([1, 2, 3, 4], { objectMode: true }); const result = await collect(source, batch(2)); expect(result).toEqual([[1, 2], [3, 4]]); }); it('should flush a partial trailing batch', async () => { const source = Readable.from([1, 2, 3, 4, 5], { objectMode: true }); const result = await collect(source, batch(2)); expect(result).toEqual([[1, 2], [3, 4], [5]]); }); it('should emit nothing for an empty source', async () => { const source = Readable.from([], { objectMode: true }); const result = await collect(source, batch(3)); expect(result).toEqual([]); }); it('should reject a non-positive size', () => { expect(() => batch(0)).toThrow(TypeError); expect(() => batch(1.5)).toThrow(TypeError); }); }); describe('jsonArray', () => { const serialize = async (items: unknown[]): Promise => { const chunks = await collect( Readable.from(items, { objectMode: true }), jsonArray() ); return chunks.map(String).join(''); }; it('should serialize objects into a JSON array', async () => { const items = [{ id: 'a' }, { id: 'b' }]; const output = await serialize(items); expect(output).toBe('[{"id":"a"},{"id":"b"}]'); expect(JSON.parse(output)).toEqual(items); }); it('should emit an empty array when the source yields nothing', async () => { const output = await serialize([]); expect(output).toBe('[]'); expect(JSON.parse(output)).toEqual([]); }); it('should emit a valid single-element array', async () => { const output = await serialize([{ id: 'only' }]); expect(JSON.parse(output)).toEqual([{ id: 'only' }]); }); it('should propagate serialization errors', async () => { const circular: Record = {}; circular.self = circular; await expect(serialize([circular])).rejects.toThrow(); }); });