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>
66 lines
2.5 KiB
TypeScript
66 lines
2.5 KiB
TypeScript
import { INestApplication } from "@nestjs/common";
|
|
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
import { agent, bearer, closeTestApp, createTestApp, loginSuperAdmin, type AuthedTokens } from "./setup.js";
|
|
|
|
/**
|
|
* Protects the CNPJ digit-check invariant in
|
|
* apps/api/src/companies/companies.service.ts (assertValidCnpjIfPresent ->
|
|
* @eden/domain-shared's isValidCNPJ) — format validation only, per that
|
|
* function's own doc comment ("never confirms a document actually exists
|
|
* or belongs to whoever claims it").
|
|
*
|
|
* The valid-CNPJ fixture uses 11.444.777/0001-61 — verified against the
|
|
* same digit-check algorithm (packages/domain-shared/src/validators/
|
|
* br-documents.ts) before writing this test, and confirmed (by querying
|
|
* the shared dev Postgres directly) NOT already used by any company row,
|
|
* unlike 11.222.333/0001-81 which the seeded "Handix Telecom LTDA" company
|
|
* already holds.
|
|
*
|
|
* Cleanup: there is no DELETE /v1/companies endpoint, so the company
|
|
* created by the "valid CNPJ succeeds" test is deactivated
|
|
* (PATCH isActive:false) in afterAll rather than deleted.
|
|
*/
|
|
describe("companies — CNPJ validation invariant", () => {
|
|
let app: INestApplication;
|
|
let admin: AuthedTokens;
|
|
let createdCompanyId: string | undefined;
|
|
|
|
beforeAll(async () => {
|
|
app = await createTestApp();
|
|
admin = await loginSuperAdmin(app);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
if (createdCompanyId) {
|
|
await agent(app)
|
|
.patch(`/api/v1/companies/${createdCompanyId}`)
|
|
.set(...bearer(admin.accessToken))
|
|
.send({ isActive: false })
|
|
.expect(200);
|
|
}
|
|
await closeTestApp(app);
|
|
});
|
|
|
|
it("rejects a CNPJ that fails the check-digit algorithm with 400", async () => {
|
|
const res = await agent(app)
|
|
.post("/api/v1/companies")
|
|
.set(...bearer(admin.accessToken))
|
|
.send({ companyName: "qa-test- Empresa CNPJ Inválido", cnpj: "11.222.333/0001-00" })
|
|
.expect(400);
|
|
expect(res.body.message).toContain("CNPJ inválido");
|
|
});
|
|
|
|
it("accepts a company with a valid, not-already-used CNPJ", async () => {
|
|
const res = await agent(app)
|
|
.post("/api/v1/companies")
|
|
.set(...bearer(admin.accessToken))
|
|
.send({ companyName: "qa-test- Empresa CNPJ Válido", cnpj: "11.444.777/0001-61" })
|
|
.expect(201);
|
|
|
|
expect(res.body.id).toBeTypeOf("string");
|
|
// Persisted digits-only, per companies.service.ts's onlyDigits(dto.cnpj).
|
|
expect(res.body.cnpj).toBe("11444777000161");
|
|
createdCompanyId = res.body.id;
|
|
});
|
|
});
|