@dbs-portal/core-api
Version:
HTTP client and API utilities for DBS Portal
183 lines • 6.28 kB
JavaScript
/**
* MSW simulation utilities for delays, errors, and network conditions
*/
import { createErrorResponse } from './response-builder';
/**
* Simulate network delay
*/
export async function simulateDelay(delay) {
const ms = Array.isArray(delay)
? Math.floor(Math.random() * (delay[1] - delay[0] + 1)) + delay[0]
: delay;
if (ms > 0) {
await new Promise(resolve => setTimeout(resolve, ms));
}
}
/**
* Simulate network error based on configuration
*/
export async function simulateError(request, config = {}) {
const { networkErrorRate = 0, serverErrorRate = 0, timeoutErrorRate = 0, customErrors = [], } = config;
// Check custom error scenarios first
for (const scenario of customErrors) {
const shouldTrigger = Math.random() < (scenario.probability || 1);
if (!shouldTrigger)
continue;
const matches = typeof scenario.pattern === 'string'
? request.url.pathname.includes(scenario.pattern)
: scenario.pattern.test(request.url.pathname);
if (matches && (!scenario.method || scenario.method === request.method)) {
const error = typeof scenario.error === 'function' ? scenario.error() : scenario.error;
return createErrorResponse(error);
}
}
// Network errors (connection issues)
if (Math.random() < networkErrorRate) {
return createErrorResponse({
code: 'NETWORK_ERROR',
message: 'Network connection failed',
}, { status: 0 }); // Status 0 indicates network error
}
// Timeout errors
if (Math.random() < timeoutErrorRate) {
return createErrorResponse({
code: 'TIMEOUT_ERROR',
message: 'Request timeout',
}, { status: 408 });
}
// Server errors (5xx)
if (Math.random() < serverErrorRate) {
const serverErrors = [
{ status: 500, code: 'INTERNAL_ERROR', message: 'Internal server error' },
{ status: 502, code: 'BAD_GATEWAY', message: 'Bad gateway' },
{ status: 503, code: 'SERVICE_UNAVAILABLE', message: 'Service unavailable' },
{ status: 504, code: 'GATEWAY_TIMEOUT', message: 'Gateway timeout' },
];
const error = serverErrors[Math.floor(Math.random() * serverErrors.length)];
return createErrorResponse({
code: error?.code || 'No code',
message: error?.message || 'No message',
}, { status: error?.status || 500 });
}
return null;
}
/**
* Simulate loading states with progressive responses
*/
export async function simulateProgressiveLoading(data, options = {}) {
const { steps = 3, stepDelay = 200, onProgress } = options;
for (let i = 0; i <= steps; i++) {
const progress = (i / steps) * 100;
if (onProgress) {
onProgress(progress);
}
if (i < steps) {
await simulateDelay(stepDelay);
}
}
return data;
}
/**
* Simulate file upload with progress
*/
export async function simulateFileUpload(file, options = {}) {
const { chunkSize = 1024 * 64, // 64KB chunks
chunkDelay = 100, onProgress, failureRate = 0, } = options;
// Simulate upload failure
if (Math.random() < failureRate) {
throw new Error('Upload failed');
}
const totalChunks = Math.ceil(file.size / chunkSize);
for (let chunk = 0; chunk < totalChunks; chunk++) {
const progress = ((chunk + 1) / totalChunks) * 100;
if (onProgress) {
onProgress(progress);
}
await simulateDelay(chunkDelay);
}
// Return mock upload result
return {
id: `file_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
url: `/uploads/${file.name}`,
metadata: {
originalName: file.name,
size: file.size,
type: file.type,
uploadedAt: new Date().toISOString(),
},
};
}
/**
* Simulate real-time data updates
*/
export function simulateRealTimeUpdates(initialData, updateFn, options = {}) {
const { interval = 1000, maxUpdates = Number.POSITIVE_INFINITY, onUpdate } = options;
let currentData = initialData;
let updateCount = 0;
const intervalId = setInterval(() => {
if (updateCount >= maxUpdates) {
clearInterval(intervalId);
return;
}
currentData = updateFn(currentData);
updateCount++;
if (onUpdate) {
onUpdate(currentData);
}
}, interval);
// Return cleanup function
return () => clearInterval(intervalId);
}
/**
* Simulate batch processing
*/
export async function simulateBatchProcessing(items, processor, options = {}) {
const { batchSize = 10, batchDelay = 500, onBatchComplete, onProgress } = options;
const results = [];
const batches = [];
// Split items into batches
for (let i = 0; i < items.length; i += batchSize) {
batches.push(items.slice(i, i + batchSize));
}
// Process each batch
for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
const batch = batches[batchIndex] ?? [];
const batchResults = await Promise.all(batch.map(item => Promise.resolve(processor(item))));
results.push(...batchResults);
if (onBatchComplete) {
onBatchComplete(batchResults, batchIndex);
}
if (onProgress) {
onProgress(results.length, items.length);
}
// Delay between batches (except for the last one)
if (batchIndex < batches.length - 1) {
await simulateDelay(batchDelay);
}
}
return results;
}
/**
* Simulate network conditions (slow 3G, fast 3G, etc.)
*/
export function getNetworkConditionDelay(condition) {
switch (condition) {
case 'slow-3g':
return [2000, 5000];
case 'fast-3g':
return [500, 1500];
case '4g':
return [100, 500];
case 'wifi':
return [50, 200];
default:
return [100, 300];
}
}
/**
* Simulate intermittent connectivity
*/
export function simulateIntermittentConnectivity(successRate = 0.9) {
return Math.random() < successRate;
}
//# sourceMappingURL=simulation.js.map