8.7 KiB
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:
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:
{
"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 intest/ - Naming:
*.spec.tsfor unit tests,*.e2e-spec.tsfor 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):
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 suitesit()for individual tests (ortest())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:
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/reactfor 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 seedseed-equipment.ts- 5,482 equipment itemsseed-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:
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):
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:
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):
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:
const { result } = await renderHook(() => useCharacterSocket());
await waitFor(() => expect(result.current.socket).toBeDefined());
Error Testing
Not yet implemented, but pattern would be:
Server:
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):
- Write AuthService unit tests with mocked Prisma
- Write JwtAuthGuard tests
- Write integration tests for login/register endpoints
Phase 2 (Character CRUD):
- Test CharactersService access control
- Test HP update logic
- Test condition application
Phase 3 (WebSocket):
- Mock socket.io for gateway tests
- Test connection/disconnect
- Test broadcast patterns
Phase 4 (Client):
- Setup vitest
- Test HpControl component
- Test modal components
- Test Zustand store
Testing analysis: 2026-04-27