more backend unit test coverage

This commit is contained in:
jackiettran
2026-01-18 19:18:35 -05:00
parent e6c56ae90f
commit 41d8cf4c04
18 changed files with 4961 additions and 1 deletions

View File

@@ -0,0 +1,217 @@
// Mock dependencies
jest.mock('../../../../../services/email/core/EmailClient', () => {
return jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockResolvedValue(),
sendEmail: jest.fn().mockResolvedValue({ success: true, messageId: 'msg-123' }),
}));
});
jest.mock('../../../../../services/email/core/TemplateManager', () => {
return jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockResolvedValue(),
renderTemplate: jest.fn().mockResolvedValue('<html>Test</html>'),
}));
});
const AuthEmailService = require('../../../../../services/email/domain/AuthEmailService');
describe('AuthEmailService', () => {
let service;
const originalEnv = process.env;
beforeEach(() => {
jest.clearAllMocks();
process.env = { ...originalEnv, FRONTEND_URL: 'http://localhost:3000' };
service = new AuthEmailService();
});
afterEach(() => {
process.env = originalEnv;
});
describe('initialize', () => {
it('should initialize only once', async () => {
await service.initialize();
await service.initialize();
expect(service.emailClient.initialize).toHaveBeenCalledTimes(1);
expect(service.templateManager.initialize).toHaveBeenCalledTimes(1);
});
});
describe('sendVerificationEmail', () => {
it('should send verification email with correct variables', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
const token = 'verify-token';
const result = await service.sendVerificationEmail(user, token);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'emailVerificationToUser',
expect.objectContaining({
recipientName: 'John',
verificationUrl: 'http://localhost:3000/verify-email?token=verify-token',
})
);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'john@example.com',
'Verify Your Email - Village Share',
expect.any(String)
);
});
it('should use default name when firstName is missing', async () => {
const user = { email: 'john@example.com' };
const token = 'verify-token';
await service.sendVerificationEmail(user, token);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'emailVerificationToUser',
expect.objectContaining({ recipientName: 'there' })
);
});
});
describe('sendPasswordResetEmail', () => {
it('should send password reset email with reset URL', async () => {
const user = { firstName: 'Jane', email: 'jane@example.com' };
const token = 'reset-token';
const result = await service.sendPasswordResetEmail(user, token);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'passwordResetToUser',
expect.objectContaining({
recipientName: 'Jane',
resetUrl: 'http://localhost:3000/reset-password?token=reset-token',
})
);
});
});
describe('sendPasswordChangedEmail', () => {
it('should send password changed confirmation', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
const result = await service.sendPasswordChangedEmail(user);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'passwordChangedToUser',
expect.objectContaining({
recipientName: 'John',
email: 'john@example.com',
timestamp: expect.any(String),
})
);
});
});
describe('sendPersonalInfoChangedEmail', () => {
it('should send personal info changed notification', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
const result = await service.sendPersonalInfoChangedEmail(user);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'personalInfoChangedToUser',
expect.objectContaining({ recipientName: 'John' })
);
});
});
describe('sendTwoFactorOtpEmail', () => {
it('should send OTP code email', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
const otpCode = '123456';
const result = await service.sendTwoFactorOtpEmail(user, otpCode);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'twoFactorOtpToUser',
expect.objectContaining({
recipientName: 'John',
otpCode: '123456',
})
);
});
});
describe('sendTwoFactorEnabledEmail', () => {
it('should send 2FA enabled confirmation', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
const result = await service.sendTwoFactorEnabledEmail(user);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'twoFactorEnabledToUser',
expect.objectContaining({ recipientName: 'John' })
);
});
});
describe('sendTwoFactorDisabledEmail', () => {
it('should send 2FA disabled notification', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
const result = await service.sendTwoFactorDisabledEmail(user);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'twoFactorDisabledToUser',
expect.objectContaining({ recipientName: 'John' })
);
});
});
describe('sendRecoveryCodeUsedEmail', () => {
it('should send recovery code used notification with green color for many codes', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
const result = await service.sendRecoveryCodeUsedEmail(user, 8);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'recoveryCodeUsedToUser',
expect.objectContaining({
remainingCodes: 8,
remainingCodesColor: '#28a745',
lowCodesWarning: false,
})
);
});
it('should use orange color for medium remaining codes', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
await service.sendRecoveryCodeUsedEmail(user, 4);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'recoveryCodeUsedToUser',
expect.objectContaining({
remainingCodesColor: '#fd7e14',
})
);
});
it('should use red color and warning for low remaining codes', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
await service.sendRecoveryCodeUsedEmail(user, 1);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'recoveryCodeUsedToUser',
expect.objectContaining({
remainingCodesColor: '#dc3545',
lowCodesWarning: true,
})
);
});
});
});

View File

@@ -0,0 +1,166 @@
// Mock dependencies
jest.mock('../../../../../services/email/core/EmailClient', () => {
return jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockResolvedValue(),
sendEmail: jest.fn().mockResolvedValue({ success: true, messageId: 'msg-123' }),
}));
});
jest.mock('../../../../../services/email/core/TemplateManager', () => {
return jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockResolvedValue(),
renderTemplate: jest.fn().mockResolvedValue('<html>Test</html>'),
}));
});
const FeedbackEmailService = require('../../../../../services/email/domain/FeedbackEmailService');
describe('FeedbackEmailService', () => {
let service;
const originalEnv = process.env;
beforeEach(() => {
jest.clearAllMocks();
process.env = { ...originalEnv, FEEDBACK_EMAIL: 'feedback@example.com' };
service = new FeedbackEmailService();
});
afterEach(() => {
process.env = originalEnv;
});
describe('initialize', () => {
it('should initialize only once', async () => {
await service.initialize();
await service.initialize();
expect(service.emailClient.initialize).toHaveBeenCalledTimes(1);
expect(service.templateManager.initialize).toHaveBeenCalledTimes(1);
});
});
describe('sendFeedbackConfirmation', () => {
it('should send feedback confirmation to user', async () => {
const user = { firstName: 'John', email: 'john@example.com' };
const feedback = {
feedbackText: 'Great app!',
createdAt: new Date(),
};
const result = await service.sendFeedbackConfirmation(user, feedback);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'feedbackConfirmationToUser',
expect.objectContaining({
userName: 'John',
userEmail: 'john@example.com',
feedbackText: 'Great app!',
})
);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'john@example.com',
'Thank You for Your Feedback - Village Share',
expect.any(String)
);
});
it('should use default name when firstName is missing', async () => {
const user = { email: 'john@example.com' };
const feedback = {
feedbackText: 'Great app!',
createdAt: new Date(),
};
await service.sendFeedbackConfirmation(user, feedback);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'feedbackConfirmationToUser',
expect.objectContaining({ userName: 'there' })
);
});
});
describe('sendFeedbackNotificationToAdmin', () => {
it('should send feedback notification to admin', async () => {
const user = {
id: 'user-123',
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
};
const feedback = {
id: 'feedback-123',
feedbackText: 'Great app!',
url: 'https://example.com/page',
userAgent: 'Mozilla/5.0',
createdAt: new Date(),
};
const result = await service.sendFeedbackNotificationToAdmin(user, feedback);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'feedbackNotificationToAdmin',
expect.objectContaining({
userName: 'John Doe',
userEmail: 'john@example.com',
userId: 'user-123',
feedbackText: 'Great app!',
feedbackId: 'feedback-123',
url: 'https://example.com/page',
userAgent: 'Mozilla/5.0',
})
);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'feedback@example.com',
'New Feedback from John Doe',
expect.any(String)
);
});
it('should return error when no admin email configured', async () => {
delete process.env.FEEDBACK_EMAIL;
delete process.env.CUSTOMER_SUPPORT_EMAIL;
const user = { id: 'user-123', firstName: 'John', lastName: 'Doe', email: 'john@example.com' };
const feedback = { id: 'feedback-123', feedbackText: 'Test', createdAt: new Date() };
const result = await service.sendFeedbackNotificationToAdmin(user, feedback);
expect(result.success).toBe(false);
expect(result.error).toContain('No admin email configured');
});
it('should use CUSTOMER_SUPPORT_EMAIL when FEEDBACK_EMAIL not set', async () => {
delete process.env.FEEDBACK_EMAIL;
process.env.CUSTOMER_SUPPORT_EMAIL = 'support@example.com';
const user = { id: 'user-123', firstName: 'John', lastName: 'Doe', email: 'john@example.com' };
const feedback = { id: 'feedback-123', feedbackText: 'Test', createdAt: new Date() };
await service.sendFeedbackNotificationToAdmin(user, feedback);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'support@example.com',
expect.any(String),
expect.any(String)
);
});
it('should use default values for optional fields', async () => {
const user = { id: 'user-123', firstName: 'John', lastName: 'Doe', email: 'john@example.com' };
const feedback = { id: 'feedback-123', feedbackText: 'Test', createdAt: new Date() };
await service.sendFeedbackNotificationToAdmin(user, feedback);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'feedbackNotificationToAdmin',
expect.objectContaining({
url: 'Not provided',
userAgent: 'Not provided',
})
);
});
});
});

View File

@@ -0,0 +1,220 @@
// Mock dependencies
jest.mock('../../../../../services/email/core/EmailClient', () => {
return jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockResolvedValue(),
sendEmail: jest.fn().mockResolvedValue({ success: true, messageId: 'msg-123' }),
}));
});
jest.mock('../../../../../services/email/core/TemplateManager', () => {
return jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockResolvedValue(),
renderTemplate: jest.fn().mockResolvedValue('<html>Test</html>'),
}));
});
jest.mock('../../../../../utils/logger', () => ({
info: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
}));
const ForumEmailService = require('../../../../../services/email/domain/ForumEmailService');
describe('ForumEmailService', () => {
let service;
const originalEnv = process.env;
beforeEach(() => {
jest.clearAllMocks();
process.env = { ...originalEnv, FRONTEND_URL: 'http://localhost:3000' };
service = new ForumEmailService();
});
afterEach(() => {
process.env = originalEnv;
});
describe('initialize', () => {
it('should initialize only once', async () => {
await service.initialize();
await service.initialize();
expect(service.emailClient.initialize).toHaveBeenCalledTimes(1);
});
});
describe('sendForumCommentNotification', () => {
it('should send comment notification to post author', async () => {
const postAuthor = { firstName: 'John', email: 'john@example.com' };
const commenter = { firstName: 'Jane', lastName: 'Doe' };
const post = { id: 123, title: 'Test Post' };
const comment = { content: 'Great post!', createdAt: new Date() };
const result = await service.sendForumCommentNotification(postAuthor, commenter, post, comment);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'forumCommentToPostAuthor',
expect.objectContaining({
postAuthorName: 'John',
commenterName: 'Jane Doe',
postTitle: 'Test Post',
commentContent: 'Great post!',
})
);
});
it('should handle errors gracefully', async () => {
service.templateManager.renderTemplate.mockRejectedValue(new Error('Template error'));
const result = await service.sendForumCommentNotification(
{ email: 'test@example.com' },
{ firstName: 'Jane', lastName: 'Doe' },
{ id: 1, title: 'Test' },
{ content: 'Test', createdAt: new Date() }
);
expect(result.success).toBe(false);
expect(result.error).toContain('Template error');
});
});
describe('sendForumReplyNotification', () => {
it('should send reply notification to comment author', async () => {
const commentAuthor = { firstName: 'John', email: 'john@example.com' };
const replier = { firstName: 'Jane', lastName: 'Doe' };
const post = { id: 123, title: 'Test Post' };
const reply = { content: 'Good point!', createdAt: new Date() };
const parentComment = { content: 'Original comment' };
const result = await service.sendForumReplyNotification(
commentAuthor, replier, post, reply, parentComment
);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'forumReplyToCommentAuthor',
expect.objectContaining({
commentAuthorName: 'John',
replierName: 'Jane Doe',
parentCommentContent: 'Original comment',
replyContent: 'Good point!',
})
);
});
});
describe('sendForumAnswerAcceptedNotification', () => {
it('should send answer accepted notification', async () => {
const commentAuthor = { firstName: 'John', email: 'john@example.com' };
const postAuthor = { firstName: 'Jane', lastName: 'Doe' };
const post = { id: 123, title: 'Test Question' };
const comment = { content: 'The answer is...' };
const result = await service.sendForumAnswerAcceptedNotification(
commentAuthor, postAuthor, post, comment
);
expect(result.success).toBe(true);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'john@example.com',
'Your comment was marked as the accepted answer!',
expect.any(String)
);
});
});
describe('sendForumThreadActivityNotification', () => {
it('should send thread activity notification', async () => {
const participant = { firstName: 'John', email: 'john@example.com' };
const commenter = { firstName: 'Jane', lastName: 'Doe' };
const post = { id: 123, title: 'Test Post' };
const comment = { content: 'New comment', createdAt: new Date() };
const result = await service.sendForumThreadActivityNotification(
participant, commenter, post, comment
);
expect(result.success).toBe(true);
});
});
describe('sendForumPostClosedNotification', () => {
it('should send post closed notification', async () => {
const recipient = { firstName: 'John', email: 'john@example.com' };
const closer = { firstName: 'Admin', lastName: 'User' };
const post = { id: 123, title: 'Test Post' };
const closedAt = new Date();
const result = await service.sendForumPostClosedNotification(
recipient, closer, post, closedAt
);
expect(result.success).toBe(true);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'john@example.com',
'Discussion closed: Test Post',
expect.any(String)
);
});
});
describe('sendForumPostDeletionNotification', () => {
it('should send post deletion notification', async () => {
const postAuthor = { firstName: 'John', email: 'john@example.com' };
const admin = { firstName: 'Admin', lastName: 'User' };
const post = { title: 'Deleted Post' };
const deletionReason = 'Violated community guidelines';
const result = await service.sendForumPostDeletionNotification(
postAuthor, admin, post, deletionReason
);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'forumPostDeletionToAuthor',
expect.objectContaining({
deletionReason: 'Violated community guidelines',
})
);
});
});
describe('sendForumCommentDeletionNotification', () => {
it('should send comment deletion notification', async () => {
const commentAuthor = { firstName: 'John', email: 'john@example.com' };
const admin = { firstName: 'Admin', lastName: 'User' };
const post = { id: 123, title: 'Test Post' };
const deletionReason = 'Violated community guidelines';
const result = await service.sendForumCommentDeletionNotification(
commentAuthor, admin, post, deletionReason
);
expect(result.success).toBe(true);
});
});
describe('sendItemRequestNotification', () => {
it('should send item request notification to nearby users', async () => {
const recipient = { firstName: 'John', email: 'john@example.com' };
const requester = { firstName: 'Jane', lastName: 'Doe' };
const post = { id: 123, title: 'Looking for a Drill', content: 'Need a power drill for the weekend' };
const distance = '2.5';
const result = await service.sendItemRequestNotification(
recipient, requester, post, distance
);
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'forumItemRequestNotification',
expect.objectContaining({
itemRequested: 'Looking for a Drill',
distance: '2.5',
})
);
});
});
});

View File

@@ -0,0 +1,243 @@
// Mock dependencies
jest.mock('../../../../../services/email/core/EmailClient', () => {
return jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockResolvedValue(),
sendEmail: jest.fn().mockResolvedValue({ success: true, messageId: 'msg-123' }),
}));
});
jest.mock('../../../../../services/email/core/TemplateManager', () => {
return jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockResolvedValue(),
renderTemplate: jest.fn().mockResolvedValue('<html>Test</html>'),
}));
});
jest.mock('../../../../../utils/logger', () => ({
info: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
}));
const PaymentEmailService = require('../../../../../services/email/domain/PaymentEmailService');
describe('PaymentEmailService', () => {
let service;
const originalEnv = process.env;
beforeEach(() => {
jest.clearAllMocks();
process.env = {
...originalEnv,
FRONTEND_URL: 'http://localhost:3000',
ADMIN_EMAIL: 'admin@example.com',
};
service = new PaymentEmailService();
});
afterEach(() => {
process.env = originalEnv;
});
describe('initialize', () => {
it('should initialize only once', async () => {
await service.initialize();
await service.initialize();
expect(service.emailClient.initialize).toHaveBeenCalledTimes(1);
});
});
describe('sendPaymentDeclinedNotification', () => {
it('should send payment declined notification to renter', async () => {
const result = await service.sendPaymentDeclinedNotification('renter@example.com', {
renterFirstName: 'John',
itemName: 'Test Item',
declineReason: 'Card declined',
updatePaymentUrl: 'http://localhost:3000/update-payment',
});
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'paymentDeclinedToRenter',
expect.objectContaining({
renterFirstName: 'John',
itemName: 'Test Item',
declineReason: 'Card declined',
})
);
});
it('should use default values for missing params', async () => {
await service.sendPaymentDeclinedNotification('renter@example.com', {});
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'paymentDeclinedToRenter',
expect.objectContaining({
renterFirstName: 'there',
itemName: 'the item',
})
);
});
it('should handle errors gracefully', async () => {
service.templateManager.renderTemplate.mockRejectedValue(new Error('Template error'));
const result = await service.sendPaymentDeclinedNotification('test@example.com', {});
expect(result.success).toBe(false);
expect(result.error).toContain('Template error');
});
});
describe('sendPaymentMethodUpdatedNotification', () => {
it('should send payment method updated notification to owner', async () => {
const result = await service.sendPaymentMethodUpdatedNotification('owner@example.com', {
ownerFirstName: 'Jane',
itemName: 'Test Item',
approvalUrl: 'http://localhost:3000/approve',
});
expect(result.success).toBe(true);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'owner@example.com',
'Payment Method Updated - Test Item',
expect.any(String)
);
});
});
describe('sendPayoutFailedNotification', () => {
it('should send payout failed notification to owner', async () => {
const result = await service.sendPayoutFailedNotification('owner@example.com', {
ownerName: 'John',
payoutAmount: 50.00,
failureMessage: 'Bank account closed',
actionRequired: 'Please update your bank account',
failureCode: 'account_closed',
requiresBankUpdate: true,
});
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'payoutFailedToOwner',
expect.objectContaining({
ownerName: 'John',
payoutAmount: '50.00',
failureCode: 'account_closed',
requiresBankUpdate: true,
})
);
});
});
describe('sendAccountDisconnectedEmail', () => {
it('should send account disconnected notification', async () => {
const result = await service.sendAccountDisconnectedEmail('owner@example.com', {
ownerName: 'John',
hasPendingPayouts: true,
pendingPayoutCount: 3,
});
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'accountDisconnectedToOwner',
expect.objectContaining({
hasPendingPayouts: true,
pendingPayoutCount: 3,
})
);
});
it('should use default values for missing params', async () => {
await service.sendAccountDisconnectedEmail('owner@example.com', {});
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'accountDisconnectedToOwner',
expect.objectContaining({
ownerName: 'there',
hasPendingPayouts: false,
pendingPayoutCount: 0,
})
);
});
});
describe('sendPayoutsDisabledEmail', () => {
it('should send payouts disabled notification', async () => {
const result = await service.sendPayoutsDisabledEmail('owner@example.com', {
ownerName: 'John',
disabledReason: 'Verification required',
});
expect(result.success).toBe(true);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'owner@example.com',
'Action Required: Your payouts have been paused - Village Share',
expect.any(String)
);
});
});
describe('sendDisputeAlertEmail', () => {
it('should send dispute alert to admin', async () => {
const result = await service.sendDisputeAlertEmail({
rentalId: 'rental-123',
amount: 50.00,
reason: 'fraudulent',
evidenceDueBy: new Date(),
renterName: 'Renter Name',
renterEmail: 'renter@example.com',
ownerName: 'Owner Name',
ownerEmail: 'owner@example.com',
itemName: 'Test Item',
});
expect(result.success).toBe(true);
expect(service.emailClient.sendEmail).toHaveBeenCalledWith(
'admin@example.com',
'URGENT: Payment Dispute - Rental #rental-123',
expect.any(String)
);
});
});
describe('sendDisputeLostAlertEmail', () => {
it('should send dispute lost alert to admin', async () => {
const result = await service.sendDisputeLostAlertEmail({
rentalId: 'rental-123',
amount: 50.00,
ownerPayoutAmount: 45.00,
ownerName: 'Owner Name',
ownerEmail: 'owner@example.com',
});
expect(result.success).toBe(true);
expect(service.templateManager.renderTemplate).toHaveBeenCalledWith(
'disputeLostAlertToAdmin',
expect.objectContaining({
rentalId: 'rental-123',
amount: '50.00',
ownerPayoutAmount: '45.00',
})
);
});
});
describe('formatDisputeReason', () => {
it('should format known dispute reasons', () => {
expect(service.formatDisputeReason('fraudulent')).toBe('Fraudulent transaction');
expect(service.formatDisputeReason('product_not_received')).toBe('Product not received');
expect(service.formatDisputeReason('duplicate')).toBe('Duplicate charge');
});
it('should return original reason for unknown reasons', () => {
expect(service.formatDisputeReason('unknown_reason')).toBe('unknown_reason');
});
it('should return "Unknown reason" for null/undefined', () => {
expect(service.formatDisputeReason(null)).toBe('Unknown reason');
expect(service.formatDisputeReason(undefined)).toBe('Unknown reason');
});
});
});