# Frontend Testing Strategy

**Project**: Paper Dynasty Real-Time Game Engine - SBA Frontend
**Framework**: Vue 3 + Nuxt 3 + TypeScript
**Testing Philosophy**: Test early, test often - unit tests in every phase
**Created**: 2025-01-10

---

## Overview

This document outlines our comprehensive testing strategy for the SBA frontend. **Unlike the original plan to defer testing to Phase F9, we now write unit tests alongside feature development in each phase** (F1-F8), with E2E and performance testing in Phase F9.

---

## Testing Philosophy

### Core Principles

1. **Test-Driven Quality**: Write tests as you build features, not after
2. **Fast Feedback**: Unit tests run in milliseconds, catch bugs immediately
3. **Confidence**: High test coverage allows refactoring without fear
4. **Documentation**: Tests serve as executable documentation
5. **Regression Prevention**: Tests prevent reintroducing fixed bugs

### Why Test in Each Phase?

✅ **Immediate Feedback**: Catch bugs before they compound
✅ **Better Design**: Writing testable code forces better architecture
✅ **Faster Development**: Less debugging time overall
✅ **Prevent Regressions**: Safe refactoring as project grows
✅ **Easier Onboarding**: Tests document expected behavior

❌ **Without Tests**: Tech debt accumulates, bugs multiply, refactoring becomes risky

---

## Testing Pyramid

```
         /\
        /E2\       E2E Tests (Phase F9)
       /____\      - Full user flows
      /      \     - Cross-browser testing
     / INTEG  \    - Real WebSocket connections
    /  RATION  \
   /____________\
  /              \ Integration Tests (Light, as needed)
 /    UNIT        \ - API mocking
/      TESTS       \ - Store + composable integration
/____________________\
      80% of tests   Unit Tests (Every Phase)
                     - Composables, stores, utils
                     - Fast, isolated, deterministic
```

**Target Distribution**:
- **80%**: Unit tests (fast, isolated, many)
- **15%**: Integration tests (medium speed, some mocking)
- **5%**: E2E tests (slow, expensive, critical paths only)

---

## Testing Tools

### Unit Testing

**Vitest** - Modern, fast test runner
- Native ESM support
- Compatible with Vue and Nuxt
- Watch mode with instant feedback
- Built-in coverage reporting

**@vue/test-utils** - Official Vue testing library
- Mount Vue components
- Simulate user interactions
- Test props, emits, slots

**happy-dom** - Lightweight DOM implementation
- Faster than jsdom
- Sufficient for most unit tests
- Integrates with Vitest

### E2E Testing (Phase F9)

**Playwright** - Modern E2E testing
- Cross-browser (Chromium, Firefox, WebKit)
- Mobile emulation
- Network interception
- Video/screenshot capture

---

## What to Test (By Layer)

### Composables (Critical - 90%+ coverage)

**Why**: Composables contain business logic and are highly reusable.

**Test**:
- ✅ Return values and reactive refs
- ✅ Side effects (API calls, WebSocket emits)
- ✅ Error handling and edge cases
- ✅ Lifecycle hooks (onMounted, onUnmounted)
- ✅ Integration with other composables/stores

**Example**: `useWebSocket.spec.ts`
```typescript
describe('useWebSocket', () => {
  it('connects with JWT auth on mount', () => { ... })
  it('reconnects with exponential backoff', () => { ... })
  it('emits correct events', () => { ... })
  it('handles connection errors gracefully', () => { ... })
})
```

### Stores (Critical - 90%+ coverage)

**Why**: Stores hold application state and business logic.

**Test**:
- ✅ State initialization
- ✅ Actions modify state correctly
- ✅ Computed properties calculate correctly
- ✅ Persistence (localStorage integration)
- ✅ Multiple action calls (state transitions)

**Example**: `auth.spec.ts`
```typescript
describe('useAuthStore', () => {
  it('logs in user with Discord OAuth', () => { ... })
  it('persists token to localStorage', () => { ... })
  it('refreshes expired tokens', () => { ... })
  it('logs out and clears state', () => { ... })
})
```

### Components (Important - 70%+ coverage)

**Why**: Components are the user interface layer.

**Test**:
- ✅ Props render correctly
- ✅ User interactions trigger emits
- ✅ Conditional rendering (v-if, v-show)
- ✅ Computed properties and methods
- ⚠️ **Not**: Visual appearance (use Storybook for that)

**Example**: `ScoreBoard.spec.ts`
```typescript
describe('ScoreBoard', () => {
  it('displays correct score and inning', () => { ... })
  it('highlights current inning', () => { ... })
  it('shows correct inning half (Top/Bottom)', () => { ... })
})
```

### Utilities (Critical - 100% coverage)

**Why**: Pure functions are easiest to test and should be thoroughly covered.

**Test**:
- ✅ Input/output correctness
- ✅ Edge cases (null, undefined, empty)
- ✅ Error handling
- ✅ Type safety

**Example**: `formatters.spec.ts`
```typescript
describe('formatInning', () => {
  it('formats top of 1st inning', () => { ... })
  it('formats bottom of 9th inning', () => { ... })
  it('handles extra innings', () => { ... })
})
```

---

## Testing Patterns

### Mocking Strategy

**Mock External Dependencies**:
```typescript
// Mock Socket.io
vi.mock('socket.io-client', () => ({
  io: vi.fn(() => ({
    on: vi.fn(),
    emit: vi.fn(),
    connect: vi.fn(),
    disconnect: vi.fn(),
  }))
}))

// Mock Nuxt composables
vi.mock('#app', () => ({
  useRuntimeConfig: vi.fn(() => ({
    public: {
      apiUrl: 'http://localhost:8000',
      wsUrl: 'http://localhost:8000'
    }
  }))
}))
```

**Don't Mock What You Own**:
- ❌ Don't mock stores in composable tests (test integration)
- ❌ Don't mock child components (use shallow mount if needed)
- ✅ Mock external APIs, WebSocket, localStorage

### Test Structure (AAA Pattern)

```typescript
describe('Feature', () => {
  it('does something specific', () => {
    // Arrange: Set up test data and mocks
    const store = useAuthStore()
    const mockToken = 'jwt-token-123'

    // Act: Perform the action being tested
    store.setToken(mockToken)

    // Assert: Verify the outcome
    expect(store.token).toBe(mockToken)
    expect(localStorage.setItem).toHaveBeenCalledWith('token', mockToken)
  })
})
```

### Testing Async Code

```typescript
it('fetches user data on login', async () => {
  const store = useAuthStore()

  // Mock API response
  vi.mocked($fetch).mockResolvedValue({
    id: '123',
    username: 'testuser'
  })

  // Act
  await store.login('code', 'state')

  // Assert
  expect(store.currentUser).toEqual({
    id: '123',
    username: 'testuser'
  })
})
```

### Testing Composables

```typescript
import { mount } from '@vue/test-utils'
import { defineComponent } from 'vue'

it('useGameActions emits correct events', () => {
  const mockSocket = {
    emit: vi.fn(),
    connected: true
  }

  // Create wrapper component to test composable
  const TestComponent = defineComponent({
    setup() {
      const actions = useGameActions('game-123')
      return { actions }
    },
    template: '<div></div>'
  })

  const wrapper = mount(TestComponent, {
    global: {
      provide: {
        socket: mockSocket
      }
    }
  })

  // Act
  wrapper.vm.actions.rollDice()

  // Assert
  expect(mockSocket.emit).toHaveBeenCalledWith('roll_dice', {
    game_id: 'game-123'
  })
})
```

---

## Phase-by-Phase Testing Plan

### Phase F1: Core Infrastructure (20+ tests)

**Focus**: Composables and stores (most critical)

**Tests**:
- `useWebSocket.spec.ts` (8+ tests)
  - Connection/disconnection
  - Exponential backoff
  - JWT authentication
  - Event handler registration

- `useGameActions.spec.ts` (6+ tests)
  - Validation logic
  - Emit parameter construction
  - Error handling

- `auth.spec.ts` (3+ tests)
  - Login/logout flow
  - Token management
  - localStorage persistence

- `game.spec.ts` (2+ tests)
  - State updates
  - Play history management

- `ui.spec.ts` (2+ tests)
  - Toast lifecycle
  - Modal stack

**Estimated Time**: 3-4 hours

---

### Phase F2: Game State Display (10+ tests)

**Focus**: Display components and state sync

**Tests**:
- `ScoreBoard.spec.ts` (2+ tests)
- `GameBoard.spec.ts` (2+ tests)
- `PlayByPlay.spec.ts` (2+ tests)
- `CurrentBatter.spec.ts` (2+ tests)
- State synchronization logic (2+ tests)

**Estimated Time**: 2-3 hours

---

### Phase F3: Decision Input Workflow (8+ tests)

**Focus**: Decision components and validation

**Tests**:
- `DefensiveSetup.spec.ts` (2+ tests)
- `OffensiveApproach.spec.ts` (2+ tests)
- `StolenBaseInputs.spec.ts` (2+ tests)
- Decision validation logic (2+ tests)

**Estimated Time**: 2 hours

---

### Phase F4: Manual Outcome Workflow (8+ tests)

**Focus**: Dice roll and outcome validation

**Tests**:
- `DiceRollButton.spec.ts` (2+ tests)
- `OutcomeInputForm.spec.ts` (3+ tests)
- Outcome validation logic (3+ tests)

**Estimated Time**: 2 hours

---

### Phase F5: Substitutions (8+ tests)

**Focus**: Substitution logic and components

**Tests**:
- `SubstitutionModal.spec.ts` (2+ tests)
- `PinchHitterSelect.spec.ts` (2+ tests)
- Substitution validation (4+ tests)

**Estimated Time**: 2 hours

---

### Phase F6: Game Management (10+ tests)

**Focus**: Game API and management features

**Tests**:
- `useGameApi.spec.ts` (4+ tests)
- `GameCreationForm.spec.ts` (2+ tests)
- `GamesList.spec.ts` (2+ tests)
- `GameFilters.spec.ts` (2+ tests)

**Estimated Time**: 2-3 hours

---

### Phase F7: Spectator Mode (5+ tests)

**Focus**: Spectator permissions and UI

**Tests**:
- Spectator role validation (2+ tests)
- `SpectatorGameView.spec.ts` (2+ tests)
- Spectator WebSocket events (1+ test)

**Estimated Time**: 1-2 hours

---

### Phase F8: Polish & Animation (5+ tests)

**Focus**: Animation triggers and timing

**Tests**:
- Animation trigger logic (3+ tests)
- Toast timing and auto-dismiss (2+ tests)

**Estimated Time**: 1-2 hours

---

### Phase F9: E2E & Performance (10+ tests)

**Focus**: End-to-end user flows and performance

**E2E Tests**:
- `auth-flow.e2e.ts` - Complete auth workflow
- `game-creation.e2e.ts` - Create and join game
- `gameplay-flow.e2e.ts` - Full game from start to finish
- `substitution-flow.e2e.ts` - Player substitutions
- `spectator-flow.e2e.ts` - Spectator mode
- `mobile-responsive.e2e.ts` - Mobile UX
- `websocket-recovery.e2e.ts` - Connection recovery

**Performance Tests**:
- Lighthouse audits (automated)
- Bundle size monitoring
- Memory leak detection

**Estimated Time**: 1 week

---

## Running Tests

### Development Workflow

```bash
# Run all tests (once)
npm run test

# Watch mode (re-run on file changes)
npm run test:watch

# Run specific test file
npm run test useWebSocket.spec.ts

# Run tests matching pattern
npm run test --grep "WebSocket"

# Coverage report
npm run test:coverage

# UI mode (interactive)
npm run test:ui
```

### CI/CD Pipeline

```yaml
# .github/workflows/test.yml
name: Test Suite
on: [push, pull_request]

jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run test:coverage
      - uses: codecov/codecov-action@v3
        with:
          files: ./coverage/coverage-final.json

  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npx playwright install
      - run: npm run test:e2e
```

---

## Coverage Goals

### Minimum Coverage Targets

| Layer | Target | Priority |
|-------|--------|----------|
| Composables | 90% | Critical |
| Stores | 90% | Critical |
| Utilities | 100% | Critical |
| Components | 70% | Important |
| Overall | 80% | Required |

### Coverage Exemptions

**Don't need 100% coverage for**:
- UI-only components (visual polish)
- Third-party library wrappers
- Configuration files
- Type definitions

**Do need high coverage for**:
- Business logic (composables, stores)
- Validation and error handling
- WebSocket communication
- Authentication and security

---

## Best Practices

### DO ✅

- Write tests alongside feature code
- Test behavior, not implementation
- Use descriptive test names
- Keep tests independent (no shared state)
- Mock external dependencies
- Test edge cases and errors
- Run tests before committing

### DON'T ❌

- Skip tests to "save time" (you'll pay later)
- Test implementation details
- Create test dependencies (test A needs test B)
- Mock everything (test real integration)
- Write slow unit tests (use E2E instead)
- Ignore failing tests
- Commit code that breaks tests

---

## Troubleshooting

### Tests Run Slowly

**Problem**: Unit tests take > 5 seconds
**Solution**:
- Check for unmocked API calls
- Use happy-dom instead of jsdom
- Avoid unnecessary component mounts
- Run tests in parallel

### Flaky Tests

**Problem**: Tests pass sometimes, fail other times
**Solution**:
- Fix race conditions (use `waitFor`)
- Clear mocks between tests
- Avoid relying on timing
- Check for shared state

### Coverage Not Updating

**Problem**: Coverage report doesn't reflect new tests
**Solution**:
- Delete `coverage/` directory
- Re-run `npm run test:coverage`
- Check if files are ignored in config

---

## Example Test Suites

### Composable Test Template

```typescript
// tests/unit/composables/useExample.spec.ts
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { useExample } from '~/composables/useExample'

describe('useExample', () => {
  beforeEach(() => {
    // Setup: Create fresh instances, mock dependencies
  })

  afterEach(() => {
    // Cleanup: Clear mocks, restore state
    vi.clearAllMocks()
  })

  describe('initialization', () => {
    it('initializes with default state', () => {
      // Test default values
    })
  })

  describe('actions', () => {
    it('performs action successfully', async () => {
      // Test happy path
    })

    it('handles errors gracefully', async () => {
      // Test error case
    })
  })

  describe('edge cases', () => {
    it('handles null input', () => {
      // Test edge case
    })
  })
})
```

### Store Test Template

```typescript
// tests/unit/store/example.spec.ts
import { describe, it, expect, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useExampleStore } from '~/store/example'

describe('useExampleStore', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })

  it('initializes with default state', () => {
    const store = useExampleStore()
    expect(store.someState).toBe(null)
  })

  it('updates state via action', () => {
    const store = useExampleStore()
    store.someAction('value')
    expect(store.someState).toBe('value')
  })

  it('computes derived state correctly', () => {
    const store = useExampleStore()
    store.someState = 'test'
    expect(store.computedValue).toBe('TEST')
  })
})
```

### Component Test Template

```typescript
// tests/unit/components/Example.spec.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import ExampleComponent from '~/components/Example.vue'

describe('ExampleComponent', () => {
  it('renders props correctly', () => {
    const wrapper = mount(ExampleComponent, {
      props: {
        title: 'Test Title'
      }
    })

    expect(wrapper.text()).toContain('Test Title')
  })

  it('emits event on button click', async () => {
    const wrapper = mount(ExampleComponent)

    await wrapper.find('button').trigger('click')

    expect(wrapper.emitted('click')).toBeTruthy()
    expect(wrapper.emitted('click')?.[0]).toEqual(['expected-value'])
  })

  it('conditionally renders based on prop', () => {
    const wrapper = mount(ExampleComponent, {
      props: {
        show: false
      }
    })

    expect(wrapper.find('.conditional-element').exists()).toBe(false)
  })
})
```

---

## Success Metrics

**Phase Completion Criteria**:
- ✅ All new code has corresponding tests
- ✅ All tests passing (no skipped tests)
- ✅ Coverage meets phase target (> 80%)
- ✅ No flaky tests
- ✅ Tests run in < 10 seconds (unit tests)

**Project Completion Criteria**:
- ✅ 80%+ overall coverage
- ✅ 90%+ coverage on critical paths
- ✅ All E2E tests passing
- ✅ Performance benchmarks met
- ✅ Zero known failing tests

---

## Resources

**Documentation**:
- [Vitest Docs](https://vitest.dev/)
- [Vue Test Utils](https://test-utils.vuejs.org/)
- [Playwright Docs](https://playwright.dev/)

**Backend Tests** (Inspiration):
- `/mnt/NV2/Development/strat-gameplay-webapp/backend/tests/unit/`
- 730+ tests with 99.9% coverage - excellent patterns to learn from

---

**Document Version**: 1.0
**Last Updated**: 2025-01-10
**Status**: Active - guiding all frontend development
