Files
planflow/tests/unit/env.test.ts
T
Claude dd639a86f5 WP-00: application foundation
Scaffolds the project: Next.js 16 App Router with strict TypeScript,
Prisma 7 on PostgreSQL 16, Tailwind 4, Vitest, Playwright, CI, and a
standalone Docker image that applies migrations on boot.

Makes the no-tracker rule of PLAN.md 3.7 enforceable rather than
stated. A per-request nonce-based CSP names no external origin, a unit
test fails if any network directive gains one, and a second test fails
if a tracking package appears in package.json. The end-to-end test
drives the standalone server the Docker image runs, not `next dev`,
so a proxy matcher that stopped matching could not pass unnoticed.

Environment is validated at import, so a missing DATABASE_URL fails at
boot with a readable message instead of surfacing later as a driver
error mid-export. ENCRYPTION_KEY is checked to be 32 bytes.

Three deviations from the plan, recorded in PLAN.md and README:
Next 16 rather than 15, `proxy.ts` rather than the now-deprecated
`middleware.ts`, and database-backed sessions rather than Auth.js v5,
which is still beta and whose JWTs would make the session revocation
required by compliance item 23 awkward.

Verified locally against PostgreSQL 16: migrations apply, extensions
created, typecheck, lint, 9 unit tests and the end-to-end header test
all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 17:54:11 +00:00

50 lines
1.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it, vi } from 'vitest';
/**
* The env module validates at import, so each case needs a fresh module
* registry with process.env set beforehand.
*/
async function loadEnv(values: Record<string, string | undefined>) {
const previous = { ...process.env };
process.env = { ...previous, ...values } as NodeJS.ProcessEnv;
try {
vi.resetModules();
return await import('@/lib/env');
} finally {
process.env = previous;
}
}
const VALID_KEY = Buffer.alloc(32, 7).toString('base64');
describe('configuration d’environnement', () => {
it('accepte une configuration complète', async () => {
const { env } = await loadEnv({
DATABASE_URL: 'postgresql://user:pass@localhost:5432/planflow',
ENCRYPTION_KEY: VALID_KEY,
APP_URL: 'https://planflow.example',
});
expect(env.DATABASE_URL).toContain('planflow');
expect(env.APP_URL).toBe('https://planflow.example');
});
it('refuse une clé de chiffrement qui ne fait pas 32 octets', async () => {
await expect(
loadEnv({
DATABASE_URL: 'postgresql://user:pass@localhost:5432/planflow',
ENCRYPTION_KEY: Buffer.alloc(16, 1).toString('base64'),
}),
).rejects.toThrow(/ENCRYPTION_KEY/);
});
it('refuse une URL de base non PostgreSQL', async () => {
await expect(
loadEnv({
DATABASE_URL: 'mysql://user:pass@localhost:3306/planflow',
ENCRYPTION_KEY: VALID_KEY,
}),
).rejects.toThrow(/DATABASE_URL/);
});
});