Testing Guide
Testing across the platform follows a layered safety model. Each project uses its own framework and conventions, but all share the principle: tests must never target production systems or corrupt real data.
Backend (NestJS / Jest)
Test Commands
| Command | Safety | What runs |
|---|---|---|
npm run test:unit | Safe | Unit tests only (*.spec.ts) |
npm run test:safe | Safe | Unit + mocked integration (recommended manual check before commit) |
npm run test:integration | Dangerous | Real DB (requires RUN_REAL_INTEGRATION_TESTS=true) |
npm run test:e2e | Dangerous | Real API (requires RUN_REAL_E2E_TESTS=true + E2E_API_URL) |
File Naming Conventions
| Suffix | Level | Ran by CI | Description |
|---|---|---|---|
*.spec.ts | Unit | Yes | Mocked dependencies, no DB/API calls |
*.integration.spec.ts | Safe integration | Yes | TestPrismaService with auto-cleanup |
*.real-integration.spec.ts | Real DB | No | Requires explicit env vars to run |
*.e2e-spec.ts | E2E | No | Hits real API endpoints |
Mocking Patterns
// Service test with mocked Prisma
const module = await Test.createTestingModule({
providers: [
MyService,
{ provide: PrismaService, useValue: { user: { findUnique: jest.fn(), create: jest.fn() } } },
],
}).compile();
// Resolver test with guard override
const module = await Test.createTestingModule({ providers: [MyResolver, MyService] })
.overrideGuard(JwtAuthGuard)
.useValue({ canActivate: () => true })
.compile();
// Transaction mock
{ $transaction: jest.fn((fn) => fn(mockPrisma)) }
Safety Components
| Component | Purpose |
|---|---|
TestEnvironmentGuard | Validates NODE_ENV=test, blocks production DB URLs |
E2EEnvironmentGuard | Prevents targeting production endpoints |
TestPrismaService | Prisma wrapper with built-in environment checks |
TestDataManager | Automatic test data tracking and cleanup |
Background Tasks (FastAPI / pytest)
Test Commands
| Command | Scope |
|---|---|
pytest -m unit | Unit tests (mocked, sub-second) |
pytest -m integration | Real DB with cleanup fixtures |
pytest -m e2e | E2E against ai-dev.aiqlick.com |
pytest --cov=app --cov-report=term-missing | With coverage report |
Conventions
- Async mode:
asyncio_mode = "auto"(all async tests auto-detected) - Coverage minimum: 30% (
--cov-fail-under=30) - Markers:
unit,integration,slow,e2e - Fixtures:
db_pool,db_conn,clean_agent_tablesintests/conftest.py - Results: Auto-saved to
docs/test-results/via fixtures
Frontend (Next.js)
No test framework is configured. Build verification serves as the primary quality gate:
npm run build # Must pass before commit
The pre-commit hook runs scripts/verify-build.sh which blocks commits on build failure.
Pre-Commit Hook Pipeline (Backend)
The backend .husky/pre-commit hook runs these steps in order:
| Step | Action |
|---|---|
| 1 | npx prisma generate — regenerate the Prisma client |
| 2 | yarn build — catch TypeScript / module-graph errors |
| 3 | Schema sync — regenerate schema.gql if any *.resolver.ts / *.dto.ts / *.input.ts / *.entity.ts is staged (auto-stages the refreshed schema.gql) |
| 4 | Dev-boot probe — SERVICE_PORT=14001 npm run start:dev, wait up to 60 s for the log line Application started successfully, then kill the server. Fails the commit if boot times out or the bootstrap logs Failed to start application |
Jest has been intentionally removed from pre-commit for faster iteration. CI runs the full npm run test:safe suite on every push to dev. Developers are expected to run npm run test:safe locally before pushing when they've touched service / resolver code.
The boot probe requires a reachable Postgres and Redis. The default local-dev stack (aiqlick-local-postgres, aiqlick-local-redis) satisfies both — point .env DATABASE_URL and REDIS_URL at localhost so the probe doesn't hit shared Redis Cloud credentials. See Local Docker setup.
The probe uses SERVICE_PORT=14001 (overrides PORT and the default 4001 — see src/main.ts) so it coexists with a dev server already running on 4001.
Environment Variables for Testing
| Variable | Purpose |
|---|---|
NODE_ENV=test | Required for destructive test operations |
TEST_DATABASE_URL | Dedicated test database connection |
RUN_REAL_INTEGRATION_TESTS=true | Enable real DB integration tests |
RUN_REAL_E2E_TESTS=true | Enable E2E tests |
E2E_API_URL | Target endpoint for E2E tests |
ALLOW_DESTRUCTIVE_TESTS=true | Allow data-deleting operations |
ALLOW_PRODUCTION_E2E=true | Override production endpoint protection |
Never set ALLOW_PRODUCTION_E2E=true in CI pipelines. This flag exists only for manual validation by authorized engineers.