car_mms/app/lib/__tests__/maintenance-visit-management.test.ts
2025-09-11 14:22:27 +03:00

434 lines
14 KiB
TypeScript

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