import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { createExpense, getExpenses, getExpenseById, updateExpense, deleteExpense, getExpenseCategories, getExpensesByCategory, getTotalExpenses } from '../expense-management.server'; import { prisma } from '../db.server'; describe('Expense Management', () => { beforeEach(async () => { // Clean up test data await prisma.expense.deleteMany(); }); afterEach(async () => { // Clean up test data await prisma.expense.deleteMany(); }); describe('createExpense', () => { it('should create a new expense', async () => { const expenseData = { description: 'قطع غيار للمحرك', category: 'قطع غيار', amount: 500.00, expenseDate: new Date('2024-01-15'), }; const expense = await createExpense(expenseData); expect(expense).toBeDefined(); expect(expense.description).toBe(expenseData.description); expect(expense.category).toBe(expenseData.category); expect(expense.amount).toBe(expenseData.amount); expect(expense.expenseDate).toEqual(expenseData.expenseDate); }); it('should create expense with current date if no date provided', async () => { const expenseData = { description: 'مصروف عام', category: 'أخرى', amount: 100.00, }; const expense = await createExpense(expenseData); expect(expense).toBeDefined(); expect(expense.expenseDate).toBeInstanceOf(Date); }); }); describe('getExpenses', () => { beforeEach(async () => { // Create test expenses await prisma.expense.createMany({ data: [ { description: 'قطع غيار', category: 'قطع غيار', amount: 500.00, expenseDate: new Date('2024-01-15'), }, { description: 'أدوات صيانة', category: 'أدوات', amount: 200.00, expenseDate: new Date('2024-01-10'), }, { description: 'إيجار المحل', category: 'إيجار', amount: 3000.00, expenseDate: new Date('2024-01-01'), }, ], }); }); it('should get all expenses with pagination', async () => { const result = await getExpenses(); expect(result.expenses).toHaveLength(3); expect(result.total).toBe(3); expect(result.totalPages).toBe(1); }); it('should filter expenses by search query', async () => { const result = await getExpenses('قطع غيار'); expect(result.expenses).toHaveLength(1); expect(result.expenses[0].description).toBe('قطع غيار'); }); it('should filter expenses by category', async () => { const result = await getExpenses(undefined, 1, 10, 'أدوات'); expect(result.expenses).toHaveLength(1); expect(result.expenses[0].category).toBe('أدوات'); }); it('should filter expenses by date range', async () => { const dateFrom = new Date('2024-01-10'); const dateTo = new Date('2024-01-20'); const result = await getExpenses(undefined, 1, 10, undefined, dateFrom, dateTo); expect(result.expenses).toHaveLength(2); }); it('should handle pagination correctly', async () => { const result = await getExpenses(undefined, 1, 2); expect(result.expenses).toHaveLength(2); expect(result.totalPages).toBe(2); }); }); describe('getExpenseById', () => { it('should get expense by ID', async () => { const createdExpense = await prisma.expense.create({ data: { description: 'تست مصروف', category: 'أخرى', amount: 100.00, }, }); const expense = await getExpenseById(createdExpense.id); expect(expense).toBeDefined(); expect(expense?.id).toBe(createdExpense.id); expect(expense?.description).toBe('تست مصروف'); }); it('should return null for non-existent expense', async () => { const expense = await getExpenseById(999); expect(expense).toBeNull(); }); }); describe('updateExpense', () => { it('should update expense successfully', async () => { const createdExpense = await prisma.expense.create({ data: { description: 'مصروف قديم', category: 'أخرى', amount: 100.00, }, }); const updateData = { description: 'مصروف محدث', category: 'قطع غيار', amount: 200.00, }; const updatedExpense = await updateExpense(createdExpense.id, updateData); expect(updatedExpense.description).toBe(updateData.description); expect(updatedExpense.category).toBe(updateData.category); expect(updatedExpense.amount).toBe(updateData.amount); }); }); describe('deleteExpense', () => { it('should delete expense successfully', async () => { const createdExpense = await prisma.expense.create({ data: { description: 'مصروف للحذف', category: 'أخرى', amount: 100.00, }, }); await deleteExpense(createdExpense.id); const deletedExpense = await prisma.expense.findUnique({ where: { id: createdExpense.id }, }); expect(deletedExpense).toBeNull(); }); }); describe('getExpenseCategories', () => { beforeEach(async () => { await prisma.expense.createMany({ data: [ { description: 'مصروف 1', category: 'قطع غيار', amount: 100 }, { description: 'مصروف 2', category: 'أدوات', amount: 200 }, { description: 'مصروف 3', category: 'قطع غيار', amount: 150 }, ], }); }); it('should get unique expense categories', async () => { const categories = await getExpenseCategories(); expect(categories).toHaveLength(2); expect(categories).toContain('قطع غيار'); expect(categories).toContain('أدوات'); }); }); describe('getExpensesByCategory', () => { beforeEach(async () => { await prisma.expense.createMany({ data: [ { description: 'مصروف 1', category: 'قطع غيار', amount: 100 }, { description: 'مصروف 2', category: 'أدوات', amount: 200 }, { description: 'مصروف 3', category: 'قطع غيار', amount: 150 }, ], }); }); it('should group expenses by category', async () => { const result = await getExpensesByCategory(); expect(result).toHaveLength(2); const spareParts = result.find(r => r.category === 'قطع غيار'); expect(spareParts?.total).toBe(250); expect(spareParts?.count).toBe(2); const tools = result.find(r => r.category === 'أدوات'); expect(tools?.total).toBe(200); expect(tools?.count).toBe(1); }); }); describe('getTotalExpenses', () => { beforeEach(async () => { await prisma.expense.createMany({ data: [ { description: 'مصروف 1', category: 'قطع غيار', amount: 100, expenseDate: new Date('2024-01-15'), }, { description: 'مصروف 2', category: 'أدوات', amount: 200, expenseDate: new Date('2024-01-10'), }, { description: 'مصروف 3', category: 'إيجار', amount: 3000, expenseDate: new Date('2023-12-15'), }, ], }); }); it('should calculate total expenses', async () => { const total = await getTotalExpenses(); expect(total).toBe(3300); }); it('should calculate total expenses for date range', async () => { const dateFrom = new Date('2024-01-01'); const dateTo = new Date('2024-01-31'); const total = await getTotalExpenses(dateFrom, dateTo); expect(total).toBe(300); // Only expenses from January 2024 }); }); });