- Add comprehensive tests for email service functionality - Test email validation, sending capabilities, and error handling - Improve service test coverage and reliability - Ensure email operations work correctly in test environment This adds another layer of service testing infrastructure.
211 lines
6.5 KiB
TypeScript
211 lines
6.5 KiB
TypeScript
import { EmailService, emailService } from '../email';
|
|
|
|
// Mock console methods
|
|
const mockConsoleWarn = jest.fn();
|
|
const mockConsoleLog = jest.fn();
|
|
|
|
describe('EmailService', () => {
|
|
let service: EmailService;
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
console.warn = mockConsoleWarn;
|
|
console.log = mockConsoleLog;
|
|
service = new EmailService();
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
describe('constructor', () => {
|
|
test('should create a new EmailService instance', () => {
|
|
expect(service).toBeInstanceOf(EmailService);
|
|
});
|
|
});
|
|
|
|
describe('sendVerificationEmail', () => {
|
|
test('should log verification email details', async () => {
|
|
const email = 'test@example.com';
|
|
const token = 'test-token-123';
|
|
|
|
await service.sendVerificationEmail(email, token);
|
|
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`📧 Sending verification email to ${email} with token: ${token}`
|
|
);
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`🔗 Verification link: /verify-email?token=${token}`
|
|
);
|
|
expect(mockConsoleWarn).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
test('should handle empty email gracefully', async () => {
|
|
const email = '';
|
|
const token = 'test-token-123';
|
|
|
|
await service.sendVerificationEmail(email, token);
|
|
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`📧 Sending verification email to ${email} with token: ${token}`
|
|
);
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`🔗 Verification link: /verify-email?token=${token}`
|
|
);
|
|
});
|
|
|
|
test('should handle empty token gracefully', async () => {
|
|
const email = 'test@example.com';
|
|
const token = '';
|
|
|
|
await service.sendVerificationEmail(email, token);
|
|
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`📧 Sending verification email to ${email} with token: ${token}`
|
|
);
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`🔗 Verification link: /verify-email?token=${token}`
|
|
);
|
|
});
|
|
|
|
test('should handle special characters in email and token', async () => {
|
|
const email = 'test+user@example-domain.com';
|
|
const token = 'abc123!@#$%^&*()_+-={}[]|\\:";\'<>?,./';
|
|
|
|
await service.sendVerificationEmail(email, token);
|
|
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`📧 Sending verification email to ${email} with token: ${token}`
|
|
);
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`🔗 Verification link: /verify-email?token=${token}`
|
|
);
|
|
});
|
|
|
|
test('should simulate network delay', async () => {
|
|
const email = 'test@example.com';
|
|
const token = 'test-token-123';
|
|
|
|
const startTime = Date.now();
|
|
await service.sendVerificationEmail(email, token);
|
|
const endTime = Date.now();
|
|
|
|
// Should take at least 500ms due to the simulated delay
|
|
expect(endTime - startTime).toBeGreaterThanOrEqual(450); // Allow some margin for test execution
|
|
});
|
|
|
|
test('should complete successfully without throwing errors', async () => {
|
|
const email = 'test@example.com';
|
|
const token = 'test-token-123';
|
|
|
|
await expect(
|
|
service.sendVerificationEmail(email, token)
|
|
).resolves.toBeUndefined();
|
|
});
|
|
|
|
test('should handle very long email addresses', async () => {
|
|
const email = 'a'.repeat(100) + '@' + 'b'.repeat(100) + '.com';
|
|
const token = 'test-token-123';
|
|
|
|
await service.sendVerificationEmail(email, token);
|
|
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`📧 Sending verification email to ${email} with token: ${token}`
|
|
);
|
|
});
|
|
|
|
test('should handle very long tokens', async () => {
|
|
const email = 'test@example.com';
|
|
const token = 'a'.repeat(1000);
|
|
|
|
await service.sendVerificationEmail(email, token);
|
|
|
|
expect(mockConsoleWarn).toHaveBeenCalledWith(
|
|
`🔗 Verification link: /verify-email?token=${token}`
|
|
);
|
|
});
|
|
|
|
test('should handle null and undefined inputs gracefully', async () => {
|
|
// Test with null values
|
|
await service.sendVerificationEmail(null as any, null as any);
|
|
expect(mockConsoleWarn).toHaveBeenCalled();
|
|
|
|
jest.clearAllMocks();
|
|
|
|
// Test with undefined values
|
|
await service.sendVerificationEmail(undefined as any, undefined as any);
|
|
expect(mockConsoleWarn).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('emailService singleton', () => {
|
|
test('should export a singleton instance', () => {
|
|
expect(emailService).toBeInstanceOf(EmailService);
|
|
});
|
|
|
|
test('should be the same instance when imported multiple times', () => {
|
|
// This test verifies that the exported emailService is a singleton
|
|
const { emailService: secondImport } = require('../email');
|
|
expect(emailService).toBe(secondImport);
|
|
});
|
|
|
|
test('should have the sendVerificationEmail method', () => {
|
|
expect(typeof emailService.sendVerificationEmail).toBe('function');
|
|
});
|
|
});
|
|
|
|
describe('method return values', () => {
|
|
test('sendVerificationEmail should return a Promise that resolves to void', async () => {
|
|
const result = await service.sendVerificationEmail(
|
|
'test@example.com',
|
|
'token'
|
|
);
|
|
expect(result).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('console output format', () => {
|
|
test('should use emoji prefixes for visual identification', async () => {
|
|
const email = 'test@example.com';
|
|
const token = 'test-token-123';
|
|
|
|
await service.sendVerificationEmail(email, token);
|
|
|
|
const [firstCall, secondCall] = mockConsoleWarn.mock.calls;
|
|
expect(firstCall[0]).toMatch(/^📧/);
|
|
expect(secondCall[0]).toMatch(/^🔗/);
|
|
});
|
|
|
|
test('should format verification link consistently', async () => {
|
|
const email = 'test@example.com';
|
|
const token = 'test-token-123';
|
|
|
|
await service.sendVerificationEmail(email, token);
|
|
|
|
const secondCall = mockConsoleWarn.mock.calls[1];
|
|
expect(secondCall[0]).toBe(
|
|
`🔗 Verification link: /verify-email?token=${token}`
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('error handling', () => {
|
|
test('should not throw errors even with malformed inputs', async () => {
|
|
const testCases = [
|
|
['', ''],
|
|
[null, null],
|
|
[undefined, undefined],
|
|
['invalid-email', 'token'],
|
|
['test@example.com', null],
|
|
[null, 'token'],
|
|
];
|
|
|
|
for (const [email, token] of testCases) {
|
|
await expect(
|
|
service.sendVerificationEmail(email as any, token as any)
|
|
).resolves.not.toThrow();
|
|
}
|
|
});
|
|
});
|
|
});
|