UNPKG

@dbs-portal/core-api

Version:

HTTP client and API utilities for DBS Portal

287 lines 8.28 kB
/** * 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