chore(quick-260613-ndv-02): clean-slate comment in setup.ts + README local-test docs
- Update apps/api/test/setup.ts header: clarify tests run against familysync_test
(provisioned by global-setup.ts), document users-cleanup decision (intact across
tests), and note CI-vs-local env difference
- Add apps/api/README.md "Running API tests locally" section: documents the test
DB isolation, run command, DB_ROOT_PASSWORD requirement, and CI no-op behaviour
- Fix apps/api/test/global-setup.ts: switch from drizzle({ client, mode }) to
drizzle(pool, { mode }) — drizzle-orm@0.45.2 isConfig() has a tautological OR
in the `mode` branch that always returns false, causing the combined-config form
to pass the config object as the client (client.query is not a function); two-arg
form routes correctly; 244/244 tests pass against familysync_test
This commit is contained in:
@@ -144,6 +144,26 @@ pnpm --filter @familysync/api typecheck
|
|||||||
|
|
||||||
Integration tests that hit MariaDB require a running dev DB with `DB_HOST=127.0.0.1` and credentials from your `.env`. See [../../docs/TESTING.md](../../docs/TESTING.md) for the full setup.
|
Integration tests that hit MariaDB require a running dev DB with `DB_HOST=127.0.0.1` and credentials from your `.env`. See [../../docs/TESTING.md](../../docs/TESTING.md) for the full setup.
|
||||||
|
|
||||||
|
## Running API tests locally
|
||||||
|
|
||||||
|
Local test runs use a dedicated `familysync_test` database so the dev `familysync` database is never mutated. `test/global-setup.ts` creates and migrates `familysync_test` automatically on the first run.
|
||||||
|
|
||||||
|
**Prerequisites:**
|
||||||
|
|
||||||
|
- Dev MariaDB running and port-bound (`127.0.0.1:3306`) — start with `docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d mariadb`
|
||||||
|
- `.env` sourced in your shell (provides `DB_PASSWORD`, `DB_ROOT_PASSWORD`, and other credentials)
|
||||||
|
|
||||||
|
**Run command:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
set -a; source .env; set +a
|
||||||
|
DB_HOST=127.0.0.1 pnpm --filter @familysync/api test
|
||||||
|
```
|
||||||
|
|
||||||
|
`DB_ROOT_PASSWORD` must be set in `.env` for the one-time `CREATE DATABASE` / `GRANT` that provisions `familysync_test`. Subsequent runs skip the provisioning step if the database already exists (`CREATE DATABASE IF NOT EXISTS`).
|
||||||
|
|
||||||
|
**CI is unaffected.** `test/global-setup.ts` returns immediately when `CI` is set (the CI `api` job provisions its own `familysync` service DB and runs `db:migrate` before the test step). The `test.env` DB override in `vitest.config.ts` is also a no-op under CI.
|
||||||
|
|
||||||
## Further reading
|
## Further reading
|
||||||
|
|
||||||
- [Architecture](../../docs/ARCHITECTURE.md) — system overview and component diagram
|
- [Architecture](../../docs/ARCHITECTURE.md) — system overview and component diagram
|
||||||
|
|||||||
@@ -80,23 +80,33 @@ export default async function setup(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Step 4: Apply committed migrations to familysync_test ──────────────────
|
// ── Step 4: Apply committed migrations to familysync_test ──────────────────
|
||||||
const appConn = await mysql.createConnection({
|
// Use a Pool (not a Connection) — drizzle-orm/mysql2 session.all() calls
|
||||||
|
// client.execute() and transaction() calls client.getConnection(), both of
|
||||||
|
// which are pool methods. createPool with connectionLimit:1 is the minimal form.
|
||||||
|
const appPool = mysql.createPool({
|
||||||
host,
|
host,
|
||||||
port,
|
port,
|
||||||
user: appUser,
|
user: appUser,
|
||||||
password: appPassword,
|
password: appPassword,
|
||||||
database: TEST_DB,
|
database: TEST_DB,
|
||||||
|
connectionLimit: 1,
|
||||||
multipleStatements: true, // required by drizzle migrator for multi-statement SQL files
|
multipleStatements: true, // required by drizzle migrator for multi-statement SQL files
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const db = drizzle({ client: appConn, mode: 'default' });
|
// Pass pool as the first arg + config as the second. Do NOT use the
|
||||||
|
// { client: pool, mode } combined-config form — drizzle-orm@0.45.2 has a
|
||||||
|
// bug in isConfig() where the `mode` branch always returns false (its OR
|
||||||
|
// condition is a tautology), so the combined form falls through to
|
||||||
|
// construct({ client, mode }, undefined) and the session client becomes
|
||||||
|
// the plain config object (no .query()). The two-arg form is safe.
|
||||||
|
const db = drizzle(appPool, { mode: 'default' });
|
||||||
const migrationsFolder = fileURLToPath(
|
const migrationsFolder = fileURLToPath(
|
||||||
new URL('../src/db/migrations', import.meta.url),
|
new URL('../src/db/migrations', import.meta.url),
|
||||||
);
|
);
|
||||||
await migrate(db, { migrationsFolder });
|
await migrate(db, { migrationsFolder });
|
||||||
} finally {
|
} finally {
|
||||||
await appConn.end();
|
await appPool.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[global-setup] provisioned + migrated familysync_test');
|
console.log('[global-setup] provisioned + migrated familysync_test');
|
||||||
|
|||||||
+17
-10
@@ -1,18 +1,25 @@
|
|||||||
/**
|
/**
|
||||||
* Vitest global test setup for apps/api.
|
* Vitest per-file test setup for apps/api.
|
||||||
*
|
*
|
||||||
* Establishes shared test infrastructure for API tests:
|
* Tests now run against the isolated `familysync_test` database, which is
|
||||||
* - DB pool access via the existing client.ts (DB_HOST/DB_NAME from env)
|
* auto-provisioned and migrated by `test/global-setup.ts` before the suite
|
||||||
* - Per-test cleanup for list tables (truncate between tests so state is isolated)
|
* starts. The dev `familysync` database is never touched by a local test run.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Cleanup strategy:
|
||||||
* This file is referenced in vitest.config.ts via test.setupFiles.
|
* - afterEach truncates list/push tables in FK-safe order so each test
|
||||||
* Pure-logic tests (listEmitter, fractional rank) do NOT require DB — the
|
* starts with a clean slate for those tables.
|
||||||
* cleanup function is a no-op when the tables are empty.
|
* - `users` is intentionally left intact across tests within a single run.
|
||||||
|
* Many tests seed user id=1 once and reuse it; deleting users between tests
|
||||||
|
* would break FK-dependent rows mid-suite. The globalSetup provides a fresh
|
||||||
|
* migrated `familysync_test` at run start, so `users` starts empty and any
|
||||||
|
* seed inserted by the first test that needs it persists for the session.
|
||||||
|
* If a specific test leaks `users` rows that affect another test, scope a
|
||||||
|
* targeted delete inside that test's own beforeEach/afterEach instead.
|
||||||
*
|
*
|
||||||
* Environment:
|
* Environment:
|
||||||
* Set DB_HOST, DB_USER, DB_PASSWORD, DB_NAME in the test environment.
|
* DB_HOST, DB_USER, DB_PASSWORD, and DB_NAME=familysync_test are injected by
|
||||||
* Tests run against a local MariaDB dev database; production data is never touched.
|
* vitest.config.ts (test.env) for local runs. Under CI, DB_NAME=familysync is
|
||||||
|
* preserved from the job-level env and globalSetup is a no-op.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { afterEach } from 'vitest';
|
import { afterEach } from 'vitest';
|
||||||
|
|||||||
Reference in New Issue
Block a user