mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
adding ability to record logs for debug purposes
This commit is contained in:
89
test/services/logger.test.js
Normal file
89
test/services/logger.test.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2026 by Christian Kellner.
|
||||
* Licensed under Apache-2.0 with Commons Clause and Attribution/Naming Clause
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import path from 'node:path';
|
||||
|
||||
describe('services/logger.js - debug log sink', () => {
|
||||
let logger;
|
||||
let setDebugLogSink;
|
||||
let consoleSpies;
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
const mod = await import(path.resolve('lib/services/logger.js'));
|
||||
logger = mod.default;
|
||||
setDebugLogSink = mod.setDebugLogSink;
|
||||
|
||||
// Silence console output so test runner stdout stays readable while still
|
||||
// letting us inspect what the logger emitted if a test wants to.
|
||||
consoleSpies = {
|
||||
debug: vi.spyOn(console, 'debug').mockImplementation(() => {}),
|
||||
info: vi.spyOn(console, 'info').mockImplementation(() => {}),
|
||||
warn: vi.spyOn(console, 'warn').mockImplementation(() => {}),
|
||||
error: vi.spyOn(console, 'error').mockImplementation(() => {}),
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
setDebugLogSink(null);
|
||||
for (const spy of Object.values(consoleSpies)) spy.mockRestore();
|
||||
});
|
||||
|
||||
it('is a no-op for the sink when none is registered', () => {
|
||||
// Just make sure nothing throws.
|
||||
expect(() => logger.info('hello')).not.toThrow();
|
||||
expect(() => logger.error(new Error('boom'))).not.toThrow();
|
||||
});
|
||||
|
||||
it('forwards every log level (including debug) to the registered sink', () => {
|
||||
const captured = [];
|
||||
setDebugLogSink((entry) => captured.push(entry));
|
||||
|
||||
logger.debug('debug-line');
|
||||
logger.info('info-line');
|
||||
logger.warn('warn-line');
|
||||
logger.error('error-line');
|
||||
|
||||
expect(captured).toHaveLength(4);
|
||||
expect(captured.map((c) => c.level)).toEqual(['debug', 'info', 'warn', 'error']);
|
||||
expect(captured[0].message).toContain('debug-line');
|
||||
expect(captured[1].message).toContain('info-line');
|
||||
expect(captured[2].message).toContain('warn-line');
|
||||
expect(captured[3].message).toContain('error-line');
|
||||
for (const c of captured) {
|
||||
expect(typeof c.ts).toBe('number');
|
||||
}
|
||||
});
|
||||
|
||||
it('serializes Error stacks for the sink instead of "[object Object]"', () => {
|
||||
const captured = [];
|
||||
setDebugLogSink((entry) => captured.push(entry));
|
||||
|
||||
logger.error(new Error('boom'));
|
||||
|
||||
expect(captured).toHaveLength(1);
|
||||
expect(captured[0].message).toContain('Error: boom');
|
||||
});
|
||||
|
||||
it('stops forwarding once the sink is unregistered', () => {
|
||||
const captured = [];
|
||||
setDebugLogSink((entry) => captured.push(entry));
|
||||
logger.info('one');
|
||||
setDebugLogSink(null);
|
||||
logger.info('two');
|
||||
|
||||
expect(captured).toHaveLength(1);
|
||||
expect(captured[0].message).toContain('one');
|
||||
});
|
||||
|
||||
it('does not break the caller when the sink throws', () => {
|
||||
setDebugLogSink(() => {
|
||||
throw new Error('sink exploded');
|
||||
});
|
||||
expect(() => logger.info('still works')).not.toThrow();
|
||||
expect(consoleSpies.info).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user