import assert from "node:assert/strict"; import { test } from "node:test"; import { configureCsrfTokenReader } from "@metis/core/client"; import { COMPANY_LOGO_LIMITS, COMPANY_LOGO_TYPES } from "../../common"; import { getAccess } from "../access/list/api"; import { saveAccess } from "../access/shared/api"; import { validateCompanyLogo } from "../companies/change-logo/helpers"; import { getCompany } from "../companies/detail/api"; import { listCompanies } from "../companies/list/api"; import { saveMailboxUse } from "../mailbox-uses/shared/api"; import { getMailboxes } from "../mailboxes/list/api"; import { buildPersonRequest } from "../people/shared/adapters"; import { buildProcessTemplateInput } from "../process-templates/shared/adapters"; import { buildSiteRequest } from "../sites/shared/adapters"; const COMPANY_ID = "e0420eb9-2aab-4368-96a0-2ce83dd23eb4"; test("las consultas de compañías conservan sus rutas y rechazan respuestas inválidas", async (context) => { context.after(configureCsrfTokenReader(() => "a".repeat(64))); context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => { assert.equal(options.method, "GET"); if (url === "/api/companies") { return Response.json({ companies: [] }); } assert.equal(url, `/api/companies/${COMPANY_ID}`); return Response.json({ company: { id: COMPANY_ID } }); }); assert.deepEqual(await listCompanies(), { companies: [] }); await assert.rejects(getCompany(COMPANY_ID)); }); test("lectura y guardado de accesos están separados sin cambiar el contrato HTTP", async (context) => { context.after(configureCsrfTokenReader(() => "a".repeat(64))); const calls: { url: unknown; options: RequestInit }[] = []; context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => { calls.push({ url, options }); return Response.json({ items: [], reviews: [], coverage: [] }); }); await getAccess("global"); const values = { kind: "system", name: "Directory", active: true } as const; await saveAccess("global", values, COMPANY_ID); assert.deepEqual( calls.map((call) => call.url), ["/api/access/global", `/api/access/global/${COMPANY_ID}/update`] ); assert.equal(calls[0]?.options.method, "GET"); const save = calls[1]?.options; assert.ok(save); assert.equal(save.method, "POST"); assert.equal(save.body, JSON.stringify({ values })); assert.equal(new Headers(save.headers).get("x-csrf-token"), "a".repeat(64)); }); test("el guardado de usos de buzón mantiene su endpoint y no se confunde con la consulta", async (context) => { context.after(configureCsrfTokenReader(() => "a".repeat(64))); const calls: { url: unknown; options: RequestInit }[] = []; context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => { calls.push({ url, options }); return Response.json({ mailboxes: [], uses: [] }); }); await getMailboxes(COMPANY_ID); const values = { mailboxId: COMPANY_ID, personId: COMPANY_ID, startDate: "2026-10-09", endDate: null, }; await saveMailboxUse(COMPANY_ID, values, COMPANY_ID); assert.deepEqual( calls.map((call) => call.url), [`/api/mailboxes/${COMPANY_ID}`, `/api/mailboxes/${COMPANY_ID}/uses/${COMPANY_ID}/update`] ); assert.equal(calls[0]?.options.method, "GET"); assert.equal(calls[1]?.options.method, "POST"); assert.equal(calls[1]?.options.body, JSON.stringify({ values })); }); test("los adapters mantienen la ausencia semántica sin modificar los campos del formulario", () => { const person = { name: "Ana", position: " ", email: " ana@example.test ", phone: "", active: false, isContact: true, }; const request = buildPersonRequest(person); assert.equal(request.position, null); assert.equal(request.email, "ana@example.test"); assert.equal(request.phone, null); assert.equal(request.active, false); assert.equal(person.email, " ana@example.test "); assert.deepEqual( buildSiteRequest({ active: true, name: "Office", address: " ", phone: " " }), { active: true, name: "Office", address: null, phone: null, } ); const site = buildSiteRequest({ active: true, name: "Office", address: " Street\n Floor ", phone: " +34 900 123 456 ", }); assert.equal(site.address, " Street\n Floor "); assert.equal(site.phone, " +34 900 123 456 "); }); test("las instrucciones de proceso conservan el orden y excluyen líneas vacías", () => { const values = { name: "Starter", kind: "onboarding", active: true, notes: null, lines: " First\n\n Second \r\n ", } as const; assert.deepEqual(buildProcessTemplateInput(values).instructions, ["First", "Second"]); assert.equal(values.lines, " First\n\n Second \r\n "); assert.deepEqual(buildProcessTemplateInput({ ...values, lines: "\n " }).instructions, []); }); test("la validación de logos conserva tipos permitidos, vacío y límite exacto de tamaño", () => { for (const type of COMPANY_LOGO_TYPES) { assert.equal(validateCompanyLogo({ type, size: COMPANY_LOGO_LIMITS.inputBytes }), null); assert.equal(validateCompanyLogo({ type, size: 0 }), "LOGO_TOO_LARGE"); assert.equal( validateCompanyLogo({ type, size: COMPANY_LOGO_LIMITS.inputBytes + 1 }), "LOGO_TOO_LARGE" ); } assert.equal(validateCompanyLogo({ type: "image/svg+xml", size: 1 }), "INVALID_LOGO"); });