Files
Dimension-47/.planning/codebase/TESTING.md

341 lines
8.7 KiB
Markdown

# 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*