import { describe, it, expect, vi } from 'vitest'; // Mock db module vi.mock('./db', () => ({ getRequestById: vi.fn(), getAssociationByUserId: vi.fn(), getAssociationById: vi.fn(), getDocumentById: vi.fn(), getRequestHistoryByRequestId: vi.fn(), deleteRequest: vi.fn(), createAuditLog: vi.fn(), })); import * as db from './db'; describe('Request Detail & Delete Logic', () => { describe('getById enrichment', () => { it('should return associationInfo when association exists', async () => { const mockAssociation = { id: 1, nomAssociation: 'Association Test', siret: '12345678901234', adresse: '10 rue de la Paix', codePostal: '97300', ville: 'Cayenne', telephone: '0594123456', emailContact: 'test@asso.fr', nomRepresentant: 'Jean Dupont', }; (db.getAssociationById as any).mockResolvedValue(mockAssociation); const result = await db.getAssociationById(1); expect(result).toBeDefined(); expect(result?.nomAssociation).toBe('Association Test'); expect(result?.siret).toBe('12345678901234'); expect(result?.telephone).toBe('0594123456'); }); it('should return null when association does not exist', async () => { (db.getAssociationById as any).mockResolvedValue(null); const result = await db.getAssociationById(999); expect(result).toBeNull(); }); it('should resolve attached documents from documentsJoints JSON', async () => { const mockDoc1 = { id: 1, nom: 'Statuts', type: 'statuts', fileSize: 1024 }; const mockDoc2 = { id: 2, nom: 'RIB', type: 'rib', fileSize: 2048 }; (db.getDocumentById as any) .mockResolvedValueOnce(mockDoc1) .mockResolvedValueOnce(mockDoc2); const documentsJoints = JSON.stringify([1, 2]); const docIds = JSON.parse(documentsJoints) as number[]; const docs = await Promise.all( docIds.map(async (docId: number) => { const doc = await db.getDocumentById(docId); return doc || null; }) ); const attachedDocuments = docs.filter(Boolean); expect(attachedDocuments).toHaveLength(2); expect(attachedDocuments[0]?.nom).toBe('Statuts'); expect(attachedDocuments[1]?.nom).toBe('RIB'); }); it('should handle empty documentsJoints gracefully', () => { const documentsJoints = null; let attachedDocuments: any[] = []; if (documentsJoints) { try { const docIds = JSON.parse(documentsJoints) as number[]; // would process here } catch { // ignore } } expect(attachedDocuments).toHaveLength(0); }); it('should handle invalid JSON in documentsJoints', () => { const documentsJoints = 'not-json'; let attachedDocuments: any[] = []; if (documentsJoints) { try { const docIds = JSON.parse(documentsJoints) as number[]; attachedDocuments = docIds as any[]; } catch { // ignore parse errors } } expect(attachedDocuments).toHaveLength(0); }); }); describe('delete request', () => { it('should allow deletion of a brouillon request by the owning association', async () => { const mockRequest = { id: 1, associationId: 10, status: 'brouillon', titre: 'Ma demande', type: 'subvention_fonctionnement', }; const mockAssociation = { id: 10, userId: 5 }; (db.getRequestById as any).mockResolvedValue(mockRequest); (db.getAssociationByUserId as any).mockResolvedValue(mockAssociation); (db.deleteRequest as any).mockResolvedValue(undefined); // Simulate the logic const request = await db.getRequestById(1); const association = await db.getAssociationByUserId(5); expect(request).toBeDefined(); expect(association).toBeDefined(); expect(request!.associationId).toBe(association!.id); expect(request!.status).not.toBe('validee'); expect(request!.status).not.toBe('refusee'); await db.deleteRequest(1); expect(db.deleteRequest).toHaveBeenCalledWith(1); }); it('should reject deletion of a validated request', async () => { const mockRequest = { id: 2, associationId: 10, status: 'validee', titre: 'Demande validée', type: 'subvention_projet', }; (db.getRequestById as any).mockResolvedValue(mockRequest); const request = await db.getRequestById(2); expect(request!.status).toBe('validee'); // The router would throw a TRPCError here const canDelete = request!.status !== 'validee' && request!.status !== 'refusee'; expect(canDelete).toBe(false); }); it('should reject deletion of a refused request', async () => { const mockRequest = { id: 3, associationId: 10, status: 'refusee', titre: 'Demande refusée', type: 'demande_salle', }; (db.getRequestById as any).mockResolvedValue(mockRequest); const request = await db.getRequestById(3); const canDelete = request!.status !== 'validee' && request!.status !== 'refusee'; expect(canDelete).toBe(false); }); it('should reject deletion by a non-owning association', async () => { const mockRequest = { id: 4, associationId: 10, status: 'soumise', titre: 'Demande autre asso', type: 'autre', }; const mockAssociation = { id: 20, userId: 8 }; // Different association (db.getRequestById as any).mockResolvedValue(mockRequest); (db.getAssociationByUserId as any).mockResolvedValue(mockAssociation); const request = await db.getRequestById(4); const association = await db.getAssociationByUserId(8); // Association ID mismatch expect(request!.associationId).not.toBe(association!.id); }); it('should allow deletion of a submitted request', async () => { const mockRequest = { id: 5, associationId: 10, status: 'soumise', titre: 'Demande soumise', type: 'subvention_fonctionnement', }; (db.getRequestById as any).mockResolvedValue(mockRequest); (db.deleteRequest as any).mockResolvedValue(undefined); const request = await db.getRequestById(5); const canDelete = request!.status !== 'validee' && request!.status !== 'refusee'; expect(canDelete).toBe(true); await db.deleteRequest(5); expect(db.deleteRequest).toHaveBeenCalledWith(5); }); it('should allow deletion of a request in information_complementaire status', async () => { const mockRequest = { id: 6, associationId: 10, status: 'information_complementaire', titre: 'Demande info comp', type: 'agrement_sport', }; (db.getRequestById as any).mockResolvedValue(mockRequest); const request = await db.getRequestById(6); const canDelete = request!.status !== 'validee' && request!.status !== 'refusee'; expect(canDelete).toBe(true); }); }); });