portail-associations/server/requestDetail.test.ts

224 lines
7 KiB
TypeScript

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