tests
This commit is contained in:
219
backend/tests/unit/services/damageAssessmentService.test.js
Normal file
219
backend/tests/unit/services/damageAssessmentService.test.js
Normal file
@@ -0,0 +1,219 @@
|
||||
// Mock dependencies BEFORE requiring modules
|
||||
jest.mock('../../../models');
|
||||
jest.mock('../../../services/lateReturnService');
|
||||
jest.mock('../../../services/emailService');
|
||||
jest.mock('../../../config/aws', () => ({
|
||||
getAWSConfig: jest.fn(() => ({ region: 'us-east-1' })),
|
||||
getAWSCredentials: jest.fn()
|
||||
}));
|
||||
|
||||
const DamageAssessmentService = require('../../../services/damageAssessmentService');
|
||||
const { Rental, Item } = require('../../../models');
|
||||
const LateReturnService = require('../../../services/lateReturnService');
|
||||
const emailService = require('../../../services/emailService');
|
||||
|
||||
describe('DamageAssessmentService', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('processDamageAssessment', () => {
|
||||
let mockRental;
|
||||
let mockDamageInfo;
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mockRental for each test to avoid state pollution
|
||||
mockRental = {
|
||||
id: 'rental-123',
|
||||
ownerId: 'owner-789',
|
||||
renterId: 'renter-456',
|
||||
status: 'active',
|
||||
item: { name: 'Test Camera', dailyRate: 100 },
|
||||
update: jest.fn().mockResolvedValue({
|
||||
id: 'rental-123',
|
||||
status: 'damaged',
|
||||
damageFees: 500
|
||||
})
|
||||
};
|
||||
|
||||
mockDamageInfo = {
|
||||
description: 'Camera lens is cracked and unusable',
|
||||
canBeFixed: false,
|
||||
needsReplacement: true,
|
||||
replacementCost: 500,
|
||||
photos: ['photo1.jpg', 'photo2.jpg'],
|
||||
proofOfOwnership: ['receipt.pdf']
|
||||
};
|
||||
|
||||
Rental.findByPk.mockResolvedValue(mockRental);
|
||||
LateReturnService.processLateReturn.mockResolvedValue({
|
||||
lateCalculation: { lateFee: 0, isLate: false }
|
||||
});
|
||||
emailService.sendDamageReportToCustomerService.mockResolvedValue();
|
||||
});
|
||||
|
||||
it('should process damage assessment for replacement', async () => {
|
||||
const result = await DamageAssessmentService.processDamageAssessment(
|
||||
'rental-123',
|
||||
mockDamageInfo,
|
||||
'owner-789'
|
||||
);
|
||||
|
||||
expect(mockRental.update).toHaveBeenCalledWith({
|
||||
status: 'damaged',
|
||||
damageFees: 500,
|
||||
damageAssessment: expect.objectContaining({
|
||||
description: 'Camera lens is cracked and unusable',
|
||||
canBeFixed: false,
|
||||
needsReplacement: true,
|
||||
replacementCost: 500,
|
||||
feeCalculation: expect.objectContaining({
|
||||
type: 'replacement',
|
||||
amount: 500
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
expect(emailService.sendDamageReportToCustomerService).toHaveBeenCalled();
|
||||
expect(result.totalAdditionalFees).toBe(500);
|
||||
});
|
||||
|
||||
it('should process damage assessment for repair', async () => {
|
||||
const repairInfo = {
|
||||
description: 'Lens needs professional cleaning and adjustment',
|
||||
canBeFixed: true,
|
||||
needsReplacement: false,
|
||||
repairCost: 150
|
||||
};
|
||||
|
||||
mockRental.update.mockResolvedValue({
|
||||
...mockRental,
|
||||
status: 'damaged',
|
||||
damageFees: 150
|
||||
});
|
||||
|
||||
const result = await DamageAssessmentService.processDamageAssessment(
|
||||
'rental-123',
|
||||
repairInfo,
|
||||
'owner-789'
|
||||
);
|
||||
|
||||
expect(mockRental.update).toHaveBeenCalledWith({
|
||||
status: 'damaged',
|
||||
damageFees: 150,
|
||||
damageAssessment: expect.objectContaining({
|
||||
canBeFixed: true,
|
||||
needsReplacement: false,
|
||||
repairCost: 150,
|
||||
feeCalculation: expect.objectContaining({
|
||||
type: 'repair',
|
||||
amount: 150
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
expect(result.totalAdditionalFees).toBe(150);
|
||||
});
|
||||
|
||||
it('should include late fees when provided', async () => {
|
||||
const actualReturnDateTime = new Date('2023-06-01T14:00:00Z');
|
||||
|
||||
LateReturnService.processLateReturn.mockResolvedValue({
|
||||
lateCalculation: { lateFee: 50, isLate: true }
|
||||
});
|
||||
|
||||
mockRental.update.mockResolvedValue({
|
||||
...mockRental,
|
||||
status: 'damaged',
|
||||
damageFees: 500,
|
||||
lateFees: 50
|
||||
});
|
||||
|
||||
const result = await DamageAssessmentService.processDamageAssessment(
|
||||
'rental-123',
|
||||
{ ...mockDamageInfo, actualReturnDateTime },
|
||||
'owner-789'
|
||||
);
|
||||
|
||||
expect(LateReturnService.processLateReturn).toHaveBeenCalledWith(
|
||||
'rental-123',
|
||||
actualReturnDateTime,
|
||||
'Item returned damaged: Camera lens is cracked and unusable'
|
||||
);
|
||||
|
||||
expect(result.totalAdditionalFees).toBe(550); // 500 damage + 50 late fee
|
||||
});
|
||||
|
||||
it('should throw error when rental not found', async () => {
|
||||
Rental.findByPk.mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
DamageAssessmentService.processDamageAssessment(
|
||||
'nonexistent',
|
||||
mockDamageInfo,
|
||||
'owner-789'
|
||||
)
|
||||
).rejects.toThrow('Rental not found');
|
||||
});
|
||||
|
||||
it('should validate authorization - only owner can report', async () => {
|
||||
await expect(
|
||||
DamageAssessmentService.processDamageAssessment(
|
||||
'rental-123',
|
||||
mockDamageInfo,
|
||||
'renter-456'
|
||||
)
|
||||
).rejects.toThrow('Only the item owner can report damage');
|
||||
});
|
||||
|
||||
it('should validate rental status - only active rentals', async () => {
|
||||
mockRental.status = 'completed';
|
||||
|
||||
await expect(
|
||||
DamageAssessmentService.processDamageAssessment(
|
||||
'rental-123',
|
||||
mockDamageInfo,
|
||||
'owner-789'
|
||||
)
|
||||
).rejects.toThrow('Can only assess damage for active rentals');
|
||||
});
|
||||
|
||||
it('should validate required fields - description', async () => {
|
||||
await expect(
|
||||
DamageAssessmentService.processDamageAssessment(
|
||||
'rental-123',
|
||||
{ ...mockDamageInfo, description: '' },
|
||||
'owner-789'
|
||||
)
|
||||
).rejects.toThrow('Damage description is required');
|
||||
});
|
||||
|
||||
it('should validate required fields - repair cost', async () => {
|
||||
await expect(
|
||||
DamageAssessmentService.processDamageAssessment(
|
||||
'rental-123',
|
||||
{
|
||||
description: 'Needs repair',
|
||||
canBeFixed: true,
|
||||
needsReplacement: false
|
||||
},
|
||||
'owner-789'
|
||||
)
|
||||
).rejects.toThrow('Repair cost is required when item can be fixed');
|
||||
});
|
||||
|
||||
it('should validate required fields - replacement cost', async () => {
|
||||
await expect(
|
||||
DamageAssessmentService.processDamageAssessment(
|
||||
'rental-123',
|
||||
{
|
||||
description: 'Needs replacement',
|
||||
canBeFixed: false,
|
||||
needsReplacement: true
|
||||
},
|
||||
'owner-789'
|
||||
)
|
||||
).rejects.toThrow('Replacement cost is required when item needs replacement');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user