import assert from "node:assert/strict"; import { randomUUID } from "node:crypto"; import type { Sequelize } from "sequelize"; import { QueryTypes } from "sequelize"; type Request = (path: string, body?: unknown) => Promise; export async function verifyRecordDeletion(request: Request, database: Sequelize) { const counts = async () => { const result: number[] = []; for (const table of [ "company_contacts", "assets", "resources", "work_profiles", "access_items", "mailbox_uses", ]) { const rows = await database.query<{ count: number }>( `SELECT COUNT(*) AS count FROM ${table}`, { type: QueryTypes.SELECT } ); result.push(Number(rows[0]?.count)); } return result; }; const folderSubjects = await database.query<{ profileId: string; companyId: string; needId: string; actorId: string; }>( "SELECT p.id AS profileId,p.companyId,i.id AS needId,u.id AS actorId FROM work_profiles p JOIN access_workspaces w ON w.companyId=p.companyId JOIN access_items i ON i.workspaceId=w.id CROSS JOIN users u WHERE JSON_UNQUOTE(JSON_EXTRACT(i.`values`, '$.kind'))='need' LIMIT 1", { type: QueryTypes.SELECT } ); const subject = folderSubjects[0]; assert.ok(subject, "Debe existir un perfil y una necesidad de recurso para la prueba de carpeta"); const mappingId = randomUUID(); const values = JSON.stringify({ profileId: subject.profileId, needId: subject.needId, path: "\\\\SERVER\\Test", driveLetter: null, state: "pending", notes: null, }); await database.query( "INSERT INTO folder_mappings (id,companyId,profileId,needId,`values`,currentKey,driveKey) VALUES (:id,:companyId,:profileId,:needId,:values,:currentKey,NULL)", { replacements: { ...subject, id: mappingId, values, currentKey: `${subject.profileId}:${subject.needId}`, }, } ); await database.query( "INSERT INTO folder_mapping_revisions (id,mappingId,position,`values`,actorId,recordedAt) VALUES (:id,:mappingId,0,:values,:actorId,:recordedAt)", { replacements: { id: randomUUID(), mappingId, values, actorId: subject.actorId, recordedAt: new Date().toISOString(), }, } ); const before = await counts(); const specs = [ [ "application_configurations", "application_configuration_revisions", "configurationId", "application-configurations", ], [ "certificate_configurations", "certificate_configuration_revisions", "configurationId", "certificate-configurations", ], [ "printer_configurations", "printer_configuration_revisions", "configurationId", "printer-configurations", ], [ "mail_configurations", "mail_configuration_revisions", "configurationId", "mail-configurations", ], ["folder_mappings", "folder_mapping_revisions", "mappingId", "folder-mappings"], ["asset_support", "asset_support_revisions", "connectionId", "asset-support"], ["asset_relationships", null, null, "assets"], ] as const; for (const [table, history, foreignKey, endpoint] of specs) { const rows = await database.query<{ id: string; companyId: string; assetId?: string }>( `SELECT * FROM ${table}`, { type: QueryTypes.SELECT } ); assert.ok(rows.length > 0, `No existen datos para probar ${table}`); // Todos los estados, incluidos los cerrados, admiten corregir un alta equivocada. for (const row of rows) { const suffix = endpoint === "asset-support" ? `${row.assetId}/${row.id}` : endpoint === "assets" ? `relationships/${row.id}` : row.id; const path = `/${endpoint}/${row.companyId}/${suffix}/delete`; assert.equal( (await request(`/${endpoint}/${randomUUID()}/${suffix}/delete`, {})).status, 404 ); assert.equal((await request(path.replace(row.companyId, "invalid"), {})).status, 400); assert.equal((await request(path, { unexpected: true })).status, 400); assert.equal((await request(path, {})).status, 200); assert.equal((await request(path, {})).status, 404); const remaining = await database.query(`SELECT id FROM ${table} WHERE id=:id`, { replacements: { id: row.id }, type: QueryTypes.SELECT, }); assert.equal(remaining.length, 0); if (history && foreignKey) { const revisions = await database.query( `SELECT id FROM ${history} WHERE ${foreignKey}=:id`, { replacements: { id: row.id }, type: QueryTypes.SELECT } ); assert.equal(revisions.length, 0); } } } assert.deepEqual(await counts(), before, "La eliminación debe conservar las entidades de origen"); }