qerrors
Version:
Intelligent error handling middleware with AI-powered analysis, environment validation, caching, and production-ready logging. Provides OpenAI-based error suggestions, queue management, retry mechanisms, and comprehensive configuration options for Node.js
162 lines (124 loc) • 6.99 kB
JavaScript
const test = require('node:test'); //node test runner
const assert = require('node:assert/strict'); //strict assertion helpers
const qerrors = require('../lib/qerrors'); //qerrors module with centralized handling
const logger = require('../lib/logger'); //logger for stubbing
const qtests = require('qtests'); //stubbing utilities
function createRes() { //construct minimal Express-like response mock
return {
headersSent: false, //simulates whether headers have been sent
statusCode: null, //captured status for assertions
payload: null, //body content returned by status/json/send
status(code) { this.statusCode = code; return this; }, //chainable setter
json(data) { this.payload = data; return this; }, //capture JSON payload
send(html) { this.payload = html; return this; } //capture HTML output
};
}
async function stubLogger(loggerFn) { //stub logger error method
const realLogger = await logger; //wait for logger instance
return qtests.stubMethod(realLogger, 'error', loggerFn); //stub logger.error with provided function
}
test('logErrorWithSeverity logs with severity context', async () => {
let criticalLogged = false; //track critical console output
let highLogged = false; //track high severity console output
const restoreLogger = await stubLogger(() => {}); //stub logger to prevent actual logging
const restoreConsole = qtests.stubMethod(console, 'error', (msg) => { //stub console.error
if (typeof msg === 'string' && msg.includes('CRITICAL ERROR')) criticalLogged = true;
if (typeof msg === 'string' && msg.includes('HIGH SEVERITY ERROR')) highLogged = true;
});
try {
const testError = new Error('Test error'); //create test error
const context = { userId: 123 }; //test context
// Test critical severity
await qerrors.logErrorWithSeverity(testError, 'testFunction', context, qerrors.errorTypes.ErrorSeverity.CRITICAL);
assert.ok(criticalLogged); //critical message should be logged to console
// Reset and test high severity
criticalLogged = false;
highLogged = false;
await qerrors.logErrorWithSeverity(testError, 'testFunction', context, qerrors.errorTypes.ErrorSeverity.HIGH);
assert.ok(highLogged); //high severity message should be logged to console
// Test medium severity (should not trigger console output)
criticalLogged = false;
highLogged = false;
await qerrors.logErrorWithSeverity(testError, 'testFunction', context, qerrors.errorTypes.ErrorSeverity.MEDIUM);
assert.ok(!criticalLogged); //medium severity should not trigger critical console output
assert.ok(!highLogged); //medium severity should not trigger high console output
} finally {
restoreLogger(); //restore logger stub
restoreConsole(); //restore console stub
}
});
test('handleControllerError sends standardized response', async () => {
const restoreLogger = await stubLogger(() => {}); //stub logger to prevent actual logging
// Don't stub logErrorWithSeverity, just verify the response behavior
try {
const res = createRes(); //mock response object
const testError = qerrors.errorTypes.createTypedError(
'Validation failed',
qerrors.errorTypes.ErrorTypes.VALIDATION,
'VALIDATION_ERROR'
); //create typed validation error
const context = { requestId: 'test-123' }; //test context
await qerrors.handleControllerError(res, testError, 'testController', context, 'Custom user message');
assert.equal(res.statusCode, 400); //validation error should return 400
assert.ok(res.payload); //response should have payload
assert.equal(res.payload.error.code, 'VALIDATION_ERROR'); //error code should match
assert.equal(res.payload.error.message, 'Custom user message'); //custom message should be used
assert.equal(res.payload.error.type, qerrors.errorTypes.ErrorTypes.VALIDATION); //type should match
} finally {
restoreLogger(); //restore logger stub
}
});
test('handleControllerError defaults error type and uses error message', async () => {
const restoreLogger = await stubLogger(() => {}); //stub logger
try {
const res = createRes(); //mock response object
const testError = new Error('Generic error'); //plain error without type
await qerrors.handleControllerError(res, testError, 'testController');
assert.equal(res.statusCode, 500); //should default to 500 for system error
assert.equal(res.payload.error.type, qerrors.errorTypes.ErrorTypes.SYSTEM); //should default to system error
assert.equal(res.payload.error.message, 'Generic error'); //should use error message when no custom message
} finally {
restoreLogger(); //restore logger stub
}
});
test('withErrorHandling executes operation and returns result on success', async () => {
const testResult = { success: true }; //mock successful result
const operation = async () => testResult; //mock successful operation
const result = await qerrors.withErrorHandling(operation, 'testOperation');
assert.deepEqual(result, testResult); //should return operation result
});
test('withErrorHandling logs error and returns fallback on failure', async () => {
const restoreLogger = await stubLogger(() => {}); //stub logger to prevent actual logging
try {
const testError = new Error('Operation failed'); //test error
testError.severity = qerrors.errorTypes.ErrorSeverity.HIGH; //set error severity
const operation = async () => { throw testError; }; //mock failing operation
const fallback = { fallback: true }; //fallback result
const result = await qerrors.withErrorHandling(operation, 'testOperation', {}, fallback);
assert.deepEqual(result, fallback); //should return fallback on error
} finally {
restoreLogger(); //restore logger stub
}
});
test('withErrorHandling defaults to medium severity when error has no severity', async () => {
const restoreLogger = await stubLogger(() => {}); //stub logger to prevent actual logging
try {
const testError = new Error('Operation failed'); //error without severity
const operation = async () => { throw testError; }; //mock failing operation
const result = await qerrors.withErrorHandling(operation, 'testOperation');
assert.equal(result, null); //should return null when no fallback provided
} finally {
restoreLogger(); //restore logger stub
}
});
test('withErrorHandling returns null fallback when no fallback provided', async () => {
const restoreLogger = await stubLogger(() => {}); //stub logger to prevent actual logging
try {
const testError = new Error('Operation failed'); //test error
const operation = async () => { throw testError; }; //mock failing operation
const result = await qerrors.withErrorHandling(operation, 'testOperation');
assert.equal(result, null); //should return null when no fallback provided
} finally {
restoreLogger(); //restore logger stub
}
});