# 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
    │   └── ...
    └── ...
```

