@rollercoaster-dev/rd-logger
Version:
A neurodivergent-friendly logger for Rollercoaster.dev projects
121 lines (120 loc) • 5.97 kB
JavaScript
/// <reference types="jest" />
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { runWithGenericContext } from '../generic';
import { Logger } from '../../core/logger.service';
import { getRequestStore } from '../../core/request-context';
// Mock chalk
jest.mock('chalk', () => {
const chalkMock = {
gray: (msg) => msg,
whiteBright: (msg) => msg,
blue: (msg) => msg,
green: (msg) => msg,
yellow: (msg) => msg,
red: (msg) => msg,
magenta: (msg) => msg,
dim: (msg) => msg,
cyan: (msg) => msg,
};
return Object.assign({ __esModule: true, default: chalkMock }, chalkMock);
});
// Mock Logger methods to simplify testing
jest.mock('../../core/logger.service');
describe('Generic Adapter Integration', () => {
let consoleSpy;
let mockLoggerInstance;
beforeEach(() => {
jest.clearAllMocks();
consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
// Create a fresh mocked logger for each test
mockLoggerInstance = new Logger();
// Mock the implementation of log methods
mockLoggerInstance.info = jest.fn();
mockLoggerInstance.error = jest.fn();
mockLoggerInstance.warn = jest.fn();
mockLoggerInstance.debug = jest.fn();
mockLoggerInstance.fatal = jest.fn();
});
afterEach(() => {
consoleSpy.mockRestore();
});
it('should run a function, log start/end, and provide context', () => __awaiter(void 0, void 0, void 0, function* () {
let internalRequestId;
const result = yield runWithGenericContext(() => __awaiter(void 0, void 0, void 0, function* () {
var _a;
internalRequestId = (_a = getRequestStore()) === null || _a === void 0 ? void 0 : _a.requestId;
expect(internalRequestId).toBeDefined();
// Simulate some work
yield new Promise((resolve) => setTimeout(resolve, 10));
return 'success';
}), { loggerInstance: mockLoggerInstance, contextName: 'TestTask' });
expect(result).toBe('success');
expect(internalRequestId).toBeDefined();
expect(mockLoggerInstance.info).toHaveBeenCalledTimes(2);
// Check start log
expect(mockLoggerInstance.info).toHaveBeenNthCalledWith(1, '▶ Starting TestTask', {
contextName: 'TestTask',
requestId: internalRequestId,
});
// Check end log
expect(mockLoggerInstance.info).toHaveBeenNthCalledWith(2, expect.stringContaining('◀ Finished TestTask'), expect.objectContaining({
contextName: 'TestTask',
requestId: internalRequestId,
duration: expect.any(String),
}));
// Check duration format in end log
const endLogArgs = mockLoggerInstance.info.mock.calls[1][1];
expect(endLogArgs.duration).toMatch(/\d+ms/); // e.g., '15ms'
}));
it('should log an error if the function throws', () => __awaiter(void 0, void 0, void 0, function* () {
let internalRequestId;
const testError = new Error('Something went wrong');
yield expect(runWithGenericContext(() => __awaiter(void 0, void 0, void 0, function* () {
var _a;
internalRequestId = (_a = getRequestStore()) === null || _a === void 0 ? void 0 : _a.requestId;
yield new Promise((resolve) => setTimeout(resolve, 5));
throw testError;
}), { loggerInstance: mockLoggerInstance, contextName: 'ErrorTask' })).rejects.toThrow('Something went wrong');
expect(mockLoggerInstance.info).toHaveBeenCalledTimes(1); // Only start log
expect(mockLoggerInstance.error).toHaveBeenCalledTimes(1);
// Check error log
expect(mockLoggerInstance.error).toHaveBeenCalledWith(expect.stringContaining('💥 Error in ErrorTask'), expect.objectContaining({
contextName: 'ErrorTask',
requestId: internalRequestId,
duration: expect.any(String),
error: testError, // Check that the original error object is passed
}));
// Check duration format in error log
const errorLogArgs = mockLoggerInstance.error.mock.calls[0][1];
expect(errorLogArgs.duration).toMatch(/\d+ms/);
}));
it('should use provided request ID', () => __awaiter(void 0, void 0, void 0, function* () {
const providedRequestId = 'custom-id-123';
yield runWithGenericContext(() => {
var _a;
expect((_a = getRequestStore()) === null || _a === void 0 ? void 0 : _a.requestId).toBe(providedRequestId);
}, {
loggerInstance: mockLoggerInstance,
requestId: providedRequestId,
logStartEnd: false, // Disable logs for simplicity
});
expect(mockLoggerInstance.info).not.toHaveBeenCalled();
expect(mockLoggerInstance.error).not.toHaveBeenCalled();
}));
it('should not log start/end if logStartEnd is false', () => __awaiter(void 0, void 0, void 0, function* () {
yield runWithGenericContext(() => 'done', {
loggerInstance: mockLoggerInstance,
logStartEnd: false,
});
expect(mockLoggerInstance.info).not.toHaveBeenCalled();
expect(mockLoggerInstance.error).not.toHaveBeenCalled();
}));
});