uup
This commit is contained in:
437
app/lib/__tests__/customer-management.test.ts
Normal file
437
app/lib/__tests__/customer-management.test.ts
Normal file
@@ -0,0 +1,437 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
|
||||
// Mock Prisma first
|
||||
vi.mock('../db.server', () => ({
|
||||
prisma: {
|
||||
customer: {
|
||||
findMany: vi.fn(),
|
||||
findUnique: vi.fn(),
|
||||
findFirst: vi.fn(),
|
||||
create: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
count: vi.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import {
|
||||
getCustomers,
|
||||
createCustomer,
|
||||
updateCustomer,
|
||||
deleteCustomer,
|
||||
getCustomerById,
|
||||
getCustomersForSelect,
|
||||
searchCustomers,
|
||||
getCustomerStats
|
||||
} from '../customer-management.server';
|
||||
import { prisma } from '../db.server';
|
||||
|
||||
const mockPrisma = prisma as any;
|
||||
|
||||
describe('Customer Management Server', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getCustomers', () => {
|
||||
it('should return customers with pagination', async () => {
|
||||
const mockCustomers = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
email: 'ahmed@example.com',
|
||||
address: 'الرياض',
|
||||
createdDate: new Date(),
|
||||
updateDate: new Date(),
|
||||
vehicles: [],
|
||||
maintenanceVisits: [],
|
||||
},
|
||||
];
|
||||
|
||||
mockPrisma.customer.findMany.mockResolvedValue(mockCustomers);
|
||||
mockPrisma.customer.count.mockResolvedValue(1);
|
||||
|
||||
const result = await getCustomers('', 1, 10);
|
||||
|
||||
expect(result).toEqual({
|
||||
customers: mockCustomers,
|
||||
total: 1,
|
||||
totalPages: 1,
|
||||
});
|
||||
expect(mockPrisma.customer.findMany).toHaveBeenCalledWith({
|
||||
where: {},
|
||||
include: {
|
||||
vehicles: {
|
||||
select: {
|
||||
id: true,
|
||||
plateNumber: true,
|
||||
manufacturer: true,
|
||||
model: true,
|
||||
year: true,
|
||||
lastVisitDate: true,
|
||||
suggestedNextVisitDate: true,
|
||||
},
|
||||
},
|
||||
maintenanceVisits: {
|
||||
select: {
|
||||
id: true,
|
||||
visitDate: true,
|
||||
cost: true,
|
||||
maintenanceType: true,
|
||||
},
|
||||
orderBy: { visitDate: 'desc' },
|
||||
take: 5,
|
||||
},
|
||||
},
|
||||
orderBy: { createdDate: 'desc' },
|
||||
skip: 0,
|
||||
take: 10,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle search query', async () => {
|
||||
mockPrisma.customer.findMany.mockResolvedValue([]);
|
||||
mockPrisma.customer.count.mockResolvedValue(0);
|
||||
|
||||
await getCustomers('أحمد', 1, 10);
|
||||
|
||||
expect(mockPrisma.customer.findMany).toHaveBeenCalledWith({
|
||||
where: {
|
||||
OR: [
|
||||
{ name: { contains: 'أحمد' } },
|
||||
{ phone: { contains: 'أحمد' } },
|
||||
{ email: { contains: 'أحمد' } },
|
||||
{ address: { contains: 'أحمد' } },
|
||||
],
|
||||
},
|
||||
include: expect.any(Object),
|
||||
orderBy: { createdDate: 'desc' },
|
||||
skip: 0,
|
||||
take: 10,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('createCustomer', () => {
|
||||
it('should create a new customer successfully', async () => {
|
||||
const customerData = {
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
email: 'ahmed@example.com',
|
||||
address: 'الرياض',
|
||||
};
|
||||
|
||||
const mockCustomer = {
|
||||
id: 1,
|
||||
...customerData,
|
||||
createdDate: new Date(),
|
||||
updateDate: new Date(),
|
||||
};
|
||||
|
||||
mockPrisma.customer.findFirst.mockResolvedValue(null);
|
||||
mockPrisma.customer.create.mockResolvedValue(mockCustomer);
|
||||
|
||||
const result = await createCustomer(customerData);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: true,
|
||||
customer: mockCustomer,
|
||||
});
|
||||
expect(mockPrisma.customer.create).toHaveBeenCalledWith({
|
||||
data: {
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
email: 'ahmed@example.com',
|
||||
address: 'الرياض',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return error if phone already exists', async () => {
|
||||
const customerData = {
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
};
|
||||
|
||||
const existingCustomer = {
|
||||
id: 2,
|
||||
name: 'محمد أحمد',
|
||||
phone: '0501234567',
|
||||
email: null,
|
||||
address: null,
|
||||
createdDate: new Date(),
|
||||
updateDate: new Date(),
|
||||
};
|
||||
|
||||
mockPrisma.customer.findFirst.mockResolvedValue(existingCustomer);
|
||||
|
||||
const result = await createCustomer(customerData);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
error: 'رقم الهاتف موجود بالفعل',
|
||||
});
|
||||
expect(mockPrisma.customer.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return error if email already exists', async () => {
|
||||
const customerData = {
|
||||
name: 'أحمد محمد',
|
||||
email: 'ahmed@example.com',
|
||||
};
|
||||
|
||||
const existingCustomer = {
|
||||
id: 2,
|
||||
name: 'محمد أحمد',
|
||||
phone: null,
|
||||
email: 'ahmed@example.com',
|
||||
address: null,
|
||||
createdDate: new Date(),
|
||||
updateDate: new Date(),
|
||||
};
|
||||
|
||||
mockPrisma.customer.findFirst.mockResolvedValue(existingCustomer);
|
||||
|
||||
const result = await createCustomer(customerData);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
error: 'البريد الإلكتروني موجود بالفعل',
|
||||
});
|
||||
expect(mockPrisma.customer.create).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateCustomer', () => {
|
||||
it('should update customer successfully', async () => {
|
||||
const customerId = 1;
|
||||
const updateData = {
|
||||
name: 'أحمد محمد المحدث',
|
||||
phone: '0509876543',
|
||||
};
|
||||
|
||||
const existingCustomer = {
|
||||
id: customerId,
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
email: null,
|
||||
address: null,
|
||||
createdDate: new Date(),
|
||||
updateDate: new Date(),
|
||||
};
|
||||
|
||||
const updatedCustomer = {
|
||||
...existingCustomer,
|
||||
...updateData,
|
||||
updateDate: new Date(),
|
||||
};
|
||||
|
||||
mockPrisma.customer.findUnique.mockResolvedValue(existingCustomer);
|
||||
mockPrisma.customer.findFirst.mockResolvedValue(null);
|
||||
mockPrisma.customer.update.mockResolvedValue(updatedCustomer);
|
||||
|
||||
const result = await updateCustomer(customerId, updateData);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: true,
|
||||
customer: updatedCustomer,
|
||||
});
|
||||
expect(mockPrisma.customer.update).toHaveBeenCalledWith({
|
||||
where: { id: customerId },
|
||||
data: {
|
||||
name: 'أحمد محمد المحدث',
|
||||
phone: '0509876543',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return error if customer not found', async () => {
|
||||
const customerId = 999;
|
||||
const updateData = { name: 'أحمد محمد' };
|
||||
|
||||
mockPrisma.customer.findUnique.mockResolvedValue(null);
|
||||
|
||||
const result = await updateCustomer(customerId, updateData);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
error: 'العميل غير موجود',
|
||||
});
|
||||
expect(mockPrisma.customer.update).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteCustomer', () => {
|
||||
it('should delete customer successfully when no relationships exist', async () => {
|
||||
const customerId = 1;
|
||||
const existingCustomer = {
|
||||
id: customerId,
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
email: null,
|
||||
address: null,
|
||||
createdDate: new Date(),
|
||||
updateDate: new Date(),
|
||||
vehicles: [],
|
||||
maintenanceVisits: [],
|
||||
};
|
||||
|
||||
mockPrisma.customer.findUnique.mockResolvedValue(existingCustomer);
|
||||
mockPrisma.customer.delete.mockResolvedValue(existingCustomer);
|
||||
|
||||
const result = await deleteCustomer(customerId);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: true,
|
||||
});
|
||||
expect(mockPrisma.customer.delete).toHaveBeenCalledWith({
|
||||
where: { id: customerId },
|
||||
});
|
||||
});
|
||||
|
||||
it('should return error if customer has vehicles', async () => {
|
||||
const customerId = 1;
|
||||
const existingCustomer = {
|
||||
id: customerId,
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
email: null,
|
||||
address: null,
|
||||
createdDate: new Date(),
|
||||
updateDate: new Date(),
|
||||
vehicles: [{ id: 1, plateNumber: 'ABC-123' }],
|
||||
maintenanceVisits: [],
|
||||
};
|
||||
|
||||
mockPrisma.customer.findUnique.mockResolvedValue(existingCustomer);
|
||||
|
||||
const result = await deleteCustomer(customerId);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
error: 'لا يمكن حذف العميل لأنه يملك 1 مركبة. يرجى حذف المركبات أولاً',
|
||||
});
|
||||
expect(mockPrisma.customer.delete).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return error if customer has maintenance visits', async () => {
|
||||
const customerId = 1;
|
||||
const existingCustomer = {
|
||||
id: customerId,
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
email: null,
|
||||
address: null,
|
||||
createdDate: new Date(),
|
||||
updateDate: new Date(),
|
||||
vehicles: [],
|
||||
maintenanceVisits: [{ id: 1, visitDate: new Date() }],
|
||||
};
|
||||
|
||||
mockPrisma.customer.findUnique.mockResolvedValue(existingCustomer);
|
||||
|
||||
const result = await deleteCustomer(customerId);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
error: 'لا يمكن حذف العميل لأنه لديه 1 زيارة صيانة. يرجى حذف الزيارات أولاً',
|
||||
});
|
||||
expect(mockPrisma.customer.delete).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return error if customer not found', async () => {
|
||||
const customerId = 999;
|
||||
|
||||
mockPrisma.customer.findUnique.mockResolvedValue(null);
|
||||
|
||||
const result = await deleteCustomer(customerId);
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
error: 'العميل غير موجود',
|
||||
});
|
||||
expect(mockPrisma.customer.delete).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('searchCustomers', () => {
|
||||
it('should return empty array for short queries', async () => {
|
||||
const result = await searchCustomers('a');
|
||||
expect(result).toEqual([]);
|
||||
expect(mockPrisma.customer.findMany).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should search customers by name, phone, and email', async () => {
|
||||
const mockCustomers = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'أحمد محمد',
|
||||
phone: '0501234567',
|
||||
email: 'ahmed@example.com',
|
||||
},
|
||||
];
|
||||
|
||||
mockPrisma.customer.findMany.mockResolvedValue(mockCustomers);
|
||||
|
||||
const result = await searchCustomers('أحمد', 10);
|
||||
|
||||
expect(result).toEqual(mockCustomers);
|
||||
expect(mockPrisma.customer.findMany).toHaveBeenCalledWith({
|
||||
where: {
|
||||
OR: [
|
||||
{ name: { contains: 'أحمد' } },
|
||||
{ phone: { contains: 'أحمد' } },
|
||||
{ email: { contains: 'أحمد' } },
|
||||
],
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
phone: true,
|
||||
email: true,
|
||||
},
|
||||
orderBy: { name: 'asc' },
|
||||
take: 10,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomerStats', () => {
|
||||
it('should return customer statistics', async () => {
|
||||
const customerId = 1;
|
||||
const mockCustomer = {
|
||||
id: customerId,
|
||||
name: 'أحمد محمد',
|
||||
vehicles: [{ id: 1 }, { id: 2 }],
|
||||
maintenanceVisits: [
|
||||
{ cost: 100, visitDate: new Date('2024-01-15') },
|
||||
{ cost: 200, visitDate: new Date('2024-01-10') },
|
||||
{ cost: 150, visitDate: new Date('2024-01-05') },
|
||||
],
|
||||
};
|
||||
|
||||
mockPrisma.customer.findUnique.mockResolvedValue(mockCustomer);
|
||||
|
||||
const result = await getCustomerStats(customerId);
|
||||
|
||||
expect(result).toEqual({
|
||||
totalVehicles: 2,
|
||||
totalVisits: 3,
|
||||
totalSpent: 450,
|
||||
lastVisitDate: new Date('2024-01-15'),
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null if customer not found', async () => {
|
||||
const customerId = 999;
|
||||
|
||||
mockPrisma.customer.findUnique.mockResolvedValue(null);
|
||||
|
||||
const result = await getCustomerStats(customerId);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user