mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
bun loads a plain `.env` into process.env before anything runs, and tests/helpers/env.ts read that as a deliberate export, so it beat `.env.test` outright. `scripts/test.sh api` therefore pointed the api suites at whatever deployment `.env` describes: `prisma db push --accept-data-loss` for the schema, then a truncate of every table between tests. The e2e half was worse, because playwright.config.ts built and started the app with that DATABASE_URL and those R2 credentials, then wrote fixtures into it. CI never saw any of this: a runner has no `.env`. Three changes, in order of what each one catches: - helpers/dev-env.ts drops the values bun copied out of a development env file, leaving `.env.test` to fill them. Only values that match the file character-for-character go, so a real export still wins and the per-suite databases of a parallel api run keep working. - helpers/test-database.ts refuses a DATABASE_URL whose database name is not marked as a test one, at the single point every path into the setup passes through. This is the backstop, not the fix. - playwright.config.ts blanks the variables a development env file defines and the config does not. Dropping them from process.env is not enough there: `next build` and `next start` run @next/env themselves and read the files again. That is also why a local e2e run could not build at all (a set DISABLE_RATE_LIMIT throws in lib/rate-limit.ts under NODE_ENV=production) and why auth.spec.ts failed on a machine with SMTP configured. `scripts/test.sh` now creates `.env.test` from the committed example instead of asking for a one-line copy, so the guard above is something nobody has to meet.
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
// Loads `.env.test` into `process.env`.
|
|
//
|
|
// This module exists so it can be the *first* import of both
|
|
// `tests/setup/api.ts` and `tests/setup/db-global.ts`. ESM evaluates imports in
|
|
// source order, so putting `import '../helpers/env';` above everything else
|
|
// guarantees DATABASE_URL is set before `@/lib/db` is reached: that module reads
|
|
// `process.env.DATABASE_URL` once at import time and memoizes the pg pool on
|
|
// `globalThis`, so a late load would silently point every test at the wrong
|
|
// database (or at no database at all).
|
|
//
|
|
// It must therefore never import from `@/lib/*`.
|
|
//
|
|
// Contract: an already-exported variable always wins. `.env.test` fills the
|
|
// gaps. That is what lets CI export DATABASE_URL for a service container
|
|
// without needing a `.env.test` file at all.
|
|
//
|
|
// With one correction, see forgetAutoloadedDotenv in helpers/dev-env.ts: bun
|
|
// populates process.env from a plain `.env` before any of this runs, which the
|
|
// contract above would otherwise read as a deliberate export.
|
|
|
|
import fs from 'node:fs';
|
|
import { config as loadDotenv } from 'dotenv';
|
|
|
|
import { forgetAutoloadedDotenv, REPO_ROOT, TEST_ENV_PATH } from './dev-env';
|
|
import { assertTestDatabase } from './test-database';
|
|
|
|
export { REPO_ROOT, TEST_ENV_PATH };
|
|
|
|
let loaded = false;
|
|
|
|
export function loadTestEnv(): void {
|
|
if (loaded) return;
|
|
loaded = true;
|
|
|
|
forgetAutoloadedDotenv();
|
|
|
|
if (fs.existsSync(TEST_ENV_PATH)) {
|
|
loadDotenv({ path: TEST_ENV_PATH, quiet: true });
|
|
}
|
|
|
|
if (!process.env.DATABASE_URL) {
|
|
throw new Error(
|
|
'DATABASE_URL is not set for the api test project. Either create .env.test ' +
|
|
'(cp .env.test.example .env.test) or export DATABASE_URL before running ' +
|
|
'bun run test:api.'
|
|
);
|
|
}
|
|
|
|
// Deliberately after the file load and before anything opens a pool: this is
|
|
// the one place every path into the test setup goes through.
|
|
assertTestDatabase(process.env.DATABASE_URL);
|
|
|
|
// Vitest sets this already, but db-global.ts also spawns the Prisma CLI and
|
|
// lib/rate-limit.ts throws when DISABLE_RATE_LIMIT is set in production.
|
|
// @types/node declares NODE_ENV as read-only, hence the cast.
|
|
if (!process.env.NODE_ENV) {
|
|
(process.env as Record<string, string | undefined>).NODE_ENV = 'test';
|
|
}
|
|
}
|
|
|
|
loadTestEnv();
|