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
67 lines (62 loc) • 3.4 kB
JavaScript
const test = require('node:test'); //node test runner
const assert = require('node:assert/strict'); //strict assertions
const qtests = require('qtests'); //helper for stubbing
function withOpenAIToken(token) { //temporarily modify OPENAI_TOKEN
const orig = process.env.OPENAI_TOKEN; //remember current token
if (token === undefined) { delete process.env.OPENAI_TOKEN; } else { process.env.OPENAI_TOKEN = token; }
return () => { if (orig === undefined) { delete process.env.OPENAI_TOKEN; } else { process.env.OPENAI_TOKEN = orig; } };
}
function reloadQerrors() { //load qerrors fresh with current env
delete require.cache[require.resolve('../lib/qerrors')];
return require('../lib/qerrors');
}
test('clearAdviceCache empties cache', async () => {
const restoreToken = withOpenAIToken('cache-token'); //set token for analysis
const origLimit = process.env.QERRORS_CACHE_LIMIT; //save env limit
process.env.QERRORS_CACHE_LIMIT = '2'; //ensure caching enabled
const qerrors = reloadQerrors(); //reload module
const { analyzeError, axiosInstance } = qerrors; //extract functions
const restoreAxios = qtests.stubMethod(axiosInstance, 'post', async () => ({ data: { choices: [{ message: { content: { info: 'one' } } }] } }));
try {
const err = new Error('boom');
err.stack = 'stack';
err.uniqueErrorName = 'CACHECLR';
const first = await analyzeError(err, 'ctx');
assert.equal(first.info, 'one'); //initial call fetches advice
restoreAxios(); //restore first stub
let calledAgain = false;
const restoreAxios2 = qtests.stubMethod(axiosInstance, 'post', async () => { calledAgain = true; return { data: { choices: [{ message: { content: { info: 'two' } } }] } }; });
await analyzeError(err, 'ctx');
assert.equal(calledAgain, false); //should use cache
qerrors.clearAdviceCache(); //reset cache
const afterClear = await analyzeError(err, 'ctx');
restoreAxios2();
assert.equal(afterClear.info, 'two'); //axios called again
assert.equal(calledAgain, true); //verify second stub ran
} finally {
if (origLimit === undefined) { delete process.env.QERRORS_CACHE_LIMIT; } else { process.env.QERRORS_CACHE_LIMIT = origLimit; }
restoreToken();
reloadQerrors();
}
});
test('cache limit above threshold clamps and warns', async () => {
const orig = process.env.QERRORS_CACHE_LIMIT; //backup current env
process.env.QERRORS_CACHE_LIMIT = '5000'; //set exaggerated limit
const loggerPromise = require('../lib/logger'); //logger promise for stub
const log = await loggerPromise; //wait for logger instance
let warned = false; //track call state
const restoreWarn = qtests.stubMethod(log, 'warn', () => { warned = true; });
let limit; //will capture clamped limit
try {
const qerrors = reloadQerrors(); //reload module with large limit
await new Promise(r => setImmediate(r)); //allow async warn callback
limit = qerrors.getAdviceCacheLimit(); //fetch clamped limit value
} finally {
restoreWarn(); //restore logger warn
if (orig === undefined) { delete process.env.QERRORS_CACHE_LIMIT; } else { process.env.QERRORS_CACHE_LIMIT = orig; }
delete require.cache[require.resolve('../lib/qerrors')]; //reset state
require('../lib/qerrors'); //reload defaults
}
assert.equal(limit, 1000); //expect clamp to safe threshold
assert.equal(warned, true); //warning should fire
});