import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { createMaintenanceVisit, getMaintenanceVisits, getMaintenanceVisitById, updateMaintenanceVisit, deleteMaintenanceVisit, getVehicleMaintenanceHistory, getCustomerMaintenanceHistory } from '../maintenance-visit-management.server'; import { prisma } from '../db.server'; import type { Customer, Vehicle } from '@prisma/client'; describe('Maintenance Visit Management', () => { let testCustomer: Customer; let testVehicle: Vehicle; beforeEach(async () => { // Create test customer testCustomer = await prisma.customer.create({ data: { name: 'أحمد محمد', phone: '0501234567', email: 'ahmed@example.com', }, }); // Create test vehicle testVehicle = await prisma.vehicle.create({ data: { plateNumber: 'أ ب ج 123', bodyType: 'سيدان', manufacturer: 'تويوتا', model: 'كامري', year: 2020, transmission: 'Automatic', fuel: 'Gasoline', useType: 'personal', ownerId: testCustomer.id, }, }); }); afterEach(async () => { // Clean up test data await prisma.income.deleteMany(); await prisma.maintenanceVisit.deleteMany(); await prisma.vehicle.deleteMany(); await prisma.customer.deleteMany(); }); describe('createMaintenanceVisit', () => { it('should create a maintenance visit successfully', async () => { const visitData = { vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'تغيير زيت', description: 'تغيير زيت المحرك والفلتر', cost: 150.00, paymentStatus: 'paid', kilometers: 50000, nextVisitDelay: 3, }; const visit = await createMaintenanceVisit(visitData); expect(visit).toBeDefined(); expect(visit.vehicleId).toBe(testVehicle.id); expect(visit.customerId).toBe(testCustomer.id); expect(visit.maintenanceType).toBe('تغيير زيت'); expect(visit.cost).toBe(150.00); expect(visit.nextVisitDelay).toBe(3); // Check that vehicle was updated const updatedVehicle = await prisma.vehicle.findUnique({ where: { id: testVehicle.id }, }); expect(updatedVehicle?.lastVisitDate).toBeDefined(); expect(updatedVehicle?.suggestedNextVisitDate).toBeDefined(); // Check that income was created const income = await prisma.income.findFirst({ where: { maintenanceVisitId: visit.id }, }); expect(income).toBeDefined(); expect(income?.amount).toBe(150.00); }); it('should calculate next visit date correctly', async () => { const visitData = { vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'فحص دوري', description: 'فحص دوري شامل', cost: 200.00, kilometers: 45000, nextVisitDelay: 2, // 2 months }; await createMaintenanceVisit(visitData); const updatedVehicle = await prisma.vehicle.findUnique({ where: { id: testVehicle.id }, }); expect(updatedVehicle?.suggestedNextVisitDate).toBeDefined(); // Check that the suggested date is approximately 2 months from now const now = new Date(); const expectedDate = new Date(); expectedDate.setMonth(expectedDate.getMonth() + 2); const actualDate = updatedVehicle!.suggestedNextVisitDate!; const timeDiff = Math.abs(actualDate.getTime() - expectedDate.getTime()); const daysDiff = timeDiff / (1000 * 60 * 60 * 24); expect(daysDiff).toBeLessThan(2); // Allow 2 days difference }); }); describe('getMaintenanceVisits', () => { beforeEach(async () => { // Create test visits await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'تغيير زيت', description: 'تغيير زيت المحرك', cost: 150.00, kilometers: 50000, nextVisitDelay: 3, }); await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'فحص فرامل', description: 'فحص وتنظيف الفرامل', cost: 100.00, kilometers: 52000, nextVisitDelay: 2, }); }); it('should get all maintenance visits', async () => { const result = await getMaintenanceVisits(); expect(result.visits).toHaveLength(2); expect(result.total).toBe(2); expect(result.totalPages).toBe(1); }); it('should search maintenance visits by maintenance type', async () => { const result = await getMaintenanceVisits('تغيير زيت'); expect(result.visits).toHaveLength(1); expect(result.visits[0].maintenanceType).toBe('تغيير زيت'); }); it('should filter by vehicle ID', async () => { const result = await getMaintenanceVisits('', 1, 10, testVehicle.id); expect(result.visits).toHaveLength(2); result.visits.forEach(visit => { expect(visit.vehicleId).toBe(testVehicle.id); }); }); it('should filter by customer ID', async () => { const result = await getMaintenanceVisits('', 1, 10, undefined, testCustomer.id); expect(result.visits).toHaveLength(2); result.visits.forEach(visit => { expect(visit.customerId).toBe(testCustomer.id); }); }); it('should paginate results', async () => { const result = await getMaintenanceVisits('', 1, 1); expect(result.visits).toHaveLength(1); expect(result.total).toBe(2); expect(result.totalPages).toBe(2); }); }); describe('getMaintenanceVisitById', () => { it('should get a maintenance visit by ID', async () => { const createdVisit = await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'تغيير إطارات', description: 'تغيير الإطارات الأمامية', cost: 800.00, kilometers: 55000, nextVisitDelay: 4, }); const visit = await getMaintenanceVisitById(createdVisit.id); expect(visit).toBeDefined(); expect(visit?.id).toBe(createdVisit.id); expect(visit?.vehicle).toBeDefined(); expect(visit?.customer).toBeDefined(); expect(visit?.income).toBeDefined(); }); it('should return null for non-existent visit', async () => { const visit = await getMaintenanceVisitById(99999); expect(visit).toBeNull(); }); }); describe('updateMaintenanceVisit', () => { it('should update a maintenance visit successfully', async () => { const createdVisit = await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'فحص دوري', description: 'فحص دوري أولي', cost: 200.00, kilometers: 48000, nextVisitDelay: 3, }); const updateData = { maintenanceType: 'فحص شامل', description: 'فحص شامل محدث', cost: 250.00, paymentStatus: 'paid', kilometers: 48500, nextVisitDelay: 2, }; const updatedVisit = await updateMaintenanceVisit(createdVisit.id, updateData); expect(updatedVisit.maintenanceType).toBe('فحص شامل'); expect(updatedVisit.description).toBe('فحص شامل محدث'); expect(updatedVisit.cost).toBe(250.00); expect(updatedVisit.paymentStatus).toBe('paid'); expect(updatedVisit.kilometers).toBe(48500); expect(updatedVisit.nextVisitDelay).toBe(2); // Check that income was updated const income = await prisma.income.findFirst({ where: { maintenanceVisitId: createdVisit.id }, }); expect(income?.amount).toBe(250.00); }); it('should update vehicle dates when visit date changes', async () => { const createdVisit = await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'صيانة عامة', description: 'صيانة عامة', cost: 300.00, kilometers: 50000, nextVisitDelay: 3, }); const newVisitDate = new Date(); newVisitDate.setDate(newVisitDate.getDate() - 5); // 5 days ago await updateMaintenanceVisit(createdVisit.id, { visitDate: newVisitDate, nextVisitDelay: 4, }); const updatedVehicle = await prisma.vehicle.findUnique({ where: { id: testVehicle.id }, }); expect(updatedVehicle?.lastVisitDate?.getTime()).toBe(newVisitDate.getTime()); // Check that suggested next visit date was recalculated const expectedNextDate = new Date(newVisitDate); expectedNextDate.setMonth(expectedNextDate.getMonth() + 4); const actualNextDate = updatedVehicle!.suggestedNextVisitDate!; const timeDiff = Math.abs(actualNextDate.getTime() - expectedNextDate.getTime()); const daysDiff = timeDiff / (1000 * 60 * 60 * 24); expect(daysDiff).toBeLessThan(2); }); }); describe('deleteMaintenanceVisit', () => { it('should delete a maintenance visit successfully', async () => { const createdVisit = await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'تنظيف مكيف', description: 'تنظيف وصيانة المكيف', cost: 120.00, kilometers: 47000, nextVisitDelay: 2, }); await deleteMaintenanceVisit(createdVisit.id); // Check that visit was deleted const deletedVisit = await prisma.maintenanceVisit.findUnique({ where: { id: createdVisit.id }, }); expect(deletedVisit).toBeNull(); // Check that income was deleted (cascade) const income = await prisma.income.findFirst({ where: { maintenanceVisitId: createdVisit.id }, }); expect(income).toBeNull(); // Check that vehicle dates were cleared const updatedVehicle = await prisma.vehicle.findUnique({ where: { id: testVehicle.id }, }); expect(updatedVehicle?.lastVisitDate).toBeNull(); expect(updatedVehicle?.suggestedNextVisitDate).toBeNull(); }); it('should update vehicle dates to most recent remaining visit after deletion', async () => { // Create two visits const firstVisit = await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'زيت قديم', description: 'تغيير زيت قديم', cost: 100.00, kilometers: 45000, nextVisitDelay: 3, visitDate: new Date('2023-01-01'), }); const secondVisit = await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'زيت جديد', description: 'تغيير زيت جديد', cost: 150.00, kilometers: 50000, nextVisitDelay: 2, visitDate: new Date('2023-02-01'), }); // Delete the more recent visit await deleteMaintenanceVisit(secondVisit.id); // Check that vehicle dates were updated to the remaining visit const updatedVehicle = await prisma.vehicle.findUnique({ where: { id: testVehicle.id }, }); expect(updatedVehicle?.lastVisitDate?.getTime()).toBe(new Date('2023-01-01').getTime()); // Check that suggested next visit date was recalculated based on first visit const expectedNextDate = new Date('2023-01-01'); expectedNextDate.setMonth(expectedNextDate.getMonth() + 3); const actualNextDate = updatedVehicle!.suggestedNextVisitDate!; expect(actualNextDate.getTime()).toBe(expectedNextDate.getTime()); }); }); describe('getVehicleMaintenanceHistory', () => { it('should get maintenance history for a vehicle', async () => { await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'زيت أول', description: 'تغيير زيت أول', cost: 100.00, kilometers: 45000, nextVisitDelay: 3, }); await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'زيت ثاني', description: 'تغيير زيت ثاني', cost: 120.00, kilometers: 48000, nextVisitDelay: 3, }); const history = await getVehicleMaintenanceHistory(testVehicle.id); expect(history).toHaveLength(2); expect(history[0].vehicleId).toBe(testVehicle.id); expect(history[1].vehicleId).toBe(testVehicle.id); // Should be ordered by visit date descending expect(new Date(history[0].visitDate).getTime()).toBeGreaterThanOrEqual( new Date(history[1].visitDate).getTime() ); }); }); describe('getCustomerMaintenanceHistory', () => { it('should get maintenance history for a customer', async () => { await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'صيانة أولى', description: 'صيانة أولى', cost: 200.00, kilometers: 45000, nextVisitDelay: 3, }); await createMaintenanceVisit({ vehicleId: testVehicle.id, customerId: testCustomer.id, maintenanceType: 'صيانة ثانية', description: 'صيانة ثانية', cost: 250.00, kilometers: 48000, nextVisitDelay: 2, }); const history = await getCustomerMaintenanceHistory(testCustomer.id); expect(history).toHaveLength(2); expect(history[0].customerId).toBe(testCustomer.id); expect(history[1].customerId).toBe(testCustomer.id); // Should be ordered by visit date descending expect(new Date(history[0].visitDate).getTime()).toBeGreaterThanOrEqual( new Date(history[1].visitDate).getTime() ); }); }); });