Running Tests in Nango
Overview
Nango uses Vitest with three separate configs for unit, integration, and CLI tests. Getting the config wrong silently runs zero tests.
Quick Reference
| Type | Command | File pattern |
|---|---|---|
| Unit | npm run test:unit |
*.unit.test.ts |
| Integration | npm run test:integration |
*.integration.test.ts |
| CLI | npm run test:cli |
*.unit.cli-test.ts |
| All | npm run test |
all patterns |
Running Specific Tests
# Single integration test file
npm run test:integration -- packages/server/lib/controllers/v1/team/getTeam.integration.test.ts
# Single unit test file
npm run test:unit -- packages/server/lib/authz/permissions.unit.test.ts
# Pattern match
npm run test:integration -- -t "should be protected"
All commands run from the repo root.
Before Running Tests
Always run npm install first — after pulling changes, switching branches, or in a fresh worktree. Missing deps cause import errors that look like code issues.
Integration Test Requirements
- Docker required: Global setup (
tests/setup.ts) starts PostgreSQL, Elasticsearch, ActiveMQ, and Redis via testcontainers - Tests run sequentially (
fileParallelism: false,singleFork: true) - Timeout: 20 seconds per test
- Environment:
FLAG_AUTH_ROLES_ENABLED=true, timezone UTC
Writing Integration Tests
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { seeders } from '@nangohq/shared';
import { runServer, shouldBeProtected, shouldRequireQueryEnv } from '../../../../utils/tests.js';
const route = '/api/v1/endpoint';
let api: Awaited<ReturnType<typeof runServer>>;
describe(`GET ${route}`, () => {
beforeAll(async () => {
api = await runServer(); // Starts Express + runs all migrations
});
afterAll(() => { api.server.close(); });
it('should be protected', async () => {
const res = await api.fetch(route, { method: 'GET', query: { env: 'dev' } });
shouldBeProtected(res);
});
});
Key utilities (packages/server/lib/utils/tests.ts):
runServer()— starts Express with DB migrationsshouldBeProtected(res)— asserts 401shouldRequireQueryEnv(res)— asserts 400 missing envauthenticateUser(api, user, password)— returns session cookie (use for endpoints needingres.locals.user)isSuccess(json)/isError(json)— response type guards
Seeders (@nangohq/shared):
seeders.seedAccountEnvAndUser()— creates account, environment, user, secret key
Custom Matchers
Available in all tests via tests/setupFiles.ts:
toBeIsoDate(),toBeIsoDateTimezone(),toBeUUID(),toBeSha256()toBeWithinMs(expected, toleranceMs)
Common Mistakes
| Mistake | Symptom | Fix |
|---|---|---|
| Wrong config for integration tests | 0 tests found | Use npm run test:integration not npm run test:unit |
| Using bearer token for session endpoints | 401 errors | Use authenticateUser() + session cookie |
| Running from package dir | Config not found | Always run from repo root |
| Docker not running | Connection refused | Integration tests need Docker for testcontainers |
Missing query: { env: 'dev' } |
400 invalid query | Most endpoints require env query param |