test: add unit tests for handler, logger, manager, and config

Cover Handler property accessors, format delegation, emit contract,
and close lifecycle. Cover Logger level methods, isEnabledFor caching,
manager property assignment, handler management, debug invocation,
and makeRecord extra key collision. Cover Manager getLogger hierarchy
setup, placeholder fixup, disable level, and loggerClass validation.
Cover basicConfig option handling, force flag, mutual exclusion of
stream/filename/handlers, and formatter assignment.
This commit is contained in:
Tiara Rodney 2026-03-13 22:49:12 +01:00
parent 0b87f5516a
commit 3b6b116b00
No known key found for this signature in database
GPG key ID: 5CD8EC1D46106723
4 changed files with 494 additions and 0 deletions

93
tests/unit/config.test.ts Normal file
View file

@ -0,0 +1,93 @@
import {expect, jest, test} from '@jest/globals';
import { basicConfig } from '../../src/config';
import { MANAGER } from '../../src/manager';
import { Handler } from '../../src/handler';
import { LogRecord } from '../../src/log-record';
import { Formatter } from '../../src/formatter';
import { DEBUG, WARNING, ERROR } from '../../src/log-level';
describe('basicConfig', () => {
beforeEach(() => {
MANAGER.root.handlers.splice(0, MANAGER.root.handlers.length);
});
test('adds a handler to the root logger', () => {
basicConfig({});
expect(MANAGER.root.handlers.length).toBeGreaterThan(0);
});
test('sets root logger level', () => {
basicConfig({ level: DEBUG });
expect(MANAGER.root.level).toBe(DEBUG);
});
test('does nothing when handlers already exist and force is false', () => {
basicConfig({ level: DEBUG });
const handlerCount = MANAGER.root.handlers.length;
basicConfig({ level: ERROR });
expect(MANAGER.root.handlers.length).toBe(handlerCount);
expect(MANAGER.root.level).toBe(DEBUG);
});
test('replaces handlers when force is true', () => {
basicConfig({ level: DEBUG });
basicConfig({ level: ERROR, force: true });
expect(MANAGER.root.level).toBe(ERROR);
});
test('throws on invalid style', () => {
expect(() => {
basicConfig({ style: 'X' });
}).toThrow('style must be one of');
});
test('throws when stream and filename both specified', () => {
expect(() => {
basicConfig({
stream: process.stderr,
filename: 'test.log',
});
}).toThrow('should not be specified together');
});
test('throws when handlers and stream both specified', () => {
class TestHandler extends Handler {
emit(record: LogRecord) {}
}
expect(() => {
basicConfig({
handlers: [new TestHandler()],
stream: process.stderr,
});
}).toThrow('should not be specified together');
});
test('uses provided handlers', () => {
class TestHandler extends Handler {
emit(record: LogRecord) {}
}
const handler = new TestHandler();
basicConfig({ handlers: [handler] });
expect(MANAGER.root.handlers).toContain(handler);
});
test('assigns formatter to handlers without one', () => {
class TestHandler extends Handler {
emit(record: LogRecord) {}
}
const handler = new TestHandler();
expect(handler.formatter).toBeNull();
basicConfig({ handlers: [handler] });
expect(handler.formatter).not.toBeNull();
});
test('preserves existing formatter on handlers', () => {
class TestHandler extends Handler {
emit(record: LogRecord) {}
}
const handler = new TestHandler();
const fmt = new Formatter({ fmt: '%(message)s' });
handler.formatter = fmt;
basicConfig({ handlers: [handler] });
expect(handler.formatter).toBe(fmt);
});
});