qgenutils
Version:
A security-first Node.js utility library providing authentication, HTTP operations, URL processing, validation, datetime formatting, and template rendering. Designed as a lightweight alternative to heavy npm packages with comprehensive error handling and
243 lines (199 loc) • 9.28 kB
JavaScript
// Integration tests validating error recovery across modules. These tests
// simulate multiple failure scenarios to ensure utilities cooperate under
// error conditions without crashing the process.
const utils = require('../../index');
describe('Error Handling Integration Tests', () => { // verifies utilities interact safely under failure
describe('Cascading Error Scenarios', () => { // simulates multiple failures at once
// verifies should handle multiple module failures gracefully
test('should handle multiple module failures gracefully', () => {
const mockRes = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis(),
render: jest.fn(),
send: jest.fn().mockReturnThis()
};
// Test invalid URL processing
const invalidUrl = null;
expect(utils.ensureProtocol(invalidUrl)).toBeNull(); // invalid URL returns null
expect(utils.normalizeUrlOrigin(invalidUrl)).toBeNull(); // normalization also null
expect(utils.parseUrlParts(invalidUrl)).toBeNull(); // parsing fails gracefully
// Test invalid date processing
const invalidDate = 'not-a-date';
expect(utils.formatDateTime(invalidDate)).toBe('N/A'); // invalid date yields N/A
// Test invalid duration calculation should throw
expect(() => utils.formatDuration(invalidDate)).toThrow(); // invalid duration throws
// Test validation with malformed object
expect(utils.requireFields(null, ['field'], mockRes)).toBe(false); // (reordered parameters to match obj, fields, res)
expect(mockRes.status).toHaveBeenCalledWith(500); // validation error results in server error
// Test auth with malformed request
expect(utils.checkPassportAuth(null)).toBe(false); // malformed req fails auth
});
// verifies should handle error propagation in API workflow
test('should handle error propagation in API workflow', () => {
const mockRes = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis()
};
// Simulate malformed request object
const malformedReq = {
headers: null, // This will cause issues
body: undefined, // This will cause validation issues
isAuthenticated: null // This will cause auth issues
};
// Each utility should handle the malformed data gracefully
expect(utils.checkPassportAuth(malformedReq)).toBe(false); // auth fails with bad object
// Header processing would have failed but that module was removed
expect(utils.requireFields(malformedReq.body, ['field'], mockRes)).toBe(false); // validation fails on body
});
});
describe('View Rendering Error Recovery', () => { // ensures rendering issues propagate correctly
// verifies should handle template rendering failures across multiple views
test('should handle template rendering failures across multiple views', () => {
const mockRes = {
render: jest.fn().mockImplementation(() => {
throw new Error('Template engine error');
}),
status: jest.fn().mockReturnThis(),
send: jest.fn().mockReturnThis()
};
const views = ['dashboard', 'profile', 'admin'];
views.forEach(view => {
utils.renderView(mockRes, view, `${view} Error`);
expect(mockRes.status).toHaveBeenCalledWith(500);
expect(mockRes.send).toHaveBeenCalledWith(
expect.stringContaining(`${view} Error`)
); // send error page for each view
});
// Should have attempted to render each view
expect(mockRes.render).toHaveBeenCalledTimes(3); // attempted rendering each view
// Should have sent error pages for each failure
expect(mockRes.send).toHaveBeenCalledTimes(3); // error page sent each time
});
// verifies should handle route registration with missing global app
test('should handle route registration with missing global app', () => {
const originalApp = global.app;
try {
global.app = undefined;
// Should not throw even with missing app
expect(() => {
utils.registerViewRoute('/test', 'test', 'Test Error');
}).not.toThrow(); // should not crash when app undefined
global.app = null;
expect(() => {
utils.registerViewRoute('/test2', 'test2', 'Test Error 2');
}).not.toThrow(); // handle null app as well
} finally {
global.app = originalApp;
}
});
});
describe('Authentication Error Scenarios', () => { // tests auth faults across modules
// verifies should handle passport strategy detection with broken global state
test('should handle passport strategy detection with broken global state', () => {
const originalPassport = global.passport;
try {
// Test with completely broken passport object
global.passport = {
get _strategies() {
throw new Error('Strategies access failed');
}
};
expect(utils.hasGithubStrategy()).toBe(false);
// Test with circular reference
const circular = {};
circular.self = circular;
global.passport = circular;
expect(utils.hasGithubStrategy()).toBe(false);
} finally {
global.passport = originalPassport;
}
});
// verifies should handle authentication with various request object states
test('should handle authentication with various request object states', () => {
const testCases = [
null,
undefined,
{},
{ isAuthenticated: null },
{ isAuthenticated: undefined },
{ isAuthenticated: 'not-a-function' },
{ isAuthenticated: () => { throw new Error('Auth error'); } }
];
testCases.forEach(testReq => {
expect(utils.checkPassportAuth(testReq)).toBe(false);
});
});
});
describe('URL Processing Error Recovery', () => { // validates robust URL handling
// verifies should handle malformed URLs throughout processing pipeline
test('should handle malformed URLs throughout processing pipeline', () => {
const malformedUrls = [
'',
null,
undefined,
123,
{},
'://invalid',
'ftp://unsupported-protocol.com'
];
malformedUrls.forEach(url => {
// ensureProtocol should return null for invalid inputs
const withProtocol = utils.ensureProtocol(url);
if (withProtocol === null) {
expect(utils.normalizeUrlOrigin(url)).toBeNull(); // invalid URL remains null
expect(utils.parseUrlParts(url)).toBeNull(); // parsing returns null
}
});
});
// verifies should handle URL processing with partial failures
test('should handle URL processing with partial failures', () => {
// Valid URL that might cause issues in some contexts
const edgeCaseUrls = [
'localhost',
'127.0.0.1',
'example.com:99999', // Very high port
'sub.domain.example.com/very/long/path/with/many/segments?lots=of&query=params&more=data'
];
edgeCaseUrls.forEach(url => {
const withProtocol = utils.ensureProtocol(url);
expect(withProtocol).toContain('https://'); // protocol enforced
const normalized = utils.normalizeUrlOrigin(url);
if (normalized) {
expect(normalized).toContain('https://'); // normalization adds protocol
} else {
expect(normalized).toBeNull(); // invalid normalization results null
}
const parsed = utils.parseUrlParts(url);
if (parsed) {
expect(parsed).toHaveProperty('baseUrl'); // object must contain baseUrl
expect(parsed).toHaveProperty('endpoint'); // object must contain endpoint
} else {
expect(parsed).toBeNull(); // invalid parsing results null
}
});
});
});
describe('Data Validation Error Recovery', () => { // confirms input validation fails gracefully
// verifies should handle validation with various malformed objects
test('should handle validation with various malformed objects', () => {
const mockRes = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis()
};
const testCases = [
[null, ['field'], 500], // Null object
[undefined, ['field'], 500], // Undefined object
['not-an-object', ['field'], 500], // String instead of object
[[], ['field'], 500], // Array instead of object
[42, ['field'], 500] // Number instead of object
];
testCases.forEach(([obj, fields, expectedStatus]) => {
mockRes.status.mockClear();
mockRes.json.mockClear();
const result = utils.requireFields(obj, fields, mockRes); // (reordered parameters to match obj, fields, res)
expect(result).toBe(false); // validation fails as expected
expect(mockRes.status).toHaveBeenCalledWith(expectedStatus); // status matches table
});
});
});
});