import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { createVehicle, updateVehicle, deleteVehicle, getVehicles, getVehicleById, getVehiclesForSelect, searchVehicles, getVehicleStats } from '../vehicle-management.server'; import { prisma } from '../db.server'; // Mock Prisma vi.mock('../db.server', () => ({ prisma: { vehicle: { create: vi.fn(), findMany: vi.fn(), findUnique: vi.fn(), findFirst: vi.fn(), update: vi.fn(), delete: vi.fn(), count: vi.fn(), }, customer: { findUnique: vi.fn(), }, }, })); describe('Vehicle Management', () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { vi.resetAllMocks(); }); describe('createVehicle', () => { const validVehicleData = { plateNumber: 'ABC-123', bodyType: 'سيدان', manufacturer: 'تويوتا', model: 'كامري', year: 2020, transmission: 'Automatic', fuel: 'Gasoline', useType: 'personal', ownerId: 1, }; it('should create a vehicle successfully', async () => { const mockVehicle = { id: 1, ...validVehicleData }; const mockCustomer = { id: 1, name: 'أحمد محمد' }; (prisma.vehicle.findUnique as any).mockResolvedValue(null); (prisma.customer.findUnique as any).mockResolvedValue(mockCustomer); (prisma.vehicle.create as any).mockResolvedValue(mockVehicle); const result = await createVehicle(validVehicleData); expect(result.success).toBe(true); expect(result.vehicle).toEqual(mockVehicle); expect(prisma.vehicle.create).toHaveBeenCalledWith({ data: expect.objectContaining({ plateNumber: 'ABC-123', manufacturer: 'تويوتا', model: 'كامري', ownerId: 1, }), }); }); it('should fail if plate number already exists', async () => { const existingVehicle = { id: 2, plateNumber: 'ABC-123' }; (prisma.vehicle.findUnique as any).mockResolvedValue(existingVehicle); const result = await createVehicle(validVehicleData); expect(result.success).toBe(false); expect(result.error).toBe('رقم اللوحة موجود بالفعل'); expect(prisma.vehicle.create).not.toHaveBeenCalled(); }); it('should fail if owner does not exist', async () => { (prisma.vehicle.findUnique as any).mockResolvedValue(null); (prisma.customer.findUnique as any).mockResolvedValue(null); const result = await createVehicle(validVehicleData); expect(result.success).toBe(false); expect(result.error).toBe('المالك غير موجود'); expect(prisma.vehicle.create).not.toHaveBeenCalled(); }); it('should handle database errors', async () => { (prisma.vehicle.findUnique as any).mockResolvedValue(null); (prisma.customer.findUnique as any).mockResolvedValue({ id: 1 }); (prisma.vehicle.create as any).mockRejectedValue(new Error('Database error')); const result = await createVehicle(validVehicleData); expect(result.success).toBe(false); expect(result.error).toBe('حدث خطأ أثناء إنشاء المركبة'); }); }); describe('updateVehicle', () => { const updateData = { plateNumber: 'XYZ-789', manufacturer: 'هوندا', model: 'أكورد', }; it('should update a vehicle successfully', async () => { const existingVehicle = { id: 1, plateNumber: 'ABC-123', ownerId: 1 }; const updatedVehicle = { ...existingVehicle, ...updateData }; (prisma.vehicle.findUnique as any).mockResolvedValue(existingVehicle); (prisma.vehicle.findFirst as any).mockResolvedValue(null); (prisma.vehicle.update as any).mockResolvedValue(updatedVehicle); const result = await updateVehicle(1, updateData); expect(result.success).toBe(true); expect(result.vehicle).toEqual(updatedVehicle); expect(prisma.vehicle.update).toHaveBeenCalledWith({ where: { id: 1 }, data: expect.objectContaining({ plateNumber: 'XYZ-789', manufacturer: 'هوندا', model: 'أكورد', }), }); }); it('should fail if vehicle does not exist', async () => { (prisma.vehicle.findUnique as any).mockResolvedValue(null); const result = await updateVehicle(999, updateData); expect(result.success).toBe(false); expect(result.error).toBe('المركبة غير موجودة'); expect(prisma.vehicle.update).not.toHaveBeenCalled(); }); it('should fail if new plate number conflicts', async () => { const existingVehicle = { id: 1, plateNumber: 'ABC-123' }; const conflictVehicle = { id: 2, plateNumber: 'XYZ-789' }; (prisma.vehicle.findUnique as any).mockResolvedValue(existingVehicle); (prisma.vehicle.findFirst as any).mockResolvedValue(conflictVehicle); const result = await updateVehicle(1, updateData); expect(result.success).toBe(false); expect(result.error).toBe('رقم اللوحة موجود بالفعل'); expect(prisma.vehicle.update).not.toHaveBeenCalled(); }); }); describe('deleteVehicle', () => { it('should delete a vehicle successfully', async () => { const existingVehicle = { id: 1, plateNumber: 'ABC-123', maintenanceVisits: [] }; (prisma.vehicle.findUnique as any).mockResolvedValue(existingVehicle); (prisma.vehicle.delete as any).mockResolvedValue(existingVehicle); const result = await deleteVehicle(1); expect(result.success).toBe(true); expect(prisma.vehicle.delete).toHaveBeenCalledWith({ where: { id: 1 }, }); }); it('should fail if vehicle does not exist', async () => { (prisma.vehicle.findUnique as any).mockResolvedValue(null); const result = await deleteVehicle(999); expect(result.success).toBe(false); expect(result.error).toBe('المركبة غير موجودة'); expect(prisma.vehicle.delete).not.toHaveBeenCalled(); }); it('should fail if vehicle has maintenance visits', async () => { const existingVehicle = { id: 1, plateNumber: 'ABC-123', maintenanceVisits: [{ id: 1 }, { id: 2 }] }; (prisma.vehicle.findUnique as any).mockResolvedValue(existingVehicle); const result = await deleteVehicle(1); expect(result.success).toBe(false); expect(result.error).toContain('لا يمكن حذف المركبة لأنها تحتوي على 2 زيارة صيانة'); expect(prisma.vehicle.delete).not.toHaveBeenCalled(); }); }); describe('getVehicles', () => { it('should return vehicles with pagination', async () => { const mockVehicles = [ { id: 1, plateNumber: 'ABC-123', manufacturer: 'تويوتا', owner: { id: 1, name: 'أحمد محمد' } }, { id: 2, plateNumber: 'XYZ-789', manufacturer: 'هوندا', owner: { id: 2, name: 'محمد علي' } } ]; (prisma.vehicle.findMany as any).mockResolvedValue(mockVehicles); (prisma.vehicle.count as any).mockResolvedValue(2); const result = await getVehicles('', 1, 10); expect(result.vehicles).toEqual(mockVehicles); expect(result.total).toBe(2); expect(result.totalPages).toBe(1); expect(prisma.vehicle.findMany).toHaveBeenCalledWith({ where: {}, include: { owner: { select: { id: true, name: true, phone: true, email: true, }, }, }, orderBy: { createdDate: 'desc' }, skip: 0, take: 10, }); }); it('should filter by search query', async () => { (prisma.vehicle.findMany as any).mockResolvedValue([]); (prisma.vehicle.count as any).mockResolvedValue(0); await getVehicles('تويوتا', 1, 10); expect(prisma.vehicle.findMany).toHaveBeenCalledWith({ where: { OR: [ { plateNumber: { contains: 'تويوتا' } }, { manufacturer: { contains: 'تويوتا' } }, { model: { contains: 'تويوتا' } }, { bodyType: { contains: 'تويوتا' } }, { owner: { name: { contains: 'تويوتا' } } }, ], }, include: expect.any(Object), orderBy: { createdDate: 'desc' }, skip: 0, take: 10, }); }); it('should filter by owner ID', async () => { (prisma.vehicle.findMany as any).mockResolvedValue([]); (prisma.vehicle.count as any).mockResolvedValue(0); await getVehicles('', 1, 10, 5); expect(prisma.vehicle.findMany).toHaveBeenCalledWith({ where: { ownerId: 5 }, include: expect.any(Object), orderBy: { createdDate: 'desc' }, skip: 0, take: 10, }); }); }); describe('getVehicleById', () => { it('should return vehicle with full relationships', async () => { const mockVehicle = { id: 1, plateNumber: 'ABC-123', owner: { id: 1, name: 'أحمد محمد' }, maintenanceVisits: [ { id: 1, visitDate: new Date(), cost: 100 } ] }; (prisma.vehicle.findUnique as any).mockResolvedValue(mockVehicle); const result = await getVehicleById(1); expect(result).toEqual(mockVehicle); expect(prisma.vehicle.findUnique).toHaveBeenCalledWith({ where: { id: 1 }, include: { owner: true, maintenanceVisits: { include: { customer: { select: { id: true, name: true, phone: true, }, }, }, orderBy: { visitDate: 'desc' }, take: 10, }, }, }); }); it('should return null if vehicle not found', async () => { (prisma.vehicle.findUnique as any).mockResolvedValue(null); const result = await getVehicleById(999); expect(result).toBeNull(); }); }); describe('getVehicleStats', () => { it('should calculate vehicle statistics', async () => { const mockVehicle = { id: 1, suggestedNextVisitDate: new Date('2024-06-01'), maintenanceVisits: [ { cost: 150, visitDate: new Date('2024-03-01') }, // Most recent first (desc order) { cost: 200, visitDate: new Date('2024-02-01') }, { cost: 100, visitDate: new Date('2024-01-01') }, ] }; (prisma.vehicle.findUnique as any).mockResolvedValue(mockVehicle); const result = await getVehicleStats(1); expect(result).toEqual({ totalVisits: 3, totalSpent: 450, lastVisitDate: new Date('2024-03-01'), nextSuggestedVisitDate: new Date('2024-06-01'), averageVisitCost: 150, }); }); it('should return null if vehicle not found', async () => { (prisma.vehicle.findUnique as any).mockResolvedValue(null); const result = await getVehicleStats(999); expect(result).toBeNull(); }); it('should handle vehicle with no visits', async () => { const mockVehicle = { id: 1, suggestedNextVisitDate: null, maintenanceVisits: [] }; (prisma.vehicle.findUnique as any).mockResolvedValue(mockVehicle); const result = await getVehicleStats(1); expect(result).toEqual({ totalVisits: 0, totalSpent: 0, lastVisitDate: undefined, nextSuggestedVisitDate: undefined, averageVisitCost: 0, }); }); }); describe('searchVehicles', () => { it('should search vehicles by query', async () => { const mockVehicles = [ { id: 1, plateNumber: 'ABC-123', manufacturer: 'تويوتا', model: 'كامري', year: 2020, owner: { id: 1, name: 'أحمد محمد' } } ]; (prisma.vehicle.findMany as any).mockResolvedValue(mockVehicles); const result = await searchVehicles('تويوتا'); expect(result).toEqual(mockVehicles); expect(prisma.vehicle.findMany).toHaveBeenCalledWith({ where: { OR: [ { plateNumber: { contains: 'تويوتا' } }, { manufacturer: { contains: 'تويوتا' } }, { model: { contains: 'تويوتا' } }, ], }, select: { id: true, plateNumber: true, manufacturer: true, model: true, year: true, owner: { select: { id: true, name: true, }, }, }, orderBy: { plateNumber: 'asc' }, take: 10, }); }); it('should return empty array for short queries', async () => { const result = await searchVehicles('a'); expect(result).toEqual([]); expect(prisma.vehicle.findMany).not.toHaveBeenCalled(); }); }); });