import { test } from 'node:test'; import assert from 'node:assert/strict'; import { spawnSync } from 'node:child_process'; // Regression test: the logger must produce real JSON lines, not the // literal string "undefined" (a bug caused by passing JSON.stringify a // replacer *factory* instead of calling it first). test('logger prints a parseable JSON object with the expected fields, not "undefined"', () => { const script = ` import { createLogger } from '${import.meta.resolve('../src/logger.js').replace('file://', '')}'; createLogger({ component: 'x' }).info('hello', { foo: 'bar' }); `; const result = spawnSync(process.execPath, ['--input-type=module', '-e', script], { encoding: 'utf8' }); assert.equal(result.status, 0, result.stderr); const line = result.stdout.trim(); assert.notEqual(line, 'undefined'); const parsed = JSON.parse(line); assert.equal(parsed.level, 'info'); assert.equal(parsed.msg, 'hello'); assert.equal(parsed.component, 'x'); assert.equal(parsed.foo, 'bar'); assert.ok(parsed.time); }); test('logger.child merges bindings and does not mutate the parent', () => { const script = ` import { createLogger } from '${import.meta.resolve('../src/logger.js').replace('file://', '')}'; const parent = createLogger({ a: 1 }); const child = parent.child({ b: 2 }); child.info('from child'); parent.info('from parent'); `; const result = spawnSync(process.execPath, ['--input-type=module', '-e', script], { encoding: 'utf8' }); assert.equal(result.status, 0, result.stderr); const [childLine, parentLine] = result.stdout.trim().split('\n').map((l) => JSON.parse(l)); assert.deepEqual({ a: childLine.a, b: childLine.b }, { a: 1, b: 2 }); assert.equal(parentLine.b, undefined); }); test('debug messages are suppressed at the default (info) log level', () => { const script = ` import { createLogger } from '${import.meta.resolve('../src/logger.js').replace('file://', '')}'; createLogger({}).debug('should not appear'); createLogger({}).info('should appear'); `; const result = spawnSync(process.execPath, ['--input-type=module', '-e', script], { encoding: 'utf8', env: { ...process.env, LOG_LEVEL: 'info' }, }); assert.equal(result.status, 0, result.stderr); const lines = result.stdout.trim().split('\n').filter(Boolean); assert.equal(lines.length, 1); assert.equal(JSON.parse(lines[0]).msg, 'should appear'); }); test('errors are logged with name/message/stack, not serialized to {}', () => { const script = ` import { createLogger } from '${import.meta.resolve('../src/logger.js').replace('file://', '')}'; createLogger({}).error('boom', { error: new Error('bad thing') }); `; const result = spawnSync(process.execPath, ['--input-type=module', '-e', script], { encoding: 'utf8' }); assert.equal(result.status, 0, result.stderr); const parsed = JSON.parse(result.stderr.trim()); assert.equal(parsed.error.message, 'bad thing'); assert.equal(parsed.error.name, 'Error'); assert.ok(parsed.error.stack); });