Files
CapaKraken/packages/db/src/load-workspace-env.test.ts
T
Hartmut 72471e89b8
CI / Architecture Guardrails (push) Successful in 2m42s
CI / Assistant Split Regression (push) Successful in 4m4s
CI / Lint (push) Successful in 4m16s
CI / Typecheck (push) Successful in 5m20s
CI / Unit Tests (push) Failing after 6m40s
CI / Build (push) Successful in 5m3s
CI / Release Images (push) Has been cancelled
CI / Fresh-Linux Docker Deploy (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
test(db): clear env before each loadWorkspaceEnv test, not just after
CI inherits DATABASE_URL from the outer shell (capakraken_test URL).
loadWorkspaceEnv uses dotenv semantics — pre-existing process.env wins
over .env file contents — so the first test's assertion
'DATABASE_URL === postgres://from-env' failed only in CI. Moving
clearEnv into beforeEach makes the test order-independent and
immune to inherited env. Reproduced by running the suite locally
with DATABASE_URL exported.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-12 21:08:37 +02:00

97 lines
3.3 KiB
TypeScript

import { afterEach, beforeEach, describe, it } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { loadWorkspaceEnv, resolveWorkspaceEnvPaths } from "./load-workspace-env.js";
const envKeys = ["DATABASE_URL", "SHARED_VALUE", "LOCAL_ONLY", "MODE_ONLY", "MODE_LOCAL_ONLY"];
function clearEnv() {
for (const key of envKeys) {
delete process.env[key];
}
}
function withTempWorkspace(run: (workspaceRoot: string) => void) {
const workspaceRoot = mkdtempSync(join(tmpdir(), "capakraken-env-"));
try {
run(workspaceRoot);
} finally {
rmSync(workspaceRoot, { recursive: true, force: true });
}
}
// Clear before each test too: CI inherits DATABASE_URL from the outer shell,
// and loadWorkspaceEnv (parseFile + process.env fallback) will read the
// pre-existing shell value instead of the .env file under test.
beforeEach(() => {
clearEnv();
delete process.env.NODE_ENV;
});
afterEach(() => {
clearEnv();
delete process.env.NODE_ENV;
});
describe("loadWorkspaceEnv", () => {
it("loads standard workspace env files in precedence order", () => {
withTempWorkspace((workspaceRoot) => {
writeFileSync(
join(workspaceRoot, ".env"),
"DATABASE_URL=postgres://from-env\nSHARED_VALUE=base\n",
);
writeFileSync(
join(workspaceRoot, ".env.development"),
"SHARED_VALUE=mode\nMODE_ONLY=development\n",
);
writeFileSync(join(workspaceRoot, ".env.local"), "SHARED_VALUE=local\nLOCAL_ONLY=1\n");
writeFileSync(
join(workspaceRoot, ".env.development.local"),
"SHARED_VALUE=mode-local\nMODE_LOCAL_ONLY=1\n",
);
process.env.NODE_ENV = "development";
const loadedPaths = loadWorkspaceEnv({ workspaceRoot });
assert.deepEqual(
loadedPaths.map((entry) => entry.slice(workspaceRoot.length + 1)),
[".env", ".env.development", ".env.local", ".env.development.local"],
);
assert.equal(process.env.DATABASE_URL, "postgres://from-env");
assert.equal(process.env.SHARED_VALUE, "mode-local");
assert.equal(process.env.LOCAL_ONLY, "1");
assert.equal(process.env.MODE_ONLY, "development");
assert.equal(process.env.MODE_LOCAL_ONLY, "1");
});
});
it("does not override variables that already exist in the shell environment", () => {
withTempWorkspace((workspaceRoot) => {
writeFileSync(join(workspaceRoot, ".env"), "DATABASE_URL=postgres://from-env\n");
writeFileSync(join(workspaceRoot, ".env.local"), "DATABASE_URL=postgres://from-local\n");
process.env.DATABASE_URL = "postgres://from-shell";
loadWorkspaceEnv({ workspaceRoot });
assert.equal(process.env.DATABASE_URL, "postgres://from-shell");
});
});
it("returns the candidate env paths even when files are missing", () => {
withTempWorkspace((workspaceRoot) => {
process.env.NODE_ENV = "test";
const envPaths = resolveWorkspaceEnvPaths({ workspaceRoot });
assert.deepEqual(
envPaths.map((entry) => entry.slice(workspaceRoot.length + 1)),
[".env", ".env.test", ".env.local", ".env.test.local"],
);
assert.deepEqual(loadWorkspaceEnv({ workspaceRoot }), []);
});
});
});