Spaces:
Runtime error
Runtime error
| import { describe, it, expect } from 'vitest'; | |
| import { generateRecommendations } from '../../services/recommendationEngine.js'; | |
| const heavyUserData = { | |
| dailyCarKm: 40, | |
| carFuelType: 'petrol', | |
| publicTransportKmPerWeek: 0, | |
| cyclingKmPerWeek: 0, | |
| shortFlightsPerYear: 4, | |
| longFlightsPerYear: 2, | |
| monthlyElectricityKwh: 400, | |
| renewablePercentage: 0, | |
| dietType: 'heavy_meat', | |
| clothingItemsPerYear: 30, | |
| electronicsItemsPerYear: 3, | |
| }; | |
| const lowUserData = { | |
| dailyCarKm: 0, | |
| carFuelType: 'none', | |
| publicTransportKmPerWeek: 50, | |
| cyclingKmPerWeek: 40, | |
| shortFlightsPerYear: 0, | |
| longFlightsPerYear: 0, | |
| monthlyElectricityKwh: 100, | |
| renewablePercentage: 90, | |
| dietType: 'vegan', | |
| clothingItemsPerYear: 3, | |
| electronicsItemsPerYear: 0, | |
| }; | |
| const heavyEmissions = { | |
| transportEmission: 5000, | |
| energyEmission: 1100, | |
| foodEmission: 3300, | |
| shoppingEmission: 1890, | |
| totalEmission: 11290, | |
| }; | |
| const lowEmissions = { | |
| transportEmission: 232, | |
| energyEmission: 28, | |
| foodEmission: 1500, | |
| shoppingEmission: 99, | |
| totalEmission: 1859, | |
| }; | |
| describe('Recommendation Engine', () => { | |
| describe('generateRecommendations', () => { | |
| it('returns an array of recommendations', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| expect(Array.isArray(recs)).toBe(true); | |
| expect(recs.length).toBeGreaterThan(0); | |
| }); | |
| it('each recommendation has required fields', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| recs.forEach((rec) => { | |
| expect(rec).toHaveProperty('title'); | |
| expect(rec).toHaveProperty('description'); | |
| expect(rec).toHaveProperty('estimatedSavings'); | |
| expect(rec).toHaveProperty('priority'); | |
| expect(rec).toHaveProperty('category'); | |
| }); | |
| }); | |
| it('priority values are valid', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| const validPriorities = ['HIGH', 'MEDIUM', 'LOW']; | |
| recs.forEach((rec) => { | |
| expect(validPriorities).toContain(rec.priority); | |
| }); | |
| }); | |
| it('category values are valid', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| const validCategories = ['transport', 'energy', 'food', 'shopping']; | |
| recs.forEach((rec) => { | |
| expect(validCategories).toContain(rec.category); | |
| }); | |
| }); | |
| it('estimated savings are positive numbers', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| recs.forEach((rec) => { | |
| expect(rec.estimatedSavings).toBeGreaterThanOrEqual(0); | |
| expect(typeof rec.estimatedSavings).toBe('number'); | |
| }); | |
| }); | |
| it('heavy user gets HIGH priority recommendations', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| const highPriorityRecs = recs.filter((r) => r.priority === 'HIGH'); | |
| expect(highPriorityRecs.length).toBeGreaterThan(0); | |
| }); | |
| it('heavy user gets transport recommendation due to high car use', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| const transportRecs = recs.filter((r) => r.category === 'transport'); | |
| expect(transportRecs.length).toBeGreaterThan(0); | |
| }); | |
| it('heavy meat user gets food recommendation', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| const foodRecs = recs.filter((r) => r.category === 'food'); | |
| expect(foodRecs.length).toBeGreaterThan(0); | |
| }); | |
| it('generates fewer HIGH priority recommendations for low-impact user', () => { | |
| const heavyRecs = generateRecommendations(heavyUserData, heavyEmissions); | |
| const lowRecs = generateRecommendations(lowUserData, lowEmissions); | |
| const heavyHigh = heavyRecs.filter((r) => r.priority === 'HIGH').length; | |
| const lowHigh = lowRecs.filter((r) => r.priority === 'HIGH').length; | |
| expect(heavyHigh).toBeGreaterThanOrEqual(lowHigh); | |
| }); | |
| it('recommendations are sorted with HIGH priority first', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| const priorityOrder = { HIGH: 0, MEDIUM: 1, LOW: 2 }; | |
| for (let i = 1; i < recs.length; i++) { | |
| expect(priorityOrder[recs[i].priority]).toBeGreaterThanOrEqual( | |
| priorityOrder[recs[i - 1].priority] | |
| ); | |
| } | |
| }); | |
| it('high flight user gets flight reduction recommendation', () => { | |
| const recs = generateRecommendations(heavyUserData, heavyEmissions); | |
| const flightRec = recs.find((r) => r.title.toLowerCase().includes('flight')); | |
| expect(flightRec).toBeDefined(); | |
| }); | |
| it('handles edge case with no car and no flights', () => { | |
| const data = { | |
| ...heavyUserData, | |
| dailyCarKm: 0, | |
| carFuelType: 'none', | |
| shortFlightsPerYear: 0, | |
| longFlightsPerYear: 0, | |
| }; | |
| const emissions = { ...heavyEmissions, transportEmission: 100 }; | |
| expect(() => generateRecommendations(data, emissions)).not.toThrow(); | |
| }); | |
| }); | |
| }); | |