118 lines
6.0 KiB
Markdown
118 lines
6.0 KiB
Markdown
---
|
|
phase: quick-260613-ndv
|
|
plan: "01"
|
|
subsystem: api/testing
|
|
tags: [test-isolation, mariadb, drizzle, vitest, globalSetup]
|
|
dependency_graph:
|
|
requires: []
|
|
provides: [familysync_test DB provisioning, local test isolation]
|
|
affects: [apps/api test suite, CI api job (unaffected — CI-gated)]
|
|
tech_stack:
|
|
added: []
|
|
patterns: [vitest globalSetup, drizzle-orm/mysql2 two-arg form]
|
|
key_files:
|
|
created:
|
|
- apps/api/test/global-setup.ts
|
|
modified:
|
|
- apps/api/vitest.config.ts
|
|
- apps/api/test/setup.ts
|
|
- apps/api/README.md
|
|
decisions:
|
|
- "D-ndv-pool-form: use drizzle(pool, { mode }) not drizzle({ client: pool, mode }) — drizzle-orm@0.45.2 isConfig() has a tautological OR in the mode branch that always returns false; combined-config form falls through to construct(configObj, undefined) making the config object itself the session client"
|
|
- "D-ndv-users-intact: do not delete users in afterEach — tests seed user id=1 once and reuse across test files; users starts empty in familysync_test at run start; per-test user leaks scoped to those tests' own setup"
|
|
metrics:
|
|
duration: "~15 min"
|
|
completed: "2026-06-13"
|
|
tasks_completed: 2
|
|
files_changed: 4
|
|
---
|
|
|
|
# Quick Task 260613-ndv: Test DB Isolation Summary
|
|
|
|
**One-liner:** vitest globalSetup provisions + migrates `familysync_test` via root MariaDB connection (CI-gated no-op); `test.env` forces workers to `DB_NAME=familysync_test`; 244 tests pass without touching the dev DB.
|
|
|
|
## Tasks Completed
|
|
|
|
| Task | Name | Commit | Key Files |
|
|
|------|------|--------|-----------|
|
|
| 1 | Add CI-gated globalSetup (provision + migrate familysync_test) | 8453b97 | apps/api/test/global-setup.ts (new), apps/api/vitest.config.ts |
|
|
| 2 | Clean-slate comment in setup.ts + README local-test docs | 4740d86 | apps/api/test/setup.ts, apps/api/README.md, apps/api/test/global-setup.ts (bug fix) |
|
|
|
|
## What Was Built
|
|
|
|
### apps/api/test/global-setup.ts (new, 108 lines)
|
|
|
|
Vitest `globalSetup` that runs once in the main process before any test file:
|
|
|
|
- **CI gate:** `if (process.env.CI) return` — CI provisions its own `familysync` service DB via `db:migrate`, completely unaffected.
|
|
- **Local flow:**
|
|
1. Root connection (`DB_ROOT_USER`/`DB_ROOT_PASSWORD` with dev defaults `root`/`root`) → `CREATE DATABASE IF NOT EXISTS familysync_test`
|
|
2. `GRANT ALL PRIVILEGES ON familysync_test.* TO '<appUser>'@'%'` with `appUser` validated against `/^[A-Za-z0-9_]+$/` (T-ndv-03); falls back to `@'localhost'` grant if `@'%'` fails.
|
|
3. `FLUSH PRIVILEGES`, close root connection.
|
|
4. App-user pool → `drizzle(pool, { mode: 'default' })` → `migrate(db, { migrationsFolder })` applies committed SQL from `apps/api/src/db/migrations/`.
|
|
5. Logs `[global-setup] provisioned + migrated familysync_test`.
|
|
|
|
### apps/api/vitest.config.ts (modified)
|
|
|
|
- Added `globalSetup: ['./test/global-setup.ts']`
|
|
- Added CI-gated `test.env`: locally sets `DB_NAME=familysync_test` and `DB_HOST=127.0.0.1`; under `CI` the env override is `{}` so job-level `DB_NAME=familysync` / `DB_HOST=mariadb` are preserved.
|
|
- Retained `fileParallelism: false` and `setupFiles: ['./test/setup.ts']`.
|
|
|
|
### apps/api/test/setup.ts (modified)
|
|
|
|
Updated file header to document:
|
|
- Tests now run against `familysync_test` (not dev `familysync`)
|
|
- `afterEach` truncates list/push tables only; `users` is intentionally left intact within a run
|
|
- Rationale for the `users` decision (no per-test deletion — tests seed id=1 once and reuse it)
|
|
|
|
### apps/api/README.md (modified)
|
|
|
|
Added `## Running API tests locally` section documenting:
|
|
- Dev MariaDB prerequisite + run command (`set -a; source .env; set +a; DB_HOST=127.0.0.1 pnpm --filter @familysync/api test`)
|
|
- `DB_ROOT_PASSWORD` requirement in `.env` for one-time provisioning
|
|
- CI unaffected note
|
|
|
|
## Deviations from Plan
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [Rule 1 - Bug] drizzle-orm@0.45.2 isConfig() mode branch tautology**
|
|
- **Found during:** Task 1 verification (first test run)
|
|
- **Issue:** `drizzle({ client: pool, mode: 'default' })` — the `{ client, mode }` combined config form — triggers a bug in `drizzle-orm@0.45.2/utils.js` `isConfig()`. The `mode` branch has: `if (data["mode"] !== "default" || data["mode"] !== "planetscale" || ...)` which is a tautological OR (always true for any mode value), so `isConfig` returns `false`. The call falls through to `construct(configObj, undefined)`, making the config object itself the session client. `client.query is not a function`.
|
|
- **Fix:** Switched to `drizzle(pool, { mode: 'default' })` (two-arg form, which hits the `construct(params[0], params[1])` branch directly — correct behavior). Added comment in the code explaining the drizzle-orm bug.
|
|
- **Files modified:** `apps/api/test/global-setup.ts`
|
|
- **Commit:** 4740d86
|
|
|
|
## Verification Results
|
|
|
|
| Check | Result |
|
|
|-------|--------|
|
|
| `grep -q "globalSetup" apps/api/vitest.config.ts` | PASS |
|
|
| `grep -q "familysync_test" apps/api/vitest.config.ts` | PASS |
|
|
| `grep -q "process.env.CI" apps/api/test/global-setup.ts` | PASS |
|
|
| `grep -q "migrate(" apps/api/test/global-setup.ts` | PASS |
|
|
| `pnpm --filter @familysync/api typecheck` | PASS (exit 0) |
|
|
| Full local test run (244 tests, 25 files) | PASS |
|
|
| Dev `familysync` users count before=3, after=3 | PASS |
|
|
| `familysync_test` tables after run | PASS (10 tables: all schema tables + __drizzle_migrations) |
|
|
| CI code inspection: globalSetup early-returns, env override is {} | PASS (confirmed by code) |
|
|
|
|
## Known Stubs
|
|
|
|
None.
|
|
|
|
## Threat Flags
|
|
|
|
None — no new network endpoints, auth paths, or file access patterns introduced. The root DB credential usage is scoped exclusively to the local non-CI branch of globalSetup and reads from env (T-ndv-01 mitigated as designed).
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- `apps/api/test/global-setup.ts` exists: confirmed
|
|
- `apps/api/vitest.config.ts` updated: confirmed
|
|
- `apps/api/test/setup.ts` updated: confirmed
|
|
- `apps/api/README.md` updated: confirmed
|
|
- Commit 8453b97 exists: confirmed (Task 1)
|
|
- Commit 4740d86 exists: confirmed (Task 2)
|
|
- 244/244 tests pass against familysync_test: confirmed
|
|
- Dev DB users count unchanged (3 before, 3 after): confirmed
|