Files
eden/apps/api/vitest.config.ts
Matheus (Handix) cdafb7f853 test(api): add Vitest+supertest integration test suite (eden-qa)
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>
2026-09-03 11:14:43 -03:00

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 },
},
});