# Environment for the `api` Vitest project. Copy to `.env.test` (gitignored): # cp .env.test.example .env.test # # `tests/setup/db-global.ts` and `tests/setup/api.ts` both load this file (via # `tests/helpers/env.ts`) before anything imports `@/lib/db`, which reads # DATABASE_URL once at module load and memoizes the pool. An already-exported # variable always wins over the file, so CI can override DATABASE_URL without # editing anything. # --------------------------------------------------------------------------- # DATABASE # --------------------------------------------------------------------------- # The default targets the container-to-container hostname, because the test # runner itself runs in a container attached to the `openframe-test` network: # podman compose -f docker-compose.test.yml up -d # podman run --rm --network openframe-test -v "$PWD":/workspace:z -w /workspace \ # docker.io/oven/bun:alpine sh -c "bun run test:api" DATABASE_URL="postgresql://openframe:openframe@postgres-test:5432/openframe_test?schema=public" # From the host instead (psql, or a runner that is not on that network), use the # published port: # DATABASE_URL="postgresql://openframe:openframe@127.0.0.1:55432/openframe_test?schema=public" # # On GitHub Actions, where Postgres is a service container on the job network: # DATABASE_URL="postgresql://openframe:openframe@localhost:5432/openframe_test?schema=public" # --------------------------------------------------------------------------- # AUTH # --------------------------------------------------------------------------- # `auth()` is mocked in tests, so NEXTAUTH_SECRET is only used for real work by # lib/share-session.ts, which HMAC-signs the share cookies. NEXTAUTH_URL="http://localhost:3000" NEXTAUTH_SECRET="test-secret-not-used-for-anything-real" NEXT_PUBLIC_APP_URL="http://localhost:3000" # --------------------------------------------------------------------------- # FEATURE FLAGS # --------------------------------------------------------------------------- # Stripe on, because that is what production runs and because it is what arms # every billing gate: hasBillingAccess() short-circuits to `true` when the flag # is off, which would silently neuter the whole access-control surface. Tests # that want the self-hosted behaviour stub the flag off per test. OPENFRAME_ENABLE_STRIPE="true" # Dummy credentials so isStripeBillingEnabled() is true and getStripePriceId() # does not throw. `@/lib/stripe` is module-mocked, so no request ever leaves. STRIPE_SECRET_KEY="sk_test_openframe_dummy" STRIPE_PRICE_ID="price_test_openframe_dummy" STRIPE_WEBHOOK_SECRET="whsec_test_openframe_dummy" OPENFRAME_REQUIRE_INVITE_CODE="true" INVITE_CODE="test-invite" # Direct-upload providers are deliberately left unconfigured, so # isDirectFileUploadEnabled() is false by default. Suites that exercise the # presigned-upload routes stub R2_* / BUNNY_* in per test. # No proxy in front of the test runner, so getClientIp() returns 127.0.0.1. TRUSTED_PROXY_MODE="none" # Rate limits are DB-backed and keyed on the client IP, which is that same # constant for every request in the suite. Left on, one test exhausting a # window would make the next test's 429 look like a passing authorization # check. tests/api/rate-limit.test.ts re-enables it with vi.stubEnv (the flag # is read per call, not at import) and is the only place that asserts on it. DISABLE_RATE_LIMIT="true" # SMTP is configured on purpose: isEmailVerificationEnabled() is derived from # these three variables, and with them unset the register/verify routes take a # different branch than production does. `nodemailer` is module-mocked in # tests/setup/api.ts, so nothing leaves the process; the messages are captured # and assertable through tests/helpers/mail.ts. SMTP_HOST="localhost" SMTP_PORT="1025" SMTP_USER="test" SMTP_PASSWORD="test" SMTP_FROM="OpenFrame Test " NODE_ENV="test"