Mirror of https://github.com/roostorg/coop github.com/roostorg/coop
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 557ff54b2b435e5f1e789c6a8a4e1bebf2d7deb6 165 lines 5.0 kB view raw
1import { type SESClient, SendEmailCommand } from '@aws-sdk/client-ses'; 2 3import makeSendEmail, { 4 CoopEmailAddress, 5 makeSendEmailViaSendGrid, 6 type Message, 7} from './sendEmailService.js'; 8 9function makeMockClient() { 10 const mockSend = jest.fn().mockResolvedValue({ MessageId: 'test-message-id' }); 11 const mockClient = { send: mockSend } as unknown as SESClient; 12 return { mockSend, mockClient }; 13} 14 15describe('sendEmailService', () => { 16 describe('SES backend (default)', () => { 17 it('should create a function', () => { 18 const { mockClient } = makeMockClient(); 19 const sendEmail = makeSendEmail(mockClient); 20 expect(typeof sendEmail).toBe('function'); 21 }); 22 23 it('should send email with correct SES parameters', async () => { 24 const { mockSend, mockClient } = makeMockClient(); 25 const sendEmail = makeSendEmail(mockClient); 26 27 const msg: Message = { 28 to: 'recipient@example.com', 29 from: CoopEmailAddress.NoReply, 30 subject: 'Test Subject', 31 html: '<p>Hello</p>', 32 }; 33 34 await sendEmail(msg); 35 36 expect(mockSend).toHaveBeenCalledTimes(1); 37 const command = mockSend.mock.calls[0][0]; 38 expect(command).toBeInstanceOf(SendEmailCommand); 39 expect(command.input).toEqual({ 40 Source: CoopEmailAddress.NoReply, 41 Destination: { 42 ToAddresses: ['recipient@example.com'], 43 }, 44 Message: { 45 Subject: { Charset: 'UTF-8', Data: 'Test Subject' }, 46 Body: { 47 Html: { Charset: 'UTF-8', Data: '<p>Hello</p>' }, 48 }, 49 }, 50 }); 51 }); 52 53 it('should format Source as "Name <email>" for object from address', async () => { 54 const { mockSend, mockClient } = makeMockClient(); 55 const sendEmail = makeSendEmail(mockClient); 56 57 const msg: Message = { 58 to: 'recipient@example.com', 59 from: { name: 'Coop', email: CoopEmailAddress.NoReply }, 60 subject: 'Test Subject', 61 html: '<p>Hello</p>', 62 }; 63 64 await sendEmail(msg); 65 66 const command = mockSend.mock.calls[0][0]; 67 expect(command.input.Source).toBe( 68 `Coop <${CoopEmailAddress.NoReply}>`, 69 ); 70 }); 71 72 it('should use Body.Text instead of Body.Html for text content', async () => { 73 const { mockSend, mockClient } = makeMockClient(); 74 const sendEmail = makeSendEmail(mockClient); 75 76 const msg: Message = { 77 to: 'recipient@example.com', 78 from: CoopEmailAddress.NoReply, 79 subject: 'Test Subject', 80 text: 'Hello plain text', 81 }; 82 83 await sendEmail(msg); 84 85 const command = mockSend.mock.calls[0][0]; 86 expect(command.input.Message.Body).toEqual({ 87 Text: { Charset: 'UTF-8', Data: 'Hello plain text' }, 88 }); 89 }); 90 91 it('should pass array directly to ToAddresses', async () => { 92 const { mockSend, mockClient } = makeMockClient(); 93 const sendEmail = makeSendEmail(mockClient); 94 95 const msg: Message = { 96 to: ['a@example.com', 'b@example.com'], 97 from: CoopEmailAddress.NoReply, 98 subject: 'Test', 99 text: 'Hello', 100 }; 101 102 await sendEmail(msg); 103 104 const command = mockSend.mock.calls[0][0]; 105 expect(command.input.Destination.ToAddresses).toEqual([ 106 'a@example.com', 107 'b@example.com', 108 ]); 109 }); 110 111 it('should not throw when SES returns an error', async () => { 112 const { mockSend, mockClient } = makeMockClient(); 113 mockSend.mockRejectedValueOnce(new Error('SES error')); 114 const sendEmail = makeSendEmail(mockClient); 115 116 const msg: Message = { 117 to: 'recipient@example.com', 118 from: CoopEmailAddress.NoReply, 119 subject: 'Test', 120 text: 'Hello', 121 }; 122 123 await expect(sendEmail(msg)).resolves.not.toThrow(); 124 }); 125 126 it('should log the error when SES fails', async () => { 127 const consoleSpy = jest 128 .spyOn(console, 'error') 129 .mockImplementation(() => {}); 130 const { mockSend, mockClient } = makeMockClient(); 131 mockSend.mockRejectedValueOnce(new Error('MessageRejected')); 132 const sendEmail = makeSendEmail(mockClient); 133 134 const msg: Message = { 135 to: 'recipient@example.com', 136 from: CoopEmailAddress.NoReply, 137 subject: 'Test', 138 text: 'Hello', 139 }; 140 141 await sendEmail(msg); 142 143 expect(consoleSpy).toHaveBeenCalledWith( 144 'Failed to send email:', 145 'MessageRejected', 146 ); 147 consoleSpy.mockRestore(); 148 }); 149 }); 150 151 describe('SendGrid backend', () => { 152 it('should create a function when given an API key', () => { 153 const sendEmail = makeSendEmailViaSendGrid('SG.test-key'); 154 expect(typeof sendEmail).toBe('function'); 155 }); 156 }); 157 158 describe('CoopEmailAddress defaults', () => { 159 it('should have default email addresses', () => { 160 expect(CoopEmailAddress.NoReply).toBeDefined(); 161 expect(CoopEmailAddress.Support).toBeDefined(); 162 expect(CoopEmailAddress.Team).toBeDefined(); 163 }); 164 }); 165});