224 lines
7 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|