Local changes: Updated model training, removed debug instrumentation, and configuration improvements
This commit is contained in:
270
docs/developer/frontend_testing.md
Normal file
270
docs/developer/frontend_testing.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# Frontend Testing Guide
|
||||
|
||||
This guide explains how to test the React frontend components and pages.
|
||||
|
||||
## Testing Setup
|
||||
|
||||
The frontend uses Vitest (recommended) or Jest for testing React components. To set up testing:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event vitest @vitest/ui jsdom
|
||||
```
|
||||
|
||||
Add to `package.json`:
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": "vitest",
|
||||
"test:ui": "vitest --ui",
|
||||
"test:coverage": "vitest --coverage"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Component Testing
|
||||
|
||||
Test individual components in isolation:
|
||||
|
||||
```typescript
|
||||
// frontend/src/components/__tests__/StatusIndicator.test.tsx
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import StatusIndicator from '../StatusIndicator';
|
||||
|
||||
describe('StatusIndicator', () => {
|
||||
it('renders connected status correctly', () => {
|
||||
render(<StatusIndicator status="connected" label="WebSocket" />);
|
||||
expect(screen.getByText('WebSocket')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows correct color for error status', () => {
|
||||
render(<StatusIndicator status="error" label="Error" />);
|
||||
const chip = screen.getByText('Error');
|
||||
expect(chip).toHaveClass('MuiChip-colorError');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Page Testing
|
||||
|
||||
Test complete page workflows:
|
||||
|
||||
```typescript
|
||||
// frontend/src/pages/__tests__/StrategiesPage.test.tsx
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import StrategiesPage from '../StrategiesPage';
|
||||
import * as strategiesApi from '../../api/strategies';
|
||||
|
||||
vi.mock('../../api/strategies');
|
||||
|
||||
describe('StrategiesPage', () => {
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: { queries: { retry: false } }
|
||||
});
|
||||
|
||||
it('displays list of strategies', async () => {
|
||||
const mockStrategies = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Test Strategy',
|
||||
strategy_type: 'rsi',
|
||||
enabled: false,
|
||||
paper_trading: true,
|
||||
// ... other fields
|
||||
}
|
||||
];
|
||||
|
||||
vi.mocked(strategiesApi.strategiesApi.listStrategies).mockResolvedValue(mockStrategies);
|
||||
|
||||
render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<StrategiesPage />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Test Strategy')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows create strategy button', () => {
|
||||
render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<StrategiesPage />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
expect(screen.getByText('Create Strategy')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### API Integration Testing
|
||||
|
||||
Test API client functions:
|
||||
|
||||
```typescript
|
||||
// frontend/src/api/__tests__/strategies.test.ts
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { strategiesApi } from '../strategies';
|
||||
import { apiClient } from '../client';
|
||||
|
||||
vi.mock('../client');
|
||||
|
||||
describe('strategiesApi', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('lists strategies', async () => {
|
||||
const mockStrategies = [{ id: 1, name: 'Test' }];
|
||||
vi.mocked(apiClient.get).mockResolvedValue({ data: mockStrategies });
|
||||
|
||||
const result = await strategiesApi.listStrategies();
|
||||
expect(result).toEqual(mockStrategies);
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/api/strategies/');
|
||||
});
|
||||
|
||||
it('creates strategy', async () => {
|
||||
const newStrategy = { name: 'New', strategy_type: 'rsi' };
|
||||
const created = { id: 1, ...newStrategy };
|
||||
vi.mocked(apiClient.post).mockResolvedValue({ data: created });
|
||||
|
||||
const result = await strategiesApi.createStrategy(newStrategy);
|
||||
expect(result).toEqual(created);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Hook Testing
|
||||
|
||||
Test custom React hooks:
|
||||
|
||||
```typescript
|
||||
// frontend/src/hooks/__tests__/useWebSocket.test.ts
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { useWebSocket } from '../useWebSocket';
|
||||
|
||||
// Mock WebSocket
|
||||
global.WebSocket = vi.fn(() => ({
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
send: vi.fn(),
|
||||
close: vi.fn(),
|
||||
readyState: WebSocket.OPEN,
|
||||
})) as any;
|
||||
|
||||
describe('useWebSocket', () => {
|
||||
it('connects to WebSocket', async () => {
|
||||
const { result } = renderHook(() => useWebSocket('ws://localhost:8000/ws/'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isConnected).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles messages', async () => {
|
||||
const { result } = renderHook(() => useWebSocket('ws://localhost:8000/ws/'));
|
||||
|
||||
// Simulate message
|
||||
const ws = (global.WebSocket as any).mock.results[0].value;
|
||||
const messageEvent = new MessageEvent('message', {
|
||||
data: JSON.stringify({ type: 'order_update', order_id: 1 })
|
||||
});
|
||||
ws.onmessage(messageEvent);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.lastMessage).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### Components to Test
|
||||
|
||||
1. **Pages**:
|
||||
- `StrategiesPage` - CRUD operations, start/stop
|
||||
- `TradingPage` - Order placement, position closing
|
||||
- `DashboardPage` - AutoPilot controls, system health
|
||||
- `PortfolioPage` - Position management, charts
|
||||
- `BacktestPage` - Backtest execution, results
|
||||
- `SettingsPage` - All settings tabs
|
||||
|
||||
2. **Components**:
|
||||
- `StrategyDialog` - Form validation, parameter configuration
|
||||
- `OrderForm` - Order type handling, validation
|
||||
- `PositionCard` - Position display, close functionality
|
||||
- `StatusIndicator` - Status display
|
||||
- `SystemHealth` - Health status aggregation
|
||||
- `DataFreshness` - Timestamp calculations
|
||||
- `OperationsPanel` - Operation display
|
||||
|
||||
3. **Hooks**:
|
||||
- `useWebSocket` - Connection, messages, subscriptions
|
||||
- `useRealtimeData` - Query invalidation
|
||||
|
||||
4. **Contexts**:
|
||||
- `SnackbarContext` - Notification display
|
||||
- `WebSocketProvider` - WebSocket management
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
npm test
|
||||
|
||||
# Run tests in watch mode
|
||||
npm test -- --watch
|
||||
|
||||
# Run tests with UI
|
||||
npm run test:ui
|
||||
|
||||
# Generate coverage report
|
||||
npm run test:coverage
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Mock External Dependencies**: Mock API calls, WebSocket connections
|
||||
2. **Test User Interactions**: Use `@testing-library/user-event` for clicks, typing
|
||||
3. **Test Error States**: Verify error handling and display
|
||||
4. **Test Loading States**: Ensure loading indicators appear
|
||||
5. **Test Accessibility**: Use `@testing-library/jest-dom` matchers
|
||||
6. **Keep Tests Fast**: Mock expensive operations
|
||||
7. **Test Edge Cases**: Empty states, error conditions, boundary values
|
||||
|
||||
## Example Test Suite Structure
|
||||
|
||||
```
|
||||
frontend/src/
|
||||
├── components/
|
||||
│ ├── __tests__/
|
||||
│ │ ├── StatusIndicator.test.tsx
|
||||
│ │ ├── StrategyDialog.test.tsx
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── pages/
|
||||
│ ├── __tests__/
|
||||
│ │ ├── StrategiesPage.test.tsx
|
||||
│ │ ├── TradingPage.test.tsx
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── hooks/
|
||||
│ ├── __tests__/
|
||||
│ │ ├── useWebSocket.test.ts
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
└── api/
|
||||
├── __tests__/
|
||||
│ ├── strategies.test.ts
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user