@dbs-portal/tool-mock
Version:
API mocking toolkit using MSW for DBS Portal development workflows
234 lines • 7.72 kB
JavaScript
/**
* 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