UNPKG

@energica-city/shared-amplify-utils

Version:

Shared utilities for AWS Amplify projects

570 lines 91.4 kB
import { describe, it, expect, beforeEach, vi } from 'vitest'; import { MiddlewareChain, wrapLambdaHandler, wrapGraphQLResolver, } from './middlewareChain'; // Mock the logger vi.mock('../log', () => ({ logger: { debug: vi.fn(), error: vi.fn(), info: vi.fn(), warn: vi.fn(), }, })); // Mock the error library - we'll import the real implementations for most tests // but override specific behaviors when needed vi.mock('../error', async () => { const actual = await vi.importActual('../error'); return { ...actual, throwError: vi.fn().mockImplementation((message, context) => { const error = new Error(message); // Add the same properties that the real throwError adds error.__fromErrorLibrary = true; if (context) { Object.assign(error, context); } throw error; }), }; }); describe('Middleware-Error Library Integration', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('Error Library Error Detection', () => { it('should detect errors thrown by throwError function', async () => { const chain = new MiddlewareChain(); const middleware = vi.fn().mockImplementation(async (input, next) => { // Use the real throwError function const { throwError: realThrowError } = (await vi.importActual('../error')); realThrowError('Database connection failed', { operation: 'getUser', userId: '123', }); }); chain.use('database', middleware); try { await chain.execute({ userId: '123' }, async () => 'success'); expect.fail('Should have thrown an error'); } catch (error) { // Should preserve all properties from throwError expect(error.__fromErrorLibrary).toBe(true); expect(error.operation).toBe('getUser'); expect(error.userId).toBe('123'); expect(error.middlewareName).toBe('database'); expect(error.middlewareChain).toEqual(['database']); } }); it('should distinguish between error library errors and standard errors', async () => { const chain = new MiddlewareChain(); // Test with standard Error const standardError = new Error('Standard error'); const middleware1 = vi.fn().mockRejectedValue(standardError); // Test with error library error const errorLibraryMiddleware = vi.fn().mockImplementation(async () => { const { throwError: realThrowError } = (await vi.importActual('../error')); realThrowError('Error library error', { source: 'middleware' }); }); chain.use('standard', middleware1); try { await chain.execute('input', async () => 'success'); expect.fail('Should have thrown'); } catch (error) { expect(error.__fromErrorLibrary).toBeUndefined(); expect(error.source).toBeUndefined(); expect(error.middlewareName).toBe('standard'); } // Clear and test error library error chain.clear(); chain.use('errorLib', errorLibraryMiddleware); try { await chain.execute('input', async () => 'success'); expect.fail('Should have thrown'); } catch (error) { expect(error.__fromErrorLibrary).toBe(true); expect(error.source).toBe('middleware'); expect(error.middlewareName).toBe('errorLib'); } }); it('should preserve error context from throwError through middleware chain', async () => { const chain = new MiddlewareChain(); const middleware1 = vi.fn().mockImplementation(async (input, next) => { try { return await next(); } catch (error) { // Add middleware-specific context while preserving original throw Object.assign(error, { processedBy: 'middleware1' }); } }); const middleware2 = vi.fn().mockImplementation(async () => { const { throwError: realThrowError } = (await vi.importActual('../error')); realThrowError('Validation failed', { field: 'email', value: 'invalid-email', rule: 'email-format', }); }); chain.use('processor', middleware1); chain.use('validator', middleware2); try { await chain.execute({ email: 'invalid-email' }, async () => 'success'); expect.fail('Should have thrown'); } catch (error) { // Should have both original error context and middleware additions expect(error.field).toBe('email'); expect(error.value).toBe('invalid-email'); expect(error.rule).toBe('email-format'); expect(error.processedBy).toBe('middleware1'); expect(error.middlewareName).toBe('validator'); expect(error.middlewareChain).toEqual(['processor', 'validator']); } }); }); describe('Error Message Extraction Integration', () => { it('should use extractErrorMessage for consistent error logging', async () => { const { extractErrorMessage: realExtractErrorMessage } = (await vi.importActual('../error')); const chain = new MiddlewareChain(); const customError = { message: 'Custom error message', code: 'CUSTOM_ERROR', details: 'Additional details', }; const middleware = vi.fn().mockRejectedValue(customError); chain.use('custom', middleware); try { await chain.execute('input', async () => 'success'); expect.fail('Should have thrown'); } catch (error) { // The extractErrorMessage should work on the caught error const message = realExtractErrorMessage(error); expect(message).toBe('[object Object]'); // Because it's not a standard Error expect(error.originalError).toBe(customError); } }); it('should handle complex error objects with extractErrorMessage', async () => { const { extractErrorMessage: realExtractErrorMessage } = (await vi.importActual('../error')); const chain = new MiddlewareChain(); const complexError = { error: 'Nested error message', statusCode: 400, timestamp: new Date(), }; const middleware = vi.fn().mockRejectedValue(complexError); chain.use('complex', middleware); try { await chain.execute('input', async () => 'success'); expect.fail('Should have thrown'); } catch (error) { const message = realExtractErrorMessage(complexError); expect(message).toBe('Nested error message'); } }); }); describe('Error Context Creation Integration', () => { it('should use createErrorContext for structured error data', async () => { const { createErrorContext: realCreateErrorContext } = (await vi.importActual('../error')); const chain = new MiddlewareChain(); const middleware = vi.fn().mockImplementation(async (input) => { const errorContext = realCreateErrorContext({ operation: 'processPayment', amount: 100, currency: 'USD', userId: input.userId, timestamp: undefined, // Should be filtered out invalidField: null, // Should be kept }); const error = new Error('Payment processing failed'); Object.assign(error, errorContext); throw error; }); chain.use('payment', middleware); try { await chain.execute({ userId: 'user123' }, async () => 'success'); expect.fail('Should have thrown'); } catch (error) { expect(error.operation).toBe('processPayment'); expect(error.amount).toBe(100); expect(error.currency).toBe('USD'); expect(error.userId).toBe('user123'); expect(error.invalidField).toBe(null); expect('timestamp' in error).toBe(false); // undefined values filtered out expect(error.middlewareName).toBe('payment'); } }); it('should merge error contexts from multiple sources', async () => { const { createErrorContext: realCreateErrorContext, throwError: realThrowError, } = (await vi.importActual('../error')); const chain = new MiddlewareChain(); const middleware1 = vi.fn().mockImplementation(async (input, next) => { try { return await next(); } catch (error) { const additionalContext = realCreateErrorContext({ middleware1Processing: true, timestamp: Date.now(), inputData: input, }); throw Object.assign(error, additionalContext); } }); const middleware2 = vi.fn().mockImplementation(async () => { realThrowError('Core business logic failed', realCreateErrorContext({ businessRule: 'inventory-check', requiredQuantity: 5, availableQuantity: 2, shortfall: 3, })); }); chain.use('processor', middleware1); chain.use('business', middleware2); try { await chain.execute({ productId: 'prod123' }, async () => 'success'); expect.fail('Should have thrown'); } catch (error) { // Should have context from both throwError and middleware expect(error.businessRule).toBe('inventory-check'); expect(error.requiredQuantity).toBe(5); expect(error.availableQuantity).toBe(2); expect(error.shortfall).toBe(3); expect(error.middleware1Processing).toBe(true); expect(error.inputData).toEqual({ productId: 'prod123' }); expect(error.middlewareName).toBe('business'); expect(error.middlewareChain).toEqual(['processor', 'business']); } }); }); describe('Lambda Handler Integration', () => { it('should preserve error library context through lambda wrapper', async () => { const { throwError: realThrowError } = (await vi.importActual('../error')); const chain = MiddlewareChain.createLambdaChain(); const authMiddleware = vi.fn().mockImplementation(async (input, next) => { if (!input.event.userId) { realThrowError('Authentication required', { operation: 'checkAuth', provided: Object.keys(input.event), required: ['userId'], }); } return next(); }); chain.use('auth', authMiddleware); const handler = vi.fn().mockResolvedValue({ statusCode: 200 }); const wrappedHandler = wrapLambdaHandler(chain, handler); const event = { userId: '' }; // Empty userId should trigger error const context = { functionName: 'testFunction' }; try { await wrappedHandler(event, context); expect.fail('Should have thrown'); } catch (error) { expect(error.__fromErrorLibrary).toBe(true); expect(error.operation).toBe('checkAuth'); expect(error.provided).toEqual(['userId']); expect(error.required).toEqual(['userId']); expect(error.middlewareName).toBe('auth'); } }); it('should handle lambda-specific error context creation', async () => { const { createErrorContext: realCreateErrorContext } = (await vi.importActual('../error')); const chain = MiddlewareChain.createLambdaChain(); const middleware = vi.fn().mockImplementation(async (input) => { const lambdaContext = realCreateErrorContext({ requestId: input.context.awsRequestId, functionName: input.context.functionName, remainingTime: input.context.getRemainingTimeInMillis?.(), eventType: input.event.httpMethod || 'unknown', path: input.event.path, stage: input.event.requestContext?.stage, }); const error = new Error('Lambda execution failed'); Object.assign(error, lambdaContext); throw error; }); chain.use('lambda-context', middleware); const handler = vi.fn(); const wrappedHandler = wrapLambdaHandler(chain, handler); const event = { httpMethod: 'POST', path: '/api/users', requestContext: { stage: 'prod' }, }; const context = { awsRequestId: 'req-123', functionName: 'userService', getRemainingTimeInMillis: () => 5000, }; try { await wrappedHandler(event, context); expect.fail('Should have thrown'); } catch (error) { expect(error.requestId).toBe('req-123'); expect(error.functionName).toBe('userService'); expect(error.remainingTime).toBe(5000); expect(error.eventType).toBe('POST'); expect(error.path).toBe('/api/users'); expect(error.stage).toBe('prod'); expect(error.middlewareName).toBe('lambda-context'); } }); }); describe('GraphQL Resolver Integration', () => { it('should preserve error library context through GraphQL wrapper', async () => { const { throwError: realThrowError } = (await vi.importActual('../error')); const chain = MiddlewareChain.createGraphQLChain(); const validationMiddleware = vi .fn() .mockImplementation(async (input, next) => { if (!input.args.id || input.args.id.length < 3) { realThrowError('Invalid arguments provided', { operation: 'validateArgs', field: 'id', provided: input.args.id, rule: 'minLength:3', resolver: input.info.fieldName, parentType: input.info.parentTypeName, }); } return next(); }); chain.use('validation', validationMiddleware); const resolver = vi.fn().mockResolvedValue({ id: 'valid', name: 'Test' }); const wrappedResolver = wrapGraphQLResolver(chain, resolver); const source = {}; const args = { id: 'ab' }; // Too short const context = { userId: 'user123' }; const info = { fieldName: 'getUser', parentTypeName: 'Query', }; try { await wrappedResolver(source, args, context, info); expect.fail('Should have thrown'); } catch (error) { expect(error.__fromErrorLibrary).toBe(true); expect(error.operation).toBe('validateArgs'); expect(error.field).toBe('id'); expect(error.provided).toBe('ab'); expect(error.rule).toBe('minLength:3'); expect(error.resolver).toBe('getUser'); expect(error.parentType).toBe('Query'); expect(error.middlewareName).toBe('validation'); } }); it('should handle complex GraphQL error context', async () => { const { createErrorContext: realCreateErrorContext, throwError: realThrowError, } = (await vi.importActual('../error')); const chain = MiddlewareChain.createGraphQLChain(); const businessLogicMiddleware = vi .fn() .mockImplementation(async (input) => { const graphqlContext = realCreateErrorContext({ resolver: input.info.fieldName, parentType: input.info.parentTypeName, arguments: input.args, userContext: input.context.user, requestId: input.context.requestId, variables: input.info.variables, operationName: input.info.operation?.name?.value, }); realThrowError('Business logic validation failed', graphqlContext); }); chain.use('business-logic', businessLogicMiddleware); const resolver = vi.fn(); const wrappedResolver = wrapGraphQLResolver(chain, resolver); const source = {}; const args = { userId: 'user123', includeProfile: true }; const context = { user: { id: 'user123', role: 'admin' }, requestId: 'gql-req-456', }; const info = { fieldName: 'getUserProfile', parentTypeName: 'Query', variables: { includeProfile: true }, operation: { name: { value: 'GetUserProfile' } }, }; try { await wrappedResolver(source, args, context, info); expect.fail('Should have thrown'); } catch (error) { expect(error.resolver).toBe('getUserProfile'); expect(error.parentType).toBe('Query'); expect(error.arguments).toEqual({ userId: 'user123', includeProfile: true, }); expect(error.userContext).toEqual({ id: 'user123', role: 'admin' }); expect(error.requestId).toBe('gql-req-456'); expect(error.variables).toEqual({ includeProfile: true }); expect(error.operationName).toBe('GetUserProfile'); expect(error.middlewareName).toBe('business-logic'); } }); }); describe('Error Chain Propagation', () => { it('should propagate error library errors through multiple middleware layers', async () => { const { throwError: realThrowError } = (await vi.importActual('../error')); const chain = new MiddlewareChain(); const loggerMiddleware = vi .fn() .mockImplementation(async (input, next) => { try { return await next(); } catch (error) { // Add logging context but preserve original error const logContext = { loggedAt: new Date().toISOString(), logLevel: 'error', }; throw Object.assign(error, logContext); } }); const authMiddleware = vi.fn().mockImplementation(async (input, next) => { try { return await next(); } catch (error) { // Add auth context const authContext = { authState: 'failed', attemptedUser: input.userId, }; throw Object.assign(error, authContext); } }); const dataMiddleware = vi.fn().mockImplementation(async () => { realThrowError('Database connection timeout', { database: 'users', timeout: 5000, query: 'SELECT * FROM users WHERE id = ?', retryCount: 3, }); }); chain .use('logger', loggerMiddleware) .use('auth', authMiddleware) .use('data', dataMiddleware); try { await chain.execute({ userId: 'user123' }, async () => 'success'); expect.fail('Should have thrown'); } catch (error) { // Should have all contexts combined expect(error.__fromErrorLibrary).toBe(true); expect(error.database).toBe('users'); expect(error.timeout).toBe(5000); expect(error.query).toBe('SELECT * FROM users WHERE id = ?'); expect(error.retryCount).toBe(3); expect(error.authState).toBe('failed'); expect(error.attemptedUser).toBe('user123'); expect(error.logLevel).toBe('error'); expect(typeof error.loggedAt).toBe('string'); expect(error.middlewareName).toBe('data'); expect(error.middlewareChain).toEqual(['logger', 'auth', 'data']); } }); it('should handle error transformation while preserving error library markers', async () => { const { throwError: realThrowError } = (await vi.importActual('../error')); const chain = new MiddlewareChain(); const transformerMiddleware = vi .fn() .mockImplementation(async (input, next) => { try { return await next(); } catch (error) { const errorObj = error; // Transform error but preserve error library properties if (errorObj.__fromErrorLibrary) { const transformedError = new Error(`Transformed: ${errorObj.message}`); // Copy all enumerable properties Object.assign(transformedError, errorObj); // Copy all non-enumerable properties Object.getOwnPropertyNames(errorObj).forEach(prop => { if (prop !== 'message') { // Don't overwrite the new message const descriptor = Object.getOwnPropertyDescriptor(errorObj, prop); if (descriptor && !transformedError.hasOwnProperty(prop)) { Object.defineProperty(transformedError, prop, descriptor); } } }); // Update message while preserving other properties transformedError.message = `Transformed: ${errorObj.message}`; transformedError.transformedBy = 'transformerMiddleware'; throw transformedError; } throw error; } }); const sourceMiddleware = vi.fn().mockImplementation(async () => { realThrowError('Original error', { source: 'sourceMiddleware', errorCode: 'ERR_001', }); }); chain .use('transformer', transformerMiddleware) .use('source', sourceMiddleware); try { await chain.execute('input', async () => 'success'); expect.fail('Should have thrown'); } catch (error) { expect(error.message).toBe('Transformed: Original error'); expect(error.__fromErrorLibrary).toBe(true); expect(error.source).toBe('sourceMiddleware'); expect(error.errorCode).toBe('ERR_001'); expect(error.transformedBy).toBe('transformerMiddleware'); expect(error.middlewareName).toBe('source'); expect(error.middlewareChain).toEqual(['transformer', 'source']); } }); }); describe('Performance and Memory Integration', () => { it('should handle error context creation efficiently with large context objects', async () => { const { createErrorContext: realCreateErrorContext } = (await vi.importActual('../error')); const chain = new MiddlewareChain(); const middleware = vi.fn().mockImplementation(async () => { // Create large context object with many undefined values const largeContext = {}; for (let i = 0; i < 1000; i++) { largeContext[`field${i}`] = i % 3 === 0 ? undefined : `value${i}`; } const filteredContext = realCreateErrorContext(largeContext); const error = new Error('Large context error'); Object.assign(error, filteredContext); throw error; }); chain.use('large-context', middleware); try { await chain.execute('input', async () => 'success'); expect.fail('Should have thrown'); } catch (error) { // Should have filtered out undefined values const errorKeys = Object.keys(error).filter(key => key.startsWith('field') && error[key] !== undefined); // Should have roughly 2/3 of the fields (those that weren't undefined) expect(errorKeys.length).toBeGreaterThan(600); expect(errorKeys.length).toBeLessThan(700); // Verify undefined values were filtered for (const key of errorKeys) { expect(error[key]).not.toBe(undefined); } } }); }); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZUNoYWluLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9taWRkbGV3YXJlL21pZGRsZXdhcmVDaGFpbi50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzlELE9BQU8sRUFDTCxlQUFlLEVBQ2YsaUJBQWlCLEVBQ2pCLG1CQUFtQixHQUVwQixNQUFNLG1CQUFtQixDQUFDO0FBSTNCLGtCQUFrQjtBQUNsQixFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZCLE1BQU0sRUFBRTtRQUNOLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ2QsS0FBSyxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDZCxJQUFJLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNiLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO0tBQ2Q7Q0FDRixDQUFDLENBQUMsQ0FBQztBQUVKLGdGQUFnRjtBQUNoRiw4Q0FBOEM7QUFDOUMsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDN0IsTUFBTSxNQUFNLEdBQUcsTUFBTSxFQUFFLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ2pELE9BQU87UUFDTCxHQUFHLE1BQU07UUFDVCxVQUFVLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLGtCQUFrQixDQUFDLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFO1lBQzFELE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ2pDLHdEQUF3RDtZQUN2RCxLQUFpRCxDQUFDLGtCQUFrQjtnQkFDbkUsSUFBSSxDQUFDO1lBQ1AsSUFBSSxP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