192 lines
5.9 KiB
TypeScript
192 lines
5.9 KiB
TypeScript
/**
|
|
* Logger Test Setup
|
|
*
|
|
* Setup file specific to Logger library tests.
|
|
* Provides utilities and mocks for testing logging operations.
|
|
*/
|
|
|
|
import { Logger, LogMetadata } from '../src';
|
|
import { afterAll, afterEach, beforeAll, beforeEach } from 'bun:test';
|
|
|
|
// Store original console methods
|
|
const originalConsole = {
|
|
log: console.log,
|
|
info: console.info,
|
|
warn: console.warn,
|
|
error: console.error,
|
|
debug: console.debug
|
|
};
|
|
|
|
// Create a test logger helper
|
|
export const loggerTestHelpers = {
|
|
/**
|
|
* Create a test logger instance that captures logs locally.
|
|
*/
|
|
createTestLogger: (serviceName: string = 'test-service', initialContext: any = {}) => {
|
|
const capturedLogsArray: any[] = [];
|
|
|
|
const createLoggerMockInstance = (currentContext: any): Logger => {
|
|
const buildLogEntry = (level: string, messageOrObject: string | object, metadata?: any) => {
|
|
const logObject: any = { level, service: serviceName, ...currentContext };
|
|
|
|
if (typeof messageOrObject === 'string') {
|
|
logObject.msg = messageOrObject;
|
|
if (metadata) {
|
|
Object.assign(logObject, metadata);
|
|
}
|
|
} else { // messageOrObject is an object
|
|
Object.assign(logObject, messageOrObject); // Merge fields from the message object
|
|
if (metadata) { // If metadata is also provided (e.g. logger.error({code: 1}, {extra: 'data'}))
|
|
Object.assign(logObject, metadata);
|
|
}
|
|
// Ensure 'msg' field exists, defaulting if necessary
|
|
if (typeof logObject.msg === 'undefined') {
|
|
// If the second arg was a string, it might have been intended as the message
|
|
if (typeof metadata === 'string') {
|
|
logObject.msg = metadata;
|
|
} else {
|
|
logObject.msg = 'Object logged';
|
|
}
|
|
}
|
|
}
|
|
capturedLogsArray.push(logObject);
|
|
};
|
|
|
|
return {
|
|
// serviceName, // For inspection if needed, though logs capture it
|
|
context: currentContext, // For inspection
|
|
debug: (msgOrObj: string | object, meta?: any) => buildLogEntry('debug', msgOrObj, meta),
|
|
info: (msgOrObj: string | object, meta?: any) => buildLogEntry('info', msgOrObj, meta),
|
|
warn: (msgOrObj: string | object, meta?: any) => buildLogEntry('warn', msgOrObj, meta),
|
|
error: (msgOrObj: string | object, metaOrMsg?: any) => buildLogEntry('error', msgOrObj, metaOrMsg),
|
|
child: (childContext: any): Logger => {
|
|
// Children will log to the same capturedLogsArray
|
|
return createLoggerMockInstance({ ...currentContext, ...childContext });
|
|
}
|
|
} as any; // Cast to Logger, assuming it fulfills the interface for testing purposes
|
|
};
|
|
|
|
const loggerInstance = createLoggerMockInstance(initialContext);
|
|
|
|
return {
|
|
logger: loggerInstance,
|
|
getCapturedLogs: () => [...capturedLogsArray],
|
|
clearCapturedLogs: () => {
|
|
capturedLogsArray.length = 0;
|
|
}
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Mock Loki transport
|
|
*/
|
|
mockLokiTransport: () => ({
|
|
on: () => {},
|
|
write: () => {}
|
|
}),
|
|
/**
|
|
* Create a mock Hono context for middleware tests
|
|
*/ createHonoContextMock: (options: any = {}) => {
|
|
// Default path and method
|
|
const path = options.path || '/test';
|
|
const method = options.method || 'GET';
|
|
|
|
// Create request headers
|
|
const headerEntries = Object.entries(options.req?.headers || {});
|
|
const headerMap = new Map(headerEntries);
|
|
const rawHeaders = new Headers();
|
|
headerEntries.forEach(([key, value]) => rawHeaders.set(key, value as string));
|
|
|
|
// Create request with standard properties needed for middleware
|
|
const req = {
|
|
method,
|
|
url: `http://localhost${path}`,
|
|
path,
|
|
raw: {
|
|
url: `http://localhost${path}`,
|
|
method,
|
|
headers: rawHeaders
|
|
},
|
|
query: {},
|
|
param: () => undefined,
|
|
header: (name: string) => rawHeaders.get(name.toLowerCase()),
|
|
headers: headerMap,
|
|
...options.req
|
|
};
|
|
|
|
// Create mock response
|
|
const res = {
|
|
status: 200,
|
|
statusText: 'OK',
|
|
body: null,
|
|
headers: new Map(),
|
|
clone: function() { return { ...this, text: async () => JSON.stringify(this.body) }; },
|
|
text: async () => JSON.stringify(res.body),
|
|
...options.res
|
|
};
|
|
|
|
// Create context with all required Hono methods
|
|
const c: any = {
|
|
req,
|
|
env: {},
|
|
res,
|
|
header: (name: string, value: string) => {
|
|
c.res.headers.set(name.toLowerCase(), value);
|
|
return c;
|
|
},
|
|
get: (key: string) => c[key],
|
|
set: (key: string, value: any) => { c[key] = value; return c; },
|
|
status: (code: number) => { c.res.status = code; return c; },
|
|
json: (body: any) => { c.res.body = body; return c; },
|
|
executionCtx: { waitUntil: (fn: Function) => { fn(); } }
|
|
};
|
|
|
|
return c;
|
|
},
|
|
|
|
/**
|
|
* Create a mock Next function for middleware tests
|
|
*/
|
|
createNextMock: () => {
|
|
return async () => {
|
|
// Do nothing, simulate middleware completion
|
|
return;
|
|
};
|
|
}
|
|
};
|
|
|
|
// Setup environment before tests
|
|
beforeAll(() => {
|
|
// Don't let real logs through during tests
|
|
console.log = () => {};
|
|
console.info = () => {};
|
|
console.warn = () => {};
|
|
console.error = () => {};
|
|
console.debug = () => {};
|
|
|
|
// Override NODE_ENV for tests
|
|
process.env.NODE_ENV = 'test';
|
|
|
|
// Disable real logging during tests
|
|
process.env.LOG_LEVEL = 'silent';
|
|
process.env.LOG_CONSOLE = 'false';
|
|
process.env.LOG_FILE = 'false';
|
|
|
|
// Mock Loki config to prevent real connections
|
|
process.env.LOKI_HOST = '';
|
|
process.env.LOKI_URL = '';
|
|
});
|
|
|
|
// Clean up after each test
|
|
afterEach(() => {
|
|
// loggerTestHelpers.clearCapturedLogs(); // REMOVE this if it targeted a global array
|
|
});
|
|
|
|
// Restore everything after tests
|
|
afterAll(() => {
|
|
console.log = originalConsole.log;
|
|
console.info = originalConsole.info;
|
|
console.warn = originalConsole.warn;
|
|
console.error = originalConsole.error;
|
|
console.debug = originalConsole.debug;
|
|
});
|