# Testing Patterns

**Analysis Date:** 2026-04-27

## Test Framework Status

**Current State:** **Minimal test coverage - testing infrastructure in place but not actively used**

### Jest (Server)

**Runner:**
- Jest 30.x
- Config: Inline in `server/package.json` (lines 88-104)

**Run Commands:**
```bash
cd server
npm test              # Run all unit tests (seeks *.spec.ts files)
npm run test:watch   # Watch mode for development
npm run test:cov     # Generate coverage report
npm run test:debug   # Debug mode with breakpoints
npm run test:e2e     # Run end-to-end tests (config: test/jest-e2e.json)
```

**Configuration Details:**
```json
{
  "moduleFileExtensions": ["js", "json", "ts"],
  "rootDir": "src",
  "testRegex": ".*\\.spec\\.ts$",
  "transform": { "^.+\\.(t|j)s$": "ts-jest" },
  "collectCoverageFrom": ["**/*.(t|j)s"],
  "coverageDirectory": "../coverage",
  "testEnvironment": "node"
}
```

**Testing Libraries:**
- Jest 30.x (test runner)
- ts-jest (TypeScript support)
- @nestjs/testing (NestJS module testing utilities)
- supertest (HTTP request testing)

### Vitest (Client)

**Status:** Not installed. No vitest config present in `client/package.json`

**Implications:** Client has zero automated test infrastructure. Any future testing would require adding vitest and configuring it.

## Test File Organization

**Server:**
- Location: Unit tests alongside source in `src/`, E2E tests in `test/`
- Naming: `*.spec.ts` for unit tests, `*.e2e-spec.ts` for integration tests
- Example: No unit test files currently exist in `server/src/`

**Current Test Suite:**
- Location: `server/test/app.e2e-spec.ts`
- Scope: Single basic integration test for app startup
- Status: Placeholder test (checks 'Hello World!' endpoint that doesn't exist)

**Client:**
- No test files present
- No test directory structure

## Test Structure (Server)

**E2E Test Example** (`server/test/app.e2e-spec.ts`):
```typescript
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { AppModule } from './../src/app.module';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('Hello World!');
  });
});
```

**Patterns:**
- `describe()` for test suites
- `it()` for individual tests (or `test()`)
- `beforeEach()` for setup (module initialization)
- Async/await for async operations
- Chained `.expect()` assertions with supertest

## Mocking

### Server (Jest/NestJS)

**Framework:** @nestjs/testing provides test module builder

**Pattern Observed:**
```typescript
const moduleFixture: TestingModule = await Test.createTestingModule({
  imports: [AppModule],  // Or specific module imports
}).compile();

const service = moduleFixture.get<ServiceName>(ServiceName);
```

**What to Mock:**
- Database (Prisma) - would use mock provider
- External APIs - would use jest.mock()
- Services with dependencies - inject via module builder

**What NOT to Mock:**
- NestJS core decorators
- Guards/Middleware (test through integration)
- Database schema (use test database)

### Client

**No mocking patterns established yet** - testing infrastructure not present.

Would require:
- Vitest for runner
- `@testing-library/react` for component testing
- Mock fetch/axios calls
- Mock WebSocket connections

## Fixtures and Factories

**Server:**

**Test Data Approach:** Not fully established, but patterns available:
- Prisma seed scripts exist in `server/prisma/`:
  - `seed.ts` - Basic seed
  - `seed-equipment.ts` - 5,482 equipment items
  - `seed-feats.ts` - Feat database
- Could be reused for test fixtures

**Location:** Would be in test directory or integrated with jest setup

**No factory pattern observed** - tests would need to build objects inline or create helper functions

**Client:**

**Not applicable** - no test infrastructure

## Coverage

**Requirements:** None enforced (no CI/CD pipeline checking coverage)

**View Coverage:**
```bash
cd server
npm run test:cov
# Generates: server/coverage/
```

**Current Coverage:** Unknown (no tests running)

**Gaps:** **Entire codebase untested**
- Auth module: No unit tests (`server/src/modules/auth/`)
- Characters module: No unit tests (`server/src/modules/characters/`)
- Battle module: No unit tests (`server/src/modules/battle/`)
- WebSocket gateway: No tests
- Guards/Decorators: No tests
- Client components: No tests
- Client hooks: No tests
- State management (Zustand): No tests

## Test Types

### Unit Tests

**Not currently used**

**When implemented, pattern would be:**
- Test individual services in isolation
- Mock Prisma client
- Location: `server/src/modules/[module]/[module].service.spec.ts`
- Example test structure (not yet used):
```typescript
describe('AuthService', () => {
  let service: AuthService;
  let prisma: PrismaService;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [AuthService, { provide: PrismaService, useValue: mockPrisma }],
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

  it('should register user', async () => {
    // Test implementation
  });
});
```

### Integration Tests

**Single example:** `server/test/app.e2e-spec.ts`

**Scope:**
- Tests full HTTP request/response cycle
- Uses real app instance
- Uses Test.createTestingModule() to create app

**Pattern:**
```typescript
return request(app.getHttpServer())
  .post('/auth/login')
  .send({ identifier: 'user', password: 'pass' })
  .expect(200)
  .expect((res) => {
    expect(res.body.token).toBeDefined();
  });
```

**Would need:** Database test fixtures, cleanup between tests

### E2E Tests

**Config:** `server/test/jest-e2e.json`

**Difference from Integration:**
- Run against deployed/separate server
- Test user workflows end-to-end
- Full database setup/teardown

**Currently:** Not implemented beyond placeholder

## Common Patterns

### Async Testing

**Server (Jest):**
```typescript
it('should load data', async () => {
  const result = await service.loadData();
  expect(result).toBeDefined();
});
```

- async/await preferred
- Supertest chainable: `request().post().send().expect()`

**Client (not yet implemented):**
Would use:
```typescript
const { result } = await renderHook(() => useCharacterSocket());
await waitFor(() => expect(result.current.socket).toBeDefined());
```

### Error Testing

**Not yet implemented, but pattern would be:**

**Server:**
```typescript
it('should throw NotFoundException', async () => {
  await expect(service.getCharacter('invalid-id'))
    .rejects
    .toThrow(NotFoundException);
});
```

**Actual exception handling verified through:**
- Controllers catch exceptions
- Guards handle auth failures
- Integration tests verify HTTP status codes

## Critical Test Gaps

**High Priority (Authentication):**
- AuthService.register() - conflicts, hashing, JWT generation
- AuthService.login() - invalid credentials, token generation
- JWT guard - token validation, public routes
- File: `server/src/modules/auth/auth.service.ts` (lines 20-104)

**High Priority (Character Management):**
- CharactersService access control (checkCampaignAccess, checkCharacterAccess)
- HP updates and state sync via WebSocket
- Condition application (dying, wounded, doomed mechanics)
- Item management (equip, invest, notes)
- File: `server/src/modules/characters/characters.service.ts`

**High Priority (Real-time Sync):**
- CharactersGateway connection authentication
- WebSocket message broadcasting
- Concurrent client updates
- File: `server/src/modules/characters/characters.gateway.ts`

**Medium Priority (Client UI):**
- HpControl component (damage, heal, direct modes)
- AddConditionModal (search, filtering, validation)
- Character import from Pathbuilder JSON
- File: `client/src/features/characters/components/`

**Medium Priority (Validation):**
- DTO validation (CreateCharacterDto, LoginDto)
- Prisma query results
- File: `server/src/modules/*/dto/`

## Recommendations for Implementation

**Phase 1 (Auth):**
1. Write AuthService unit tests with mocked Prisma
2. Write JwtAuthGuard tests
3. Write integration tests for login/register endpoints

**Phase 2 (Character CRUD):**
1. Test CharactersService access control
2. Test HP update logic
3. Test condition application

**Phase 3 (WebSocket):**
1. Mock socket.io for gateway tests
2. Test connection/disconnect
3. Test broadcast patterns

**Phase 4 (Client):**
1. Setup vitest
2. Test HpControl component
3. Test modal components
4. Test Zustand store

---

*Testing analysis: 2026-04-27*
