import type { Transform } from 'node:stream'; import buildOtelTimeTransform from './otel-time.transform'; /** Прогоняет NDJSON-строки через трансформ и возвращает распарсенный вывод. */ async function run(lines: object[]): Promise[]> { const stream: Transform = await buildOtelTimeTransform(); const collected = new Promise[]>((resolve) => { let out = ''; stream.on('data', (chunk) => (out += chunk)); stream.on('end', () => resolve( out .trim() .split('\n') .filter(Boolean) .map((line) => JSON.parse(line)), ), ); }); for (const line of lines) { stream.write(`${JSON.stringify(line)}\n`); } stream.end(); return collected; } describe('otel-time.transform', () => { it('конвертирует строковый ISO time в epoch ms', async () => { const iso = '2026-06-24T19:04:21.991Z'; const [record] = await run([{ level: 30, time: iso, msg: 'x' }]); expect(record.time).toBe(Date.parse(iso)); expect(typeof record.time).toBe('number'); }); it('не трогает уже числовой time', async () => { const [record] = await run([{ level: 30, time: 1782327861991, msg: 'x' }]); expect(record.time).toBe(1782327861991); }); it('не падает на отсутствии time', async () => { const [record] = await run([{ level: 30, msg: 'x' }]); expect('time' in record).toBe(false); expect(record.msg).toBe('x'); }); it('оставляет невалидную строку как есть', async () => { const [record] = await run([{ level: 30, time: 'not-a-date', msg: 'x' }]); expect(record.time).toBe('not-a-date'); }); });