Backend Testing
Guidance for unit, integration, and component tests in the write-service (Jest + TypeScript).
Test Pyramid Overview
| Type | Scope | Mocks | Run Command |
|---|---|---|---|
| Unit | Single module (service, controller, model) | Yes – external deps | npm run test:unit |
| Integration | API routes + real DB (no full container stack) | No – real DB | Not yet configured |
| Component | Full HTTP API + real DB + containers | No – live service | npm run test:component |
Unit Tests
Location and Config
- •Path:
test/unit/**/*.test.ts - •Config:
jest.config.unit.js(ts-jest, node env) - •Run:
npm run test:unit
Patterns
1. Mock dependencies at module level
jest.mock('../../../src/models/exerciseModel');
jest.mock('../../../src/models/workoutDayModel');
const mockExerciseModel = ExerciseModel as jest.Mocked<typeof ExerciseModel>;
const mockWorkoutDayModel = WorkoutDayModel as jest.Mocked<typeof WorkoutDayModel>;
2. Controllers – mock req/res
req = { params: {}, body: {} };
res = { status: jest.fn().mockReturnThis(), json: jest.fn().mockReturnThis() };
3. Services – mock models, assert calls
mockWorkoutDayModel.exists.mockResolvedValue(true); mockExerciseModel.create.mockResolvedValue(created); const result = await ExerciseService.create(input); expect(mockWorkoutDayModel.exists).toHaveBeenCalledWith(1); expect(mockExerciseModel.create).toHaveBeenCalledWith(input); expect(result).toEqual(created);
4. Cleanup
beforeEach(() => jest.clearAllMocks()); afterEach(() => consoleErrorSpy?.mockRestore());
Coverage
- •Excluded:
src/index.ts,src/config/database.ts - •Reports:
coverage/(lcov)
Integration Tests
Purpose
Test API routes with a real database, no mocks. Exercise request validation, DB queries, and error handling without running the full container stack.
When to Add
- •Need to verify SQL, transactions, or DB constraints
- •Want faster feedback than component tests
- •Component tests are too heavy for a given change
Suggested Setup (if adding)
- •Config:
jest.config.integration.jswithtestMatch: ['**/test/integration/**/*.test.ts'] - •DB: Use test DB (e.g.
xq_fitnesswith test credentials) or Docker Compose - •Pattern: Start Express app, use
supertestagainstapp, run migrations, seed if needed - •Cleanup: Truncate tables or use transactions per test
Example Pattern
import request from 'supertest';
import app from '../../src/app';
describe('POST /api/v1/routines', () => {
it('creates routine and persists to DB', async () => {
const res = await request(app)
.post('/api/v1/routines')
.send({ name: 'Test', isActive: true })
.expect(201);
expect(res.body.id).toBeDefined();
// Optionally query DB to verify
});
});
Component Tests
Component tests hit the live API over HTTP with a real database. Follow the project workflow.
Reference
Use the component-test rule: .cursor/rules/component-test.mdc (or write-service/.cursor/rules/component-test.mdc).
Quick Workflow
- •Build:
./build-write-service.sh(from write-service root) - •Client:
npm run generate:clientthennpm install - •Env:
xq-infra generate -f ./test-envandxq-infra up - •Run:
npm run test:componentornpm run test:component:ci - •Teardown:
xq-infra down
Structure
- •Tests:
test/component/workflows/**/*.test.ts - •Helpers:
test/component/helpers/(api-client, test-data, cleanup, database) - •Setup/Teardown:
test/component/setup.ts,teardown.ts - •Config:
jest.config.component.js(uses@chauhaidang/xq-test-utils)
Patterns
- •Use
ApiClientfromhelpers/api-client.ts(generated client wrapper) - •Use
testDatafromhelpers/test-data.tsfor unique payloads - •Use
CleanupHelperto track and delete created resources - •Use
DatabaseHelperfrom@chauhaidang/xq-test-utilsfor DB assertions - •Default URLs:
API_BASE_URL,HEALTH_CHECK_URL(test-env gateway on 8080)
Port Conflicts
If startup fails, check for other stacks (e.g. read-service) using the same ports. Run xq-infra down in other service directories.
Summary Checklist
Unit tests
- • Mock all external modules (models, services)
- • Use
jest.clearAllMocks()inbeforeEach - • Assert both return values and mock call arguments
Component tests
- • Follow
.cursor/rules/component-test.mdc - • Build image, generate client, run
xq-infra upbefore tests - • Use
CleanupHelperand unique test data
Integration tests (if added)
- • Use real DB, no mocks
- • Isolate tests (transactions or truncate)
- • Use
supertestagainst the Express app