import { describe, it, expect, vi, beforeEach } from 'vitest'; // Mock db module vi.mock('./db', () => ({ getRequestById: vi.fn(), updateRequestSalles: vi.fn(), createRequestHistory: vi.fn(), getAssociationById: vi.fn(), getApprovedReservations: vi.fn(), })); // Mock notification vi.mock('./_core/notification', () => ({ notifyOwner: vi.fn().mockResolvedValue(true), })); import * as db from './db'; import { notifyOwner } from './_core/notification'; describe('Calendrier des réservations - Backend', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('getApprovedReservations', () => { it('should return approved reservations with association info', async () => { const mockReservations = [ { id: 1, associationId: 10, type: 'demande_salle', titre: 'Réservation Salle TOUCAN', status: 'validee', formData: JSON.stringify({ sallesSelectionnees: ['Salle TOUCAN'], dateReservation: '2026-04-15', heureDebut: '09:00', heureFin: '17:00', motifReservation: 'AG annuelle', }), associationName: 'Association Test', associationEmail: 'test@asso.fr', createdAt: new Date('2026-03-01'), }, { id: 2, associationId: 11, type: 'demande_salle', titre: 'Réservation DOJO', status: 'validee', formData: JSON.stringify({ sallesSelectionnees: ['DOJO'], dateReservation: '2026-04-20', heureDebut: '18:00', heureFin: '20:00', motifReservation: 'Entraînement', }), associationName: 'Club Judo', associationEmail: 'judo@club.fr', createdAt: new Date('2026-03-05'), }, ]; vi.mocked(db.getApprovedReservations).mockResolvedValue(mockReservations as any); const result = await db.getApprovedReservations(); expect(result).toHaveLength(2); expect(result[0].associationName).toBe('Association Test'); expect(result[1].associationName).toBe('Club Judo'); }); it('should return empty array when no approved reservations', async () => { vi.mocked(db.getApprovedReservations).mockResolvedValue([]); const result = await db.getApprovedReservations(); expect(result).toHaveLength(0); }); }); describe('changeSalles - logic simulation', () => { it('should update salles in formData correctly', async () => { const existingRequest = { id: 1, type: 'demande_salle', associationId: 10, status: 'validee', formData: JSON.stringify({ sallesSelectionnees: ['Salle TOUCAN'], sallesIds: ['salle_toucan'], dateReservation: '2026-04-15', heureDebut: '09:00', heureFin: '17:00', }), }; vi.mocked(db.getRequestById).mockResolvedValue(existingRequest as any); vi.mocked(db.updateRequestSalles).mockResolvedValue(undefined); vi.mocked(db.createRequestHistory).mockResolvedValue(undefined as any); vi.mocked(db.getAssociationById).mockResolvedValue({ id: 10, nomAssociation: 'Association Test', emailContact: 'test@asso.fr', } as any); // Simulate the changeSalles logic const request = await db.getRequestById(1); expect(request).toBeDefined(); expect(request!.type).toBe('demande_salle'); const formData = JSON.parse(request!.formData!); const anciennesSalles = formData.sallesSelectionnees; // Update salles formData.sallesSelectionnees = ['Salle IBIS', 'Salle PELICAN']; formData.sallesIds = ['salle_ibis', 'salle_pelican']; // Add change history formData.historiqueChangementsSalles = [{ date: new Date().toISOString(), anciennesSalles, nouvellesSalles: ['Salle IBIS', 'Salle PELICAN'], raison: 'Besoin d\'une salle plus grande', parAdmin: 1, }]; await db.updateRequestSalles(1, JSON.stringify(formData)); expect(db.updateRequestSalles).toHaveBeenCalledWith( 1, expect.stringContaining('Salle IBIS') ); // Verify the updated formData const updatedFormData = JSON.parse( vi.mocked(db.updateRequestSalles).mock.calls[0][1] ); expect(updatedFormData.sallesSelectionnees).toEqual(['Salle IBIS', 'Salle PELICAN']); expect(updatedFormData.sallesIds).toEqual(['salle_ibis', 'salle_pelican']); expect(updatedFormData.historiqueChangementsSalles).toHaveLength(1); expect(updatedFormData.historiqueChangementsSalles[0].anciennesSalles).toEqual(['Salle TOUCAN']); expect(updatedFormData.historiqueChangementsSalles[0].raison).toBe('Besoin d\'une salle plus grande'); }); it('should create request history entry for salle change', async () => { vi.mocked(db.createRequestHistory).mockResolvedValue(undefined as any); await db.createRequestHistory({ requestId: 1, action: 'changement_salle', ancienStatut: 'validee', nouveauStatut: 'validee', userId: 1, commentaire: 'Changement de salle(s) : Salle TOUCAN → Salle IBIS. Raison : Besoin d\'une salle plus grande', }); expect(db.createRequestHistory).toHaveBeenCalledWith( expect.objectContaining({ requestId: 1, action: 'changement_salle', commentaire: expect.stringContaining('Salle TOUCAN'), }) ); }); it('should reject change for non-salle requests', async () => { const nonSalleRequest = { id: 2, type: 'subvention_fonctionnement', associationId: 10, status: 'validee', formData: '{}', }; vi.mocked(db.getRequestById).mockResolvedValue(nonSalleRequest as any); const request = await db.getRequestById(2); expect(request!.type).not.toBe('demande_salle'); // In the actual procedure, this would throw a TRPCError }); it('should send notification to association on salle change', async () => { vi.mocked(db.getAssociationById).mockResolvedValue({ id: 10, nomAssociation: 'Association Test', emailContact: 'test@asso.fr', } as any); const association = await db.getAssociationById(10); expect(association).toBeDefined(); await notifyOwner({ title: 'Changement de salle pour votre réservation', content: `Bonjour ${association!.nomAssociation}, votre salle a été modifiée.`, }); expect(notifyOwner).toHaveBeenCalledWith( expect.objectContaining({ title: 'Changement de salle pour votre réservation', content: expect.stringContaining('Association Test'), }) ); }); it('should preserve change history across multiple changes', () => { const formData = { sallesSelectionnees: ['Salle PELICAN'], sallesIds: ['salle_pelican'], historiqueChangementsSalles: [ { date: '2026-03-10T10:00:00Z', anciennesSalles: ['Salle TOUCAN'], nouvellesSalles: ['Salle IBIS'], raison: 'Premier changement', parAdmin: 1, }, { date: '2026-03-11T14:00:00Z', anciennesSalles: ['Salle IBIS'], nouvellesSalles: ['Salle PELICAN'], raison: 'Deuxième changement', parAdmin: 1, }, ], }; expect(formData.historiqueChangementsSalles).toHaveLength(2); expect(formData.historiqueChangementsSalles[0].anciennesSalles).toEqual(['Salle TOUCAN']); expect(formData.historiqueChangementsSalles[1].nouvellesSalles).toEqual(['Salle PELICAN']); expect(formData.sallesSelectionnees).toEqual(['Salle PELICAN']); }); }); });