@dbs-portal/tool-mock
Version:
API mocking toolkit using MSW for DBS Portal development workflows
317 lines • 8.21 kB
JavaScript
/**
* Response builder for creating mock HTTP responses
*/
import { HttpResponse } from 'msw';
import { applyDelay } from '../utils/delay';
import { generateId } from './data-generators';
/**
* Implementation of mock response builder
*/
export class MockResponseBuilderImpl {
responseData = null;
statusCode = 200;
responseHeaders = {};
responseDelay;
responseError;
metadata = {};
constructor(options = {}) {
if (options.data !== undefined)
this.responseData = options.data;
if (options.status !== undefined)
this.statusCode = options.status;
if (options.headers)
this.responseHeaders = { ...options.headers };
if (options.delay !== undefined)
this.responseDelay = options.delay;
if (options.error)
this.responseError = options.error;
if (options.meta)
this.metadata = { ...options.meta };
}
/**
* Set response data
*/
data(data) {
this.responseData = data;
return this;
}
/**
* Set status code
*/
status(code) {
this.statusCode = code;
return this;
}
/**
* Set headers
*/
headers(headers) {
this.responseHeaders = { ...this.responseHeaders, ...headers };
return this;
}
/**
* Set delay
*/
delay(ms) {
this.responseDelay = ms;
return this;
}
/**
* Add error
*/
error(error) {
this.responseError = error;
return this;
}
/**
* Set metadata
*/
meta(metadata) {
this.metadata = { ...this.metadata, ...metadata };
return this;
}
/**
* Build the response
*/
build() {
const startTime = performance.now();
// Prepare response body
let responseBody;
if (this.responseError) {
responseBody = {
success: false,
errors: [this.responseError],
meta: {
timestamp: new Date().toISOString(),
requestId: generateId(),
version: '1.0.0',
...this.metadata,
},
};
}
else {
responseBody = {
success: true,
data: this.responseData,
meta: {
timestamp: new Date().toISOString(),
requestId: generateId(),
version: '1.0.0',
...this.metadata,
},
};
}
// Set default headers
const headers = {
'Content-Type': 'application/json',
'X-Mock-Response': 'true',
...this.responseHeaders,
};
// Add generation time to metadata if available
if (this.metadata.generatedAt) {
const endTime = performance.now();
headers['X-Generation-Time'] = `${(endTime - startTime).toFixed(2)}ms`;
}
return HttpResponse.json(responseBody, {
status: this.statusCode,
headers,
});
}
/**
* Build with async delay
*/
async buildAsync() {
if (this.responseDelay) {
await applyDelay(this.responseDelay);
}
return this.build();
}
}
/**
* Create a new response builder
*/
export function mockResponseBuilder(options = {}) {
return new MockResponseBuilderImpl(options);
}
/**
* Create a success response
*/
export function createSuccessResponse(data, options = {}) {
return mockResponseBuilder({
...options,
data,
success: true,
}).build();
}
/**
* Create an error response
*/
export function createErrorResponse(error, options = {}) {
const status = error.status || 400;
return mockResponseBuilder({
...options,
error,
success: false,
status,
}).build();
}
/**
* Create a loading response (with delay)
*/
export function createLoadingResponse(data, delay = [1000, 3000], options = {}) {
return mockResponseBuilder({
...options,
data,
delay,
});
}
/**
* Create a not found response
*/
export function createNotFoundResponse(message = 'Resource not found', options = {}) {
return createErrorResponse({
code: 'NOT_FOUND',
message,
}, { ...options, status: 404 });
}
/**
* Create an unauthorized response
*/
export function createUnauthorizedResponse(message = 'Unauthorized', options = {}) {
return createErrorResponse({
code: 'UNAUTHORIZED',
message,
}, { ...options, status: 401 });
}
/**
* Create a forbidden response
*/
export function createForbiddenResponse(message = 'Forbidden', options = {}) {
return createErrorResponse({
code: 'FORBIDDEN',
message,
}, { ...options, status: 403 });
}
/**
* Create a validation error response
*/
export function createValidationErrorResponse(errors, message = 'Validation failed', options = {}) {
return createErrorResponse({
code: 'VALIDATION_ERROR',
message,
details: errors,
}, { ...options, status: 400 });
}
/**
* Create a server error response
*/
export function createServerErrorResponse(message = 'Internal server error', options = {}) {
return createErrorResponse({
code: 'INTERNAL_SERVER_ERROR',
message,
}, { ...options, status: 500 });
}
/**
* Create a rate limit response
*/
export function createRateLimitResponse(message = 'Rate limit exceeded', retryAfter = 60, options = {}) {
return mockResponseBuilder({
...options,
error: {
code: 'RATE_LIMIT_EXCEEDED',
message,
},
headers: {
'Retry-After': retryAfter.toString(),
...options.headers,
},
status: 429,
}).build();
}
/**
* Create a maintenance response
*/
export function createMaintenanceResponse(message = 'Service temporarily unavailable', retryAfter = 3600, options = {}) {
return mockResponseBuilder({
...options,
error: {
code: 'SERVICE_UNAVAILABLE',
message,
},
headers: {
'Retry-After': retryAfter.toString(),
...options.headers,
},
status: 503,
}).build();
}
/**
* Create a response with custom status and message
*/
export function createCustomResponse(status, data, error, options = {}) {
const builder = mockResponseBuilder({
...options,
status,
});
if (error) {
builder.error(error);
}
else if (data !== undefined) {
builder.data(data);
}
return builder.build();
}
/**
* Create a response that simulates network conditions
*/
export function createNetworkResponse(data, networkCondition = 'fast', options = {}) {
let delay;
switch (networkCondition) {
case 'fast':
delay = [10, 50];
break;
case 'slow':
delay = [2000, 5000];
break;
case 'unstable':
delay = [100, 3000];
break;
default:
delay = [100, 300];
}
return mockResponseBuilder({
...options,
data,
delay,
});
}
/**
* Create a response with cache headers
*/
export function createCachedResponse(data, cacheControl = 'public, max-age=3600', options = {}) {
return mockResponseBuilder({
...options,
data,
headers: {
'Cache-Control': cacheControl,
'ETag': `"${Date.now()}"`,
...options.headers,
},
}).build();
}
/**
* Create a response with CORS headers
*/
export function createCorsResponse(data, origin = '*', options = {}) {
return mockResponseBuilder({
...options,
data,
headers: {
'Access-Control-Allow-Origin': origin,
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
...options.headers,
},
}).build();
}
//# sourceMappingURL=response-builder.js.map