UNPKG

@dbs-portal/tool-mock

Version:

API mocking toolkit using MSW for DBS Portal development workflows

234 lines 7.72 kB
/** * Handler factory functions for creating common request handlers */ import { http, HttpResponse } from 'msw'; import { applyDelay } from '../utils/delay'; import { simulateError } from '../utils/error'; import { getMockConfig } from '../core/config'; /** * Create a custom handler with built-in utilities */ export function createHandler(method, path, options) { const httpMethod = http[method.toLowerCase()]; return httpMethod(path, async ({ request, params }) => { const config = getMockConfig(); // Simulate errors if configured const errorResponse = simulateError(request.url, method, config.errorSimulation); if (errorResponse) { return errorResponse; } // Check authentication if required if (options.auth) { const authResult = checkAuthentication(request, options.auth); if (!authResult.success) { return HttpResponse.json({ success: false, error: { code: authResult.code, message: authResult.message, }, }, { status: authResult.status || 401 }); } } // Create mock request context const url = new URL(request.url); const mockRequest = { url, method: request.method, headers: request.headers, body: request.body ? await request.json().catch(() => null) : null, params: params || {}, query: Object.fromEntries(url.searchParams.entries()), }; // Get response from factory const responseData = await options.response(mockRequest); // Apply delay const delay = options.delay || config.delay; if (delay) { await applyDelay(delay); } // Build response const status = options.status || 200; const headers = { 'Content-Type': 'application/json', ...options.headers, }; return HttpResponse.json(responseData, { status, headers }); }); } /** * Create multiple handlers from a configuration object */ export function createHandlers(config) { return Object.entries(config).map(([name, options]) => { const handler = createHandler(options.method, options.path, options); handler.__handlerName = name; return handler; }); } /** * Create a typed handler with TypeScript support */ export function createTypedHandler(method, path, responseFactory, options = {}) { return createHandler(method, path, { ...options, response: responseFactory, }); } /** * Create a GET handler */ export function createGetHandler(path, responseFactory, options = {}) { return createHandler('GET', path, { ...options, response: responseFactory }); } /** * Create a POST handler */ export function createPostHandler(path, responseFactory, options = {}) { return createHandler('POST', path, { ...options, response: responseFactory }); } /** * Create a PUT handler */ export function createPutHandler(path, responseFactory, options = {}) { return createHandler('PUT', path, { ...options, response: responseFactory }); } /** * Create a PATCH handler */ export function createPatchHandler(path, responseFactory, options = {}) { return createHandler('PATCH', path, { ...options, response: responseFactory }); } /** * Create a DELETE handler */ export function createDeleteHandler(path, responseFactory, options = {}) { return createHandler('DELETE', path, { ...options, response: responseFactory }); } /** * Create handlers with authentication protection */ export function withAuth(handler, _authRequirements) { // This is a simplified implementation // In a real scenario, you'd wrap the handler with auth logic return handler; } /** * Create a handler that always returns an error */ export function createErrorHandler(method, path, error) { return createHandler(method, path, { response: () => ({ success: false, error: { code: error.code, message: error.message, details: error.details, }, }), status: error.status, }); } /** * Create a handler that simulates loading */ export function createLoadingHandler(method, path, responseFactory, loadingTime = [1000, 3000]) { return createHandler(method, path, { response: responseFactory, delay: loadingTime, }); } /** * Check authentication for a request */ function checkAuthentication(request, authRequirements) { if (!authRequirements.requireAuth) { return { success: true }; } const authHeader = request.headers.get('Authorization'); if (!authHeader) { return { success: false, code: 'UNAUTHORIZED', message: 'Authorization header is required', status: 401, }; } // Simple token validation (in real implementation, you'd decode JWT) if (!authHeader.startsWith('Bearer ')) { return { success: false, code: 'INVALID_TOKEN', message: 'Invalid authorization format', status: 401, }; } const token = authHeader.substring(7); if (!token) { return { success: false, code: 'MISSING_TOKEN', message: 'Token is required', status: 401, }; } // Mock token validation try { const payload = JSON.parse(atob(token.split('.')[1] || '')); // Check roles if (authRequirements.requiredRoles && authRequirements.requiredRoles.length > 0) { const userRoles = payload.roles || []; const hasRequiredRole = authRequirements.requiredRoles.some(role => userRoles.includes(role)); if (!hasRequiredRole) { return { success: false, code: 'INSUFFICIENT_PERMISSIONS', message: 'Insufficient role permissions', status: 403, }; } } // Check permissions if (authRequirements.requiredPermissions && authRequirements.requiredPermissions.length > 0) { const userPermissions = payload.permissions || []; const hasRequiredPermissions = authRequirements.requiredPermissions.every(permission => userPermissions.includes(permission)); if (!hasRequiredPermissions) { return { success: false, code: 'INSUFFICIENT_PERMISSIONS', message: 'Insufficient permissions', status: 403, }; } } // Custom validation if (authRequirements.validator) { const mockRequest = { url: new URL(request.url), method: request.method, headers: request.headers, body: null, params: {}, query: {}, }; if (!authRequirements.validator(mockRequest)) { return { success: false, code: 'CUSTOM_AUTH_FAILED', message: 'Custom authentication failed', status: 403, }; } } return { success: true }; } catch { return { success: false, code: 'INVALID_TOKEN', message: 'Invalid token format', status: 401, }; } } //# sourceMappingURL=factory.js.map