import { describe, it, expect } from 'vitest' import { calculateServiceStatus, calculateTotalCosts, calculateAverageLifespan, formatDate, formatCurrency, } from '@/lib/utils' import { WearPart, MaintenanceHistory } from '@prisma/client' describe('Utility Functions', () => { describe('calculateServiceStatus', () => { it('should return OK status when part is new', () => { const part = { id: '1', bikeId: 'bike1', type: 'CHAIN', installDate: new Date(), installMileage: 0, serviceInterval: 1000, status: 'ACTIVE', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: null, notes: null, maintenanceHistory: [], } const status = calculateServiceStatus(part) expect(status.status).toBe('OK') expect(status.remainingKm).toBe(1000) expect(status.percentageUsed).toBe(0) }) it('should return WARNING status when 75% used', () => { const part = { id: '1', bikeId: 'bike1', type: 'CHAIN', installDate: new Date(), installMileage: 0, serviceInterval: 1000, status: 'ACTIVE', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: null, notes: null, maintenanceHistory: [ { id: '1', wearPartId: '1', date: new Date(), mileage: 750, action: 'SERVICE', createdAt: new Date(), updatedAt: new Date(), notes: null, cost: null, }, ], } const status = calculateServiceStatus(part) expect(status.status).toBe('WARNING') expect(status.percentageUsed).toBeGreaterThanOrEqual(75) }) it('should return CRITICAL status when 90% used', () => { const part = { id: '1', bikeId: 'bike1', type: 'CHAIN', installDate: new Date(), installMileage: 0, serviceInterval: 1000, status: 'ACTIVE', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: null, notes: null, maintenanceHistory: [ { id: '1', wearPartId: '1', date: new Date(), mileage: 950, action: 'SERVICE', createdAt: new Date(), updatedAt: new Date(), notes: null, cost: null, }, ], } const status = calculateServiceStatus(part) expect(status.status).toBe('CRITICAL') expect(status.percentageUsed).toBeGreaterThanOrEqual(90) }) }) describe('calculateTotalCosts', () => { it('should calculate total costs correctly', () => { const parts = [ { id: '1', bikeId: 'bike1', type: 'CHAIN', installDate: new Date(), installMileage: 0, serviceInterval: 1000, status: 'ACTIVE', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: 50.0, notes: null, maintenanceHistory: [ { id: '1', wearPartId: '1', date: new Date(), mileage: 500, action: 'SERVICE', createdAt: new Date(), updatedAt: new Date(), notes: null, cost: 20.0, }, ], }, { id: '2', bikeId: 'bike1', type: 'BRAKE_PADS', installDate: new Date(), installMileage: 0, serviceInterval: 500, status: 'ACTIVE', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: 30.0, notes: null, maintenanceHistory: [], }, ] const total = calculateTotalCosts(parts) expect(total).toBe(100.0) // 50 + 20 + 30 }) it('should return 0 for parts with no costs', () => { const parts = [ { id: '1', bikeId: 'bike1', type: 'CHAIN', installDate: new Date(), installMileage: 0, serviceInterval: 1000, status: 'ACTIVE', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: null, notes: null, maintenanceHistory: [], }, ] const total = calculateTotalCosts(parts) expect(total).toBe(0) }) }) describe('calculateAverageLifespan', () => { it('should calculate average lifespan for replaced parts', () => { const parts = [ { id: '1', bikeId: 'bike1', type: 'CHAIN', installDate: new Date(), installMileage: 0, serviceInterval: 1000, status: 'REPLACED', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: null, notes: null, maintenanceHistory: [ { id: '1', wearPartId: '1', date: new Date('2024-01-01'), mileage: 0, action: 'INSTALL', createdAt: new Date(), updatedAt: new Date(), notes: null, cost: null, }, { id: '2', wearPartId: '1', date: new Date('2024-06-01'), mileage: 2000, action: 'REPLACE', createdAt: new Date(), updatedAt: new Date(), notes: null, cost: null, }, ], }, { id: '2', bikeId: 'bike1', type: 'BRAKE_PADS', installDate: new Date(), installMileage: 0, serviceInterval: 500, status: 'REPLACED', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: null, notes: null, maintenanceHistory: [ { id: '3', wearPartId: '2', date: new Date('2024-01-01'), mileage: 0, action: 'INSTALL', createdAt: new Date(), updatedAt: new Date(), notes: null, cost: null, }, { id: '4', wearPartId: '2', date: new Date('2024-03-01'), mileage: 1000, action: 'REPLACE', createdAt: new Date(), updatedAt: new Date(), notes: null, cost: null, }, ], }, ] const avg = calculateAverageLifespan(parts) expect(avg).toBe(1500) // (2000 + 1000) / 2 }) it('should return null when no replaced parts exist', () => { const parts = [ { id: '1', bikeId: 'bike1', type: 'CHAIN', installDate: new Date(), installMileage: 0, serviceInterval: 1000, status: 'ACTIVE', createdAt: new Date(), updatedAt: new Date(), brand: null, model: null, cost: null, notes: null, maintenanceHistory: [], }, ] const avg = calculateAverageLifespan(parts) expect(avg).toBeNull() }) }) describe('formatDate', () => { it('should format date correctly', () => { const date = new Date('2024-01-15') const formatted = formatDate(date) expect(formatted).toMatch(/\d{2}\.\d{2}\.\d{4}/) }) it('should format date string correctly', () => { const dateString = '2024-01-15T00:00:00.000Z' const formatted = formatDate(dateString) expect(formatted).toMatch(/\d{2}\.\d{2}\.\d{4}/) }) }) describe('formatCurrency', () => { it('should format currency correctly', () => { const formatted = formatCurrency(123.45) expect(formatted).toContain('123,45') expect(formatted).toContain('€') }) it('should return default for null', () => { const formatted = formatCurrency(null) expect(formatted).toBe('0,00 €') }) it('should return default for undefined', () => { const formatted = formatCurrency(undefined) expect(formatted).toBe('0,00 €') }) }) })