> ## Documentation Index
> Fetch the complete documentation index at: https://docs.soundchecklive.io/llms.txt
> Use this file to discover all available pages before exploring further.

# API Testing

> Testing strategies for api-events

api-events uses **Vitest** for unit and integration tests, plus the repo-root **`e2e/`** suite for full HTTP regression against Encore on `:4000`.

## Test types

| Type | Command | Database | Purpose |
| - | - | - | - |
| Unit | `npm test` | Mocked (Prisma vi.mock) | Operations, processors, helpers |
| Integration | `npm run test:integration` | Postgres on `:5434` | Real DB queries |
| E2E | `npm run test:e2e` | Ephemeral / dev DB via runner | Full HTTP flows on `:4000` |

All commands run from `api-events/`.

***

## Running tests

### Unit tests

```bash theme={null}
cd api-events

npm test                    # all unit tests
npm run test:watch          # watch mode
npm run test:coverage       # with a coverage report (not gated)
npm test -- src/systems/venues/updateVenueOperation.test.ts  # single file
```

### Integration tests

Requires ephemeral Postgres on `:5434` (one-time setup):

```bash theme={null}
cd api-events
npm run test:integration:setup   # pwsh — starts db-ephemeral stack
npm run test:integration
```

Integration tests use `DATABASE_URL=postgresql://postgres:postgres@localhost:5434/soundcheck_test?schema=public`.

### E2E regression

Requires Encore running on `:4000` (or use the standalone runner):

```bash theme={null}
cd api-events
npm run test:e2e                  # starts infra + Encore if needed
npm run test:e2e:standalone       # assumes :4000 already up
```

Repo-root runner: `./api-events/scripts/run-encore-e2e.ps1`

Set `E2E_ENFORCE_COVERAGE=1` to fail when OpenAPI routes lack e2e hits (CI default in `api-events-deploy.yml`).

Event-chat CRUD against `tools/twilio-emulator` is gated by `E2E_EVENT_CHATS=1`. The `encore-e2e` job sets that flag and adds `event-chats` to `FEATURE_FLAG_OVERRIDES` against the in-repo emulator (never a real Twilio account). `tests/event-chats/routes-probe.test.ts` still registers coverage when the suite is skipped locally. See `e2e/README.md` and the [event chats runbook](./event-chats#ci-and-emulator-limits).

***

## Writing unit tests

Mock Prisma and external clients at module boundaries:

```typescript theme={null}
// updateVenueOperation.test.ts
import { vi } from 'vitest';

vi.mock('../../db/prisma', () => ({
  prisma: {
    venue: { update: vi.fn(), findUnique: vi.fn() },
  },
}));

import { updateVenueOperation } from './updateVenueOperation';

it('updates name when provided', async () => {
  // arrange mocks, call operation, assert result
});
```

See `.agents/skills/api-events-testing/SKILL.md` for project conventions (`vi.mock` paths, coverage expectations).

***

## Writing integration tests

Integration tests live beside operations (`*.integration.test.ts`) and hit real Postgres:

```typescript theme={null}
// userPositions.integration.test.ts
import { describe, it, expect, beforeAll } from 'vitest';
import { prisma } from '../../db/prisma';

beforeAll(async () => {
  // seed minimal fixture rows
});

it('returns positions for user', async () => {
  const result = await listUserPositionsOperation({ userId: '...' });
  expect(result).toHaveLength(1);
});
```

Run only after `test:integration:setup`.

***

## Coverage and CI gates

```bash theme={null}
cd api-events
npm run checks    # typecheck + lint + format + test
```

| Gate | Command | When |
| - | - | - |
| Unit tests | `npm test` (`npm run test:coverage` for a local report) | PR / local |
| OpenAPI contract | `npm run openapi:parity` | Route changes |
| E2E coverage | `E2E_ENFORCE_COVERAGE=1 npm run test:e2e` | Deploy pipeline |

E2E coverage reads the OpenAPI snapshot (`docs/openapi/soundcheck.json`) and reports hits in `e2e/coverage/endpoints.md`.

***

## Best practices

* **Unit** — mock Prisma and outbound clients; test operations directly (no Encore boot).
* **Integration** — isolate with ephemeral DB; clean fixtures per file.
* **E2E** — exercise real HTTP on `:4000`; add a spec when adding routes.
* **Naming** — colocate `*.test.ts` next to the module under test.

***

## Troubleshooting

> [accordion] Integration tests cannot connect
>
> Run setup and confirm ephemeral DB:
>
> ```bash theme={null}
> cd api-events && npm run test:integration:setup
> docker compose -p api -f dev/docker-compose.yml --profile ephemeral ps
> ```

> [accordion] E2E fails with connection refused
>
> Start infra + Encore:
>
> ```bash theme={null}
> npm run dev:infra
> cd api-events && npm run dev:emulator
> ```
>
> Or use `npm run test:e2e` which orchestrates the stack.

> [accordion] Coverage gate fails in CI
>
> Add an e2e hit for the new route or a justified waiver in `e2e/src/coverage/waivers.ts`. Exclusions in `coverageExclusions.ts` are retired — write coverage instead.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.