Operations
Testing
Test suite overview, running tests, writing new tests, and coverage across all packages.
The Realtime Platform has 221+ automated tests across all 12 packages, run with Vitest.
Running Tests
# All tests across the monorepo
pnpm test
# Single package
pnpm --filter @realtime/backend test
# Watch mode
pnpm --filter @realtime/event-router test:watch
# With coverage
pnpm --filter @realtime/auth test -- --coverageTest Breakdown
| Package | Tests | Description |
|---|---|---|
shared-utils | 20 | Date, error, and object utility tests |
shared-config | 2 | Environment validation tests |
observability | 3 | Logger tests |
redis-layer | 7 | Key pattern tests |
auth | 9 | JWT, permissions tests |
event-router | 11 | Filters, normalizer, subscription registry |
topic-registry | 19 | Service CRUD, validation, environment scoping |
schema-registry | 16 | Service, compatibility checker, environment scoping |
metrics | 11 | Dashboard metrics, hot topics analyzer |
workers | 30 | Mapping evaluator, webhook signer/registry, CDC reader |
backend | 76 | API routes, document service, debugger, trace store |
sdk | 17 | RealtimeClient, EventBus |
| Total | 221+ |
Test Architecture
Tests use dependency injection throughout — all stores and services are injected via interfaces, so tests use in-memory implementations without requiring PostgreSQL or Redis.
// Example: testing the topics API route
const store = new InMemoryTopicStore();
const service = new TopicRegistryService(store);
const app = createApp({ topicService: service, /* ... */ });
// Test against the Express app directly
const response = await request(app)
.post('/api/topics')
.send({ name: 'test.topic', description: 'Test', owner: 'team' });
expect(response.status).toBe(201);Writing New Tests
Create a test file
Place test files next to the source code with a .test.ts suffix:
packages/my-package/src/
service.ts
service.test.tsOr in a __tests__/ directory:
apps/backend/src/api/
topics.ts
__tests__/
topics.test.tsWrite the test
import { describe, it, expect, beforeEach } from 'vitest';
describe('MyService', () => {
let service: MyService;
beforeEach(() => {
service = new MyService(new InMemoryStore());
});
it('should create an item', async () => {
const result = await service.create({ name: 'test' });
expect(result.name).toBe('test');
});
});Run the test
pnpm --filter @realtime/my-package testConfiguration
The root vitest.config.ts provides shared configuration for all packages:
- Test framework: Vitest
- Coverage provider: v8
- File pattern:
**/*.test.ts
Best Practices
- Use in-memory store implementations for unit tests (no external dependencies)
- Test both success and error paths
- Test environment/application scoping for all entity operations
- Use
beforeEachto reset state between tests - Keep tests focused — one assertion concept per test