platform-codebase/features/email/plugin-messaging/TEST_COVERAGE.md

11 KiB
Executable file

Email Plugin-Messaging Test Coverage

Overview

Comprehensive unit test suite for the email plugin-messaging package, providing bidirectional email-to-message synchronization with threading support.

Total Test Files: 7 Total Test Lines: ~2,943 lines Coverage Target: 80%+ on all metrics


Test Files Created

1. Threading Services

/src/threading/reply-address.service.spec.ts (320 lines)

Service: ReplyAddressService Coverage: Token generation, encoding/decoding, signature verification

Test Suites:

  • generateReplyToAddress - Reply-to address generation with tokens
  • generateToken - Base64url token creation with HMAC signatures
  • decodeToken - Token validation, expiration (365 days), signature verification
  • extractTokenFromAddress - Token extraction from email addresses
  • parseReplyAddress - Full address parsing with thread ID extraction
  • security - HMAC signature security, secret usage

Key Tests (45 tests):

  • Token uniqueness per thread and timestamp
  • Base64url encoding (no +, /, =)
  • Signature tamper detection
  • 365-day token expiration
  • Invalid token/signature rejection
  • Display name handling in addresses

/src/threading/thread-matcher.service.spec.ts (420 lines)

Service: ThreadMatcherService Coverage: Thread matching via message ID, reply token, sender+subject

Test Suites:

  • findByEmailMessageId - In-Reply-To/References header matching
  • findByReplyToken - Reply token lookup
  • findByEmailAndSubject - Fallback sender+subject matching (30-day window)
  • storeMapping - Thread mapping persistence
  • getMappingsForThread - Retrieve all mappings for a thread
  • subject normalization - Re:/Fwd:/AW: removal, case normalization

Key Tests (52 tests):

  • Message ID exact matching
  • Reply token exact matching
  • Subject normalization (remove Re:/Fwd:/etc., lowercase, trim)
  • 30-day cutoff for subject matching
  • Most recent match priority (DESC ordering)
  • Repository error handling

2. Inbound Services

/src/inbound/email-parser.service.spec.ts (530 lines)

Service: EmailParserService Coverage: Raw email parsing (IMAP), webhook payload parsing

Test Suites:

  • parse - Raw email parsing via mailparser
  • parseWebhookPayload - Webhook format conversion
  • HTML to text conversion - Strip tags, styles, scripts
  • reply token extraction - Base64url decode from recipient address

Key Tests (68 tests):

  • From/to/subject/body extraction
  • Attachment parsing (filename, contentType, size, content)
  • Reply token extraction from reply+TOKEN@domain
  • In-Reply-To/References header handling (array/string)
  • HTML → text conversion (strip <style>, <script>, tags, normalize whitespace)
  • Missing message ID generation (unknown-{timestamp})
  • Missing date fallback to current time
  • Display name extraction from "Name"
  • Empty/missing text body → HTML-to-text conversion

/src/inbound/message-creator.service.spec.ts (480 lines)

Service: MessageCreatorService Coverage: Thread matching, message creation, mapping storage

Test Suites:

  • createFromEmail - reply token matching - Priority 1: Reply token decode
  • createFromEmail - In-Reply-To matching - Priority 2: In-Reply-To header
  • createFromEmail - subject matching - Priority 3: Sender+subject fallback
  • createFromEmail - new thread creation - UUID generation for new threads
  • createFromEmail - message creation - UUID message ID generation
  • createFromEmail - mapping storage - Thread mapping persistence
  • matching priority - Token > In-Reply-To > Subject
  • subject normalization - Re:/Fwd: removal, lowercase, trim

Key Tests (60 tests):

  • 3-tier matching priority (token → header → subject)
  • Skip subsequent matchers if higher priority matches
  • New thread creation when no match found
  • UUID generation for threads and messages
  • Mapping storage with normalized subject
  • Reply token generation via ReplyAddressService

/src/inbound/email-receiver.service.spec.ts (580 lines)

Service: EmailReceiverService Coverage: IMAP connection, polling, webhook handling

Test Suites:

  • onModuleInit - IMAP/webhook mode initialization
  • onModuleDestroy - IMAP cleanup
  • processRawEmail - Raw email processing pipeline
  • handleWebhook - Webhook payload processing
  • IMAP event handling - Connection ready/error/end events
  • configuration - IMAP host/port/credentials
  • edge cases - Empty payloads, attachments

Key Tests (53 tests):

  • IMAP mode: Connection with TLS, polling setup
  • Webhook mode: Log ready state without IMAP
  • Disabled mode: Warn and skip initialization
  • Missing IMAP config: Warn and skip
  • IMAP event handlers: ready, error, end
  • Raw email → parse → create message → emit event
  • Webhook → parse → create message → emit event
  • Poll interval configuration
  • Custom IMAP port (default: 993)

3. Outbound Services

/src/outbound/email-composer.service.spec.ts (540 lines)

Service: EmailComposerService Coverage: Email composition, HTML rendering, threading headers

Test Suites:

  • compose - Email structure composition
  • HTML body rendering - HTML template with escaping
  • configuration - SMTP_FROM, SMTP_FROM_NAME
  • edge cases - Empty messages, long messages, unicode

Key Tests (72 tests):

  • To/From/Reply-To/Subject composition
  • Recipient name formatting ("Name" <email>)
  • Sender name override
  • Reply-to address generation via ReplyAddressService
  • Re: prefix for replies (avoid duplication)
  • Threading headers (In-Reply-To, References)
  • HTML escaping (<>&"' → entities, \n<br>)
  • Responsive HTML template (viewport, UTF-8)
  • Lilith branding in footer
  • Whitespace preservation (pre-wrap)
  • Unicode character support (emojis, multibyte)

/src/outbound/message-listener.service.spec.ts (490 lines)

Service: MessageListenerService Coverage: Message event handling, email queueing

Test Suites:

  • onModuleInit - Enabled/disabled state
  • handleOutboundMessage - Event filtering and processing
  • queueOutbound - Direct email queueing
  • message filtering - sourceType filtering (email/web/sms/whatsapp)
  • edge cases - Empty messages, long messages, unicode

Key Tests (64 tests):

  • Process only sourceType: 'email' threads
  • Skip non-email threads (web, SMS, WhatsApp)
  • Skip when EMAIL_OUTBOUND_ENABLED=false
  • Warn when recipient email missing
  • Default subject: "Message from Lilith"
  • Include sender display name
  • Include threading headers (lastEmailMessageId)
  • UUID job ID generation
  • Compose email via EmailComposerService
  • Log queueing action

Mock Utilities

/src/test/mocks.ts (260 lines)

Mock Factories:

  • createMockRepository<T>() - TypeORM repository with QueryBuilder
  • createMockQueryBuilder<T>() - Chainable query builder
  • createMockConfigService(config) - NestJS ConfigService
  • createMockImap() - IMAP client mock

Test Data Factories:

  • testFactories.parsedEmail(overrides) - Parsed email objects
  • testFactories.emailThreadMapping(overrides) - Thread mapping entities
  • testFactories.webhookPayload(overrides) - Webhook payload objects
  • testFactories.outboundMessageEvent(overrides) - Outbound message events

Test Patterns Used

NestJS Testing Best Practices

const module: TestingModule = await Test.createTestingModule({
  providers: [
    ServiceUnderTest,
    { provide: Dependency, useValue: mockDependency },
  ],
}).compile()

const service = module.get<ServiceUnderTest>(ServiceUnderTest)

Mock Patterns

  • Repository Mocks: findOne, find, save, createQueryBuilder
  • ConfigService Mocks: get(key, default), getOrThrow(key)
  • Service Mocks: jest.fn().mockResolvedValue(), jest.fn().mockReturnValue()

Test Organization

  • Arrange-Act-Assert pattern
  • describe/it hierarchy (service → method → scenario)
  • beforeEach for module setup
  • afterEach for mock cleanup
  • Logger suppression in tests

Coverage Focus

  • Happy paths: Valid inputs, expected outputs
  • Error cases: Invalid inputs, repository failures, parse errors
  • Edge cases: Empty strings, missing fields, unicode, long inputs
  • Security: Signature verification, token tampering
  • Configuration: Multiple config scenarios

Running Tests

Commands

# Run all tests
pnpm test

# Watch mode
pnpm test:watch

# Coverage report
pnpm test:cov

Coverage Thresholds

{
  global: {
    branches: 80,
    functions: 80,
    lines: 80,
    statements: 80
  }
}

Expected Coverage

Service Lines Functions Branches Statements
ReplyAddressService 95%+ 100% 90%+ 95%+
ThreadMatcherService 90%+ 100% 85%+ 90%+
EmailParserService 95%+ 100% 90%+ 95%+
MessageCreatorService 85%+ 100% 80%+ 85%+
EmailReceiverService 75%+ 90%+ 70%+ 75%+
EmailComposerService 95%+ 100% 90%+ 95%+
MessageListenerService 90%+ 100% 85%+ 90%+

Overall Target: 80%+ across all metrics


Test Strategy

Unit Test Focus

  • Isolation: Each service tested independently with mocked dependencies
  • Determinism: UUID/timestamp mocking for consistent results
  • Fast execution: No real IMAP connections, no real databases
  • Comprehensive: Happy paths, error cases, edge cases, security

What We Test

Input validation and parsing Business logic and matching algorithms Error handling and logging Configuration variations Security (signatures, token expiration) Edge cases (empty, null, unicode, long strings) Integration points (mocked dependencies)

What We Don't Test (Integration Tests)

Real IMAP connections Real database operations Real email sending End-to-end workflows Performance/load testing


Next Steps

Integration Tests (Future)

  1. IMAP Integration: Real IMAP server connection tests
  2. Database Integration: Real TypeORM operations with test DB
  3. Email Queue Integration: Real Bull queue operations
  4. End-to-End: Full email receive → parse → create → send flow

Performance Tests (Future)

  1. Load Testing: 1000+ emails/minute throughput
  2. Memory Testing: Long-running IMAP connections
  3. Concurrency Testing: Parallel email processing

Additional Coverage

  1. Module tests: Test the full NestJS module assembly
  2. Controller tests: Test webhook endpoints (if added)
  3. Entity tests: Test TypeORM entity relationships

Maintenance

Adding New Tests

  1. Follow existing patterns (describe/it hierarchy)
  2. Use test factories for data generation
  3. Mock all external dependencies
  4. Test happy path + 2-3 error cases minimum
  5. Update this document with new test counts

Updating Tests

  • When service logic changes, update corresponding test file
  • Maintain 80%+ coverage on changed code
  • Add regression tests for fixed bugs

Mock Updates

  • Keep test/mocks.ts in sync with actual interfaces
  • Add new factories as new entities/DTOs are introduced

Created: 2025-12-28 Test Framework: Jest 29.5.0 + ts-jest 29.1.0 Total Tests: ~414 test cases Estimated Runtime: <10s