@dbs-portal/tool-mock
Version:
API mocking toolkit using MSW for DBS Portal development workflows
483 lines (398 loc) • 11.2 kB
Markdown
# 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' },
}),
],
},
},
}
```