// 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('Test'), })); }); 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', }) ); }); }); });