@dbs-portal/core-api
Version:
HTTP client and API utilities for DBS Portal
287 lines • 8.28 kB
JavaScript
/**
* MSW testing utilities
*/
import { setupServer } from 'msw/node';
import { createMockAwareQueryClient } from '../integration/query-integration';
import { defaultHandlers } from '../handlers/default-handlers';
import { authHandlers } from '../handlers/auth-handlers';
/**
* Test server instance
*/
let testServer = null;
/**
* Create test server with handlers
*/
export function createTestServer(customHandlers = []) {
// Transform all handlers to ensure they use full URLs
const transformedDefaultHandlers = defaultHandlers.map(transformHandlerToFullUrl);
const transformedAuthHandlers = authHandlers.map(transformHandlerToFullUrl);
const transformedCustomHandlers = customHandlers.map(transformHandlerToFullUrl);
const allHandlers = [...transformedDefaultHandlers, ...transformedAuthHandlers, ...transformedCustomHandlers];
return setupServer(...allHandlers);
}
/**
* Transform handler to use full URL with localhost
* This ensures MSW intercepts the requests properly
*/
function transformHandlerToFullUrl(handler) {
// This is a simple implementation - in a real scenario you might need a more
// sophisticated approach depending on your MSW setup
// Since MSW v2 handlers are immutable, we need to recreate them
return handler;
}
/**
* Setup MSW for testing
*/
export function setupMSWTesting(customHandlers = []) {
if (testServer) {
testServer.close();
}
testServer = createTestServer(customHandlers);
// Start server
testServer.listen({
onUnhandledRequest: 'warn', // Warn on unhandled requests instead of failing
});
return {
server: testServer,
addHandlers: (...handlers) => testServer?.use(...handlers),
resetHandlers: () => testServer?.resetHandlers(),
restoreHandlers: () => testServer?.restoreHandlers(),
cleanup: () => {
testServer?.resetHandlers();
},
teardown: () => {
testServer?.close();
testServer = null;
},
};
}
/**
* Create test query client with MSW
*/
export async function createTestQueryClient(customHandlers = []) {
return createMockAwareQueryClient({
mocking: {
enabled: true,
mode: 'testing',
logging: false,
delay: 0, // No delay in tests
},
mockHandlers: customHandlers,
autoSetupMocks: false, // We'll handle setup manually in tests
defaultOptions: {
queries: {
retry: false,
staleTime: 0,
gcTime: 0,
},
mutations: {
retry: false,
},
},
});
}
/**
* Wait for all queries to settle
*/
export async function waitForQueries(queryClient, timeout = 5000) {
const start = Date.now();
while (Date.now() - start < timeout) {
const queries = queryClient.getQueryCache().getAll();
const isSettled = queries.every(query => query.state.status === 'success' ||
query.state.status === 'error' ||
query.state.status === 'pending');
if (isSettled) {
return;
}
await new Promise(resolve => setTimeout(resolve, 10));
}
throw new Error(`Queries did not settle within ${timeout}ms`);
}
/**
* Mock API response helpers
*/
export const mockHelpers = {
/**
* Create successful API response
*/
success(data, message = 'Success') {
return {
success: true,
data,
message,
meta: {
timestamp: new Date().toISOString(),
requestId: `test_${Date.now()}`,
version: '1.0.0',
},
};
},
/**
* Create error API response
*/
error(message, code = 'TEST_ERROR', _status = 400) {
return {
success: false,
message,
errors: [{ code, message }],
meta: {
timestamp: new Date().toISOString(),
requestId: `test_${Date.now()}`,
version: '1.0.0',
},
};
},
/**
* Create validation error response
*/
validationError(errors) {
return {
success: false,
message: 'Validation failed',
errors: errors.map(error => ({
code: 'VALIDATION_ERROR',
message: error.message,
field: error.field,
})),
meta: {
timestamp: new Date().toISOString(),
requestId: `test_${Date.now()}`,
version: '1.0.0',
},
};
},
/**
* Create paginated response
*/
paginated(items, page = 1, pageSize = 10, total) {
const totalItems = total ?? items.length;
const totalPages = Math.ceil(totalItems / pageSize);
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedItems = items.slice(startIndex, endIndex);
return this.success({
items: paginatedItems,
totalCount: totalItems,
pageSize,
currentPage: page,
totalPages,
hasNextPage: page < totalPages,
hasPreviousPage: page > 1,
});
},
};
/**
* Test data factories
*/
export const testFactories = {
/**
* Create test user
*/
user(overrides = {}) {
return {
id: `user_${Date.now()}`,
email: 'test@example.com',
username: 'testuser',
firstName: 'Test',
lastName: 'User',
isActive: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
...overrides,
};
},
/**
* Create test file
*/
file(overrides = {}) {
return {
id: `file_${Date.now()}`,
filename: 'test-file.txt',
originalName: 'test-file.txt',
mimeType: 'text/plain',
size: 1024,
url: '/uploads/test-file.txt',
uploadedAt: new Date().toISOString(),
...overrides,
};
},
/**
* Create test auth tokens
*/
authTokens(overrides = {}) {
return {
accessToken: 'mock_access_token',
refreshToken: 'mock_refresh_token',
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
tokenType: 'Bearer',
...overrides,
};
},
};
/**
* Test assertion helpers
*/
export const testAssertions = {
/**
* Assert API response structure
*/
isApiResponse(response) {
return (typeof response === 'object' &&
response !== null &&
typeof response.success === 'boolean' &&
'data' in response &&
'message' in response &&
'meta' in response);
},
/**
* Assert successful API response
*/
isSuccessResponse(response) {
return this.isApiResponse(response) && response.success === true;
},
/**
* Assert error API response
*/
isErrorResponse(response) {
return this.isApiResponse(response) && response.success === false && Array.isArray(response.errors);
},
/**
* Assert paginated response
*/
isPaginatedResponse(response) {
return (this.isSuccessResponse(response) &&
typeof response.data === 'object' &&
Array.isArray(response.data.items) &&
typeof response.data.totalCount === 'number' &&
typeof response.data.currentPage === 'number');
},
};
/**
* Test lifecycle helpers
*/
export const testLifecycle = {
/**
* Setup function for beforeAll/beforeEach
*/
setup(customHandlers = []) {
return setupMSWTesting(customHandlers);
},
/**
* Cleanup function for afterEach
*/
cleanup(mswInstance) {
mswInstance.cleanup();
},
/**
* Teardown function for afterAll
*/
teardown(mswInstance) {
mswInstance.teardown();
},
};
/**
* Export test server for direct access
*/
export { testServer };
//# sourceMappingURL=test-utils.js.map