Boots the real Nest app (Test.createTestingModule + AppModule) against a
real Postgres — no mocked DB or guards anywhere in this suite. Uses SWC
(unplugin-swc) instead of Vite's default esbuild transform because
esbuild doesn't implement emitDecoratorMetadata, which silently breaks
NestJS's constructor DI (every provider resolves to undefined).
Covers:
- auth.spec.ts: anti-enumeration login message, refresh-token rotation,
replay-detection revoking the whole session chain, idempotent logout
(ADR-0003).
- role-weight.spec.ts: invalid role_key on invite returns 400 not 500
(regression guard), lower-weight actor forbidden from assigning a
heavier role even when holding users:edit (ADR-0004).
- companies.spec.ts: CNPJ digit-check validation (reject/accept).
- mass-assignment.spec.ts: forbidNonWhitelisted actually rejects
unexpected fields on companies/products.
- reseller-assignment.spec.ts: assign-user always targets the URL's
:id, never a body resellerId (regression guard for commit 8d108e0);
unassign-user clears the assignment.
All fixtures are qa-test-/qa_ tagged and cleaned up (deactivated where
no DELETE endpoint exists, deleted where one does) — verified no
pre-existing seed data (super_admin, Handix Telecom LTDA, Handix revenda
própria) was touched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
61 lines
2.7 KiB
TypeScript
61 lines
2.7 KiB
TypeScript
import { readFileSync, existsSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
import { defineConfig } from "vitest/config";
|
|
import swc from "unplugin-swc";
|
|
|
|
/**
|
|
* These are integration tests, not unit tests — they need DATABASE_URL,
|
|
* JWT_SIGNING_SECRET, EDEN_SUPERADMIN_EMAIL/PASSWORD, etc. from the repo
|
|
* root `.env` (gitignored, never read by vitest automatically the way
|
|
* Next/Vite's client env loading does). Parsed by hand here (no `dotenv`
|
|
* dependency needed) and passed through `test.env` so it reaches the
|
|
* worker process(es) vitest actually runs specs in.
|
|
*/
|
|
function loadRootEnv(): Record<string, string> {
|
|
const envPath = resolve(__dirname, "../../.env");
|
|
if (!existsSync(envPath)) return {};
|
|
const out: Record<string, string> = {};
|
|
for (const line of readFileSync(envPath, "utf8").split("\n")) {
|
|
const trimmed = line.trim();
|
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
const eq = trimmed.indexOf("=");
|
|
if (eq === -1) continue;
|
|
out[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim();
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Integration test config (eden-qa). Every spec under test/ boots a real,
|
|
* fully-wired Nest app (Test.createTestingModule + AppModule) against a
|
|
* real Postgres — no mocked DB layer, per the eden-qa persona's rule.
|
|
* Timeout is generous (15s default) because some tests hit the DB several
|
|
* times in sequence and hash passwords with Argon2id (intentionally slow).
|
|
*/
|
|
export default defineConfig({
|
|
// NestJS's DI resolves constructor parameter types from
|
|
// `design:paramtypes` metadata emitted by the TS decorator-metadata
|
|
// transform. Vite's default esbuild transform does NOT implement
|
|
// `emitDecoratorMetadata` (esbuild is a single-file transformer with no
|
|
// type checker to resolve types from) — every @Injectable()/@Controller
|
|
// class would silently receive `undefined` for its dependencies instead
|
|
// of a real instance. Using SWC (which does implement it, matching
|
|
// `tsc`'s behavior) here is the standard fix for testing Nest apps with
|
|
// Vitest — see https://docs.nestjs.com/recipes/swc#vitest.
|
|
plugins: [swc.vite()],
|
|
test: {
|
|
environment: "node",
|
|
include: ["test/**/*.spec.ts"],
|
|
testTimeout: 15000,
|
|
hookTimeout: 15000,
|
|
// Integration tests share one real Postgres connection pool + one
|
|
// seeded super_admin account; running spec files in parallel worker
|
|
// processes risks session/role-cleanup races between files (e.g. two
|
|
// files both minting/deleting similarly-named throwaway roles). Runs
|
|
// sequentially, file by file — still fully real, just not concurrent.
|
|
fileParallelism: false,
|
|
globals: false,
|
|
env: { ...loadRootEnv(), ...process.env },
|
|
},
|
|
});
|