This document provides comprehensive guidance on testing practices, setup, and execution for the AROCAPI project.
- Overview
- Test Types
- Setup
- Running Tests
- Writing Tests
- Coverage Requirements
- Continuous Integration
- Troubleshooting
The AROCAPI project uses Vitest as the primary testing framework, providing:
- Unit tests for individual functions and modules
- Integration tests for API endpoints with real database connections
- OpenAPI validation to ensure API compliance
- 95% coverage requirement to maintain code quality
Test individual components in isolation with mocked dependencies.
Location: src/**/*.test.ts
Purpose:
- Validate business logic
- Test error handling
- Verify edge cases
- Fast execution without external dependencies
Example:
// src/utils/errors.test.ts
import { describe, it, expect } from 'vitest';
import { createNotFoundError } from './errors.js';
describe('createNotFoundError', () => {
it('should create error with message and resource', () => {
const error = createNotFoundError('Not found', 'resource-id');
expect(error).toEqual({
error: 'Not Found',
message: 'Not found',
resource: 'resource-id',
});
});
});Test complete API workflows with real database and OpenSearch instances.
Location: src/test/integration.test.ts
Purpose:
- Test full request/response cycles
- Validate database interactions
- Test with real external services
- End-to-end API functionality
Example:
// src/test/integration.test.ts
describe('GET /entities', () => {
it('should return entities from database', async () => {
const app = getTestApp();
const response = await app.inject({
method: 'GET',
url: '/entities',
});
expect(response.statusCode).toBe(200);
const body = JSON.parse(response.body);
expect(body.total).toBeGreaterThan(0);
});
});- Docker (for test databases)
- Node.js LTS
- pnpm package manager
-
Install dependencies:
pnpm install
-
Verify setup:
pnpm run test
# Run all tests once
pnpm run test
# Run tests in watch mode
pnpm run test:watch
# Run tests with UI interface
pnpm run test:ui
# Run tests with coverage report
pnpm run test:coverageTests use separate services from development:
- Database:
localhost:3307(catalog_test) - OpenSearch:
localhost:9201 - Environment: Configured via
.env.test
# Run specific test file
pnpm run test src/routes/entity.test.ts
# Run tests matching pattern
pnpm run test --grep "entity"
# Run only unit tests (exclude integration)
pnpm run test --exclude "**/integration.test.ts"-
Descriptive test names:
it('should return 404 when entity not found', async () => { // Test implementation });
-
AAA Pattern: Arrange, Act, Assert
it('should filter entities by memberOf', async () => { // Arrange await seedTestData(); // Act const response = await app.inject({ method: 'GET', url: '/entities?memberOf=http://example.com/collection/1', }); // Assert expect(response.statusCode).toBe(200); expect(response.body.entities).toHaveLength(1); });
-
Use snapshots for complex objects:
expect(response.body).toMatchSnapshot();
Unit Tests: Mock all external dependencies
const mockPrisma = {
entity: {
findFirst: vi.fn(),
},
};
fastify.decorate('prisma', mockPrisma);Integration Tests: Use real services but clean data between tests
beforeEach(async () => {
await seedTestData();
});
afterEach(async () => {
await cleanupTestData();
});Always test both success and error paths:
describe('Entity Route', () => {
it('should return entity when found', async () => {
// Test success case
});
it('should return 404 when not found', async () => {
// Test error case
});
it('should return 500 on database error', async () => {
// Test system error
});
});- Lines: 95%
- Functions: 95%
- Branches: 95%
- Statements: 95%
- Generated code (
src/generated/**) - Build output (
dist/**) - Example code (
example/**) - Test files (
**/*.test.ts) - Configuration files (
*.config.ts) - Scripts (
src/scripts/**)
# Generate coverage report
pnpm run test:coverage
# Open HTML report
open coverage/index.htmlThe CI pipeline will fail if coverage drops below 95%. This ensures:
- New code is properly tested
- Existing test quality is maintained
- Technical debt is minimized
Tests run automatically on:
- Pull requests to main branch
- Manual triggers via workflow_dispatch
- Setup: Install dependencies, start services
- Health checks: Verify database and OpenSearch connectivity
- Database setup: Run migrations
- Linting: Code style and type checking
- Testing: Execute full test suite
- Coverage: Verify coverage thresholds
- Reporting: Post results to PR
- All tests must pass
- Coverage must be ≥95%
- Linting must pass
- Type checking must pass
The pipeline uses GitHub Actions services to provide:
- MySQL 8 database (port 3307)
- OpenSearch 3 (port 9201)
- Health checks to ensure service readiness
# Run with debug logging
DEBUG=* pnpm run test
# Vitest UI for interactive debugging
pnpm run test:ui