UNPKG

@dbs-portal/tool-mock

Version:

API mocking toolkit using MSW for DBS Portal development workflows

483 lines (398 loc) 11.2 kB
# Integration Guide - @dbs-portal/tool-mock This guide covers integration patterns with core DBS Portal packages and common development workflows. ## Core Package Integration ### @dbs-portal/core-api Integration The mock tool seamlessly integrates with the existing API client infrastructure. #### Basic Integration ```typescript import { createMockAwareApiClient } from '@dbs-portal/tool-mock' import { ApiClient } from '@dbs-portal/core-api' // Create API client with MSW support const apiClient = await createMockAwareApiClient({ baseURL: process.env.VITE_API_BASE_URL || '/api', enableMocking: process.env.NODE_ENV === 'development', mockHandlers: [ // Your custom handlers ], }) // Use with existing patterns export const userService = { getUsers: () => apiClient.get('/users'), getUser: (id: string) => apiClient.get(`/users/${id}`), createUser: (data: CreateUserDto) => apiClient.post('/users', data), updateUser: (id: string, data: UpdateUserDto) => apiClient.put(`/users/${id}`, data), deleteUser: (id: string) => apiClient.delete(`/users/${id}`), } ``` #### React Query Integration ```typescript import { useQuery, useMutation } from '@tanstack/react-query' import { userService } from './api' // Existing query hooks work seamlessly with mocked data export const useUsers = () => { return useQuery({ queryKey: ['users'], queryFn: userService.getUsers, }) } export const useCreateUser = () => { return useMutation({ mutationFn: userService.createUser, onSuccess: () => { // Invalidate and refetch queryClient.invalidateQueries({ queryKey: ['users'] }) }, }) } ``` #### Existing HTTP Client Wrapper ```typescript import { HttpClient } from '@dbs-portal/core-api' import { setupMocks, createCrudHandlers } from '@dbs-portal/tool-mock' // Setup MSW before creating HTTP client await setupMocks({ handlers: [ ...createCrudHandlers({ basePath: '/api/users', dataFactory: userFactory, }), ], }) // Existing HTTP client works with mocked endpoints const httpClient = new HttpClient({ baseURL: '/api', timeout: 30000, }) // All requests are automatically intercepted by MSW const users = await httpClient.get('/users') ``` ### @dbs-portal/core-auth Integration Mock authentication and authorization seamlessly with existing auth patterns. #### Authentication Mocking ```typescript import { createAuthHandlers, createMockAuthManager } from '@dbs-portal/tool-mock' import { AuthManager } from '@dbs-portal/core-auth' // Create mock auth handlers const authHandlers = createAuthHandlers('/api/auth', { users: [ { id: '1', email: 'admin@example.com', password: 'password', roles: ['admin'], permissions: ['users:read', 'users:write', 'users:delete'], }, { id: '2', email: 'user@example.com', password: 'password', roles: ['user'], permissions: ['users:read'], }, ], tokenExpiry: '1h', refreshTokenExpiry: '7d', }) // Setup MSW with auth handlers await setupMocks({ handlers: [...authHandlers], }) // Create auth manager (works with mocked endpoints) const authManager = new AuthManager({ apiClient: httpClient, endpoints: { login: '/api/auth/login', logout: '/api/auth/logout', refresh: '/api/auth/refresh', user: '/api/auth/me', }, }) ``` #### Permission-Based Mocking ```typescript import { withMockAuth } from '@dbs-portal/tool-mock' // Protect handlers with authentication requirements const protectedUserHandlers = withMockAuth( createCrudHandlers({ basePath: '/api/users', dataFactory: userFactory, }), { requireAuth: true, requiredRoles: ['admin'], requiredPermissions: ['users:read'], } ) // Handlers will return 401/403 for unauthorized requests ``` #### Zustand Auth Store Integration ```typescript import { useAuthStore } from '@dbs-portal/core-auth' import { mockAuthUser } from '@dbs-portal/tool-mock' // Mock authenticated user in Zustand store const mockUser = mockAuthUser({ id: '1', email: 'admin@example.com', roles: ['admin'], permissions: ['users:read', 'users:write'], }) // Set mock user in auth store useAuthStore.getState().setUser(mockUser) useAuthStore.getState().setAuthenticated(true) ``` ## Business Module Integration ### Module-Specific Mocking ```typescript // packages/modules/user-management/src/mocks/index.ts import { createCrudHandlers, createDataFactory } from '@dbs-portal/tool-mock' import type { User, CreateUserDto, UpdateUserDto } from '../types' // Module-specific data factory export const userFactory = createDataFactory<User>((overrides = {}) => ({ id: generateId(), email: 'user@example.com', firstName: 'John', lastName: 'Doe', department: 'Engineering', role: 'Developer', isActive: true, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), ...overrides, })) // Module-specific handlers export const userManagementHandlers = [ ...createCrudHandlers({ basePath: '/api/user-management/users', dataFactory: userFactory, initialData: [ userFactory({ id: '1', email: 'admin@example.com', role: 'Admin' }), userFactory({ id: '2', email: 'manager@example.com', role: 'Manager' }), ], pagination: { defaultPageSize: 20, maxPageSize: 100 }, }), // Custom endpoints http.get('/api/user-management/departments', () => { return HttpResponse.json({ success: true, data: ['Engineering', 'Marketing', 'Sales', 'HR'], }) }), http.post('/api/user-management/users/:id/activate', ({ params }) => { return HttpResponse.json({ success: true, data: userFactory({ id: params.id as string, isActive: true }), }) }), ] ``` ### Module Registration ```typescript // packages/modules/user-management/src/index.ts import { userManagementHandlers } from './mocks' export const UserManagementModule = { name: 'user-management', routes: () => import('./routes'), components: () => import('./components'), services: () => import('./services'), // Export mock handlers for development mockHandlers: userManagementHandlers, } ``` ### Portal Integration ```typescript // src/main.tsx import { setupMocks } from '@dbs-portal/tool-mock' import { UserManagementModule } from '@dbs-portal/module-user-management' import { FileManagementModule } from '@dbs-portal/module-file-management' // Collect all module mock handlers const moduleHandlers = [ ...UserManagementModule.mockHandlers, ...FileManagementModule.mockHandlers, ] // Setup MSW with all handlers await setupMocks({ handlers: moduleHandlers, }) // Start React app ReactDOM.createRoot(document.getElementById('root')!).render(<App />) ``` ## Development Workflows ### Environment-Based Configuration ```typescript // vite.config.ts import { defineConfig } from 'vite' import { mswPlugin } from '@dbs-portal/tool-mock' export default defineConfig({ plugins: [ mswPlugin({ enabled: process.env.NODE_ENV === 'development', mode: 'development', publicDir: 'public', verbose: true, }), ], define: { __MSW_ENABLED__: JSON.stringify(process.env.VITE_ENABLE_MOCKING === 'true'), }, }) ``` ### Environment Variables ```bash # .env.development VITE_ENABLE_MOCKING=true VITE_MOCK_MODE=development VITE_MOCK_DELAY=300 VITE_MOCK_LOGGING=true # .env.test VITE_ENABLE_MOCKING=true VITE_MOCK_MODE=testing VITE_MOCK_DELAY=0 VITE_MOCK_LOGGING=false # .env.production VITE_ENABLE_MOCKING=false ``` ### Hot Reloading ```typescript // Development hot reloading for mock handlers if (import.meta.hot) { import.meta.hot.accept('./mocks/handlers', (newModule) => { if (newModule) { // Update MSW handlers without restart resetHandlers() addHandlers(...newModule.handlers) } }) } ``` ## Testing Integration ### Vitest Setup ```typescript // vitest.setup.ts import { setupMSWTesting } from '@dbs-portal/tool-mock' import { userManagementHandlers } from './src/mocks' const msw = setupMSWTesting([ ...userManagementHandlers, ]) beforeAll(() => msw.listen()) afterEach(() => msw.resetHandlers()) afterAll(() => msw.close()) ``` ### Component Testing ```typescript import { render, screen } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { mockApiCall } from '@dbs-portal/tool-mock' import { UserList } from './UserList' test('should display users', async () => { // Mock API response mockApiCall('GET', '/api/users', { success: true, data: [ { id: '1', name: 'John Doe', email: 'john@example.com' }, { id: '2', name: 'Jane Smith', email: 'jane@example.com' }, ], }) const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }) render( <QueryClientProvider client={queryClient}> <UserList /> </QueryClientProvider> ) expect(await screen.findByText('John Doe')).toBeInTheDocument() expect(await screen.findByText('Jane Smith')).toBeInTheDocument() }) ``` ## Storybook Integration ### Storybook Configuration ```typescript // .storybook/main.ts import type { StorybookConfig } from '@storybook/react-vite' const config: StorybookConfig = { stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: ['@storybook/addon-essentials'], framework: { name: '@storybook/react-vite', options: {}, }, async viteFinal(config) { // Enable MSW in Storybook config.define = { ...config.define, __MSW_ENABLED__: JSON.stringify(true), } return config }, } export default config ``` ### Story Setup ```typescript // .storybook/preview.ts import { setupMocks } from '@dbs-portal/tool-mock' import { userManagementHandlers } from '../src/mocks' // Setup MSW for all stories setupMocks({ handlers: userManagementHandlers, config: { mode: 'storybook', logging: false, delay: 100, }, }) ``` ### Component Stories ```typescript // UserList.stories.tsx import type { Meta, StoryObj } from '@storybook/react' import { mockApiCall } from '@dbs-portal/tool-mock' import { UserList } from './UserList' const meta: Meta<typeof UserList> = { title: 'Components/UserList', component: UserList, } export default meta type Story = StoryObj<typeof UserList> export const Default: Story = { parameters: { msw: { handlers: [ mockApiCall('GET', '/api/users', { success: true, data: [ { id: '1', name: 'John Doe', email: 'john@example.com' }, { id: '2', name: 'Jane Smith', email: 'jane@example.com' }, ], }), ], }, }, } export const Loading: Story = { parameters: { msw: { handlers: [ mockApiCall('GET', '/api/users', { delay: 2000, // Simulate slow response success: true, data: [], }), ], }, }, } export const Error: Story = { parameters: { msw: { handlers: [ mockApiCall('GET', '/api/users', { status: 500, success: false, error: { message: 'Internal server error' }, }), ], }, }, } ```