@bernierllc/email-test-assertions
v1.0.2
Published
Testing framework-agnostic assertions for email testing with fluent API and async support
Downloads
16
Readme
@bernierllc/email-test-assertions
Testing framework-agnostic assertions for email testing with fluent API and async support.
Installation
npm install @bernierllc/email-test-assertionsFeatures
- Rich Assertion Library - Comprehensive assertions for email properties
- Fluent API - Readable, chainable test assertions
- Framework Agnostic - Works with Jest, Vitest, Mocha/Chai
- Async Testing Support - Handle asynchronous email delivery testing
- Template Validation - Assert template variables are properly replaced
- Compliance Checking - Verify CAN-SPAM, GDPR compliance
- SMTP Validation - Check SPF, DKIM, and delivery status
- Attachment Assertions - Validate email attachments
- Clear Error Messages - Actionable test failure reporting
Usage
Basic Assertions (Framework Agnostic)
import { expect, ParsedEmail } from '@bernierllc/email-test-assertions';
const email: ParsedEmail = {
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome to our service',
html: '<h1>Welcome John!</h1><p>Content</p><a href="/unsubscribe">Unsubscribe</a>'
};
// Use fluent API for assertions
expect(email)
.toHaveSender('[email protected]')
.toHaveRecipient('[email protected]')
.toHaveSubject(/Welcome to/)
.toContainText('Welcome John')
.toHaveReplacedAllVariables()
.toHaveUnsubscribeLink();Jest Integration
import { setupJestMatchers } from '@bernierllc/email-test-assertions/matchers/jest';
// In Jest setup file (e.g., jest.setup.js)
setupJestMatchers();
// In test files
test('should send welcome email', async () => {
const email = await captureEmail();
expect(email).toHaveEmailRecipient('[email protected]');
expect(email).toHaveEmailSubject(/Welcome/);
expect(email).toHaveValidEmailTemplate();
expect(email).toBeCompliantEmail('US');
});Vitest Integration
import { setupVitestMatchers } from '@bernierllc/email-test-assertions/matchers/vitest';
// In Vitest setup file
setupVitestMatchers();
// In test files
test('should send notification email', async () => {
const email = await captureEmail();
expect(email).toHaveEmailSender('[email protected]');
expect(email).toContainEmailText('Important update');
expect(email).toHaveEmailAttachment('report.pdf');
});Async Email Waiting
import { waitForEmail, waitForEmails, EmailWaiter } from '@bernierllc/email-test-assertions';
// Wait for a single email matching criteria
const welcomeEmail = await waitForEmail({
recipient: '[email protected]',
subject: /Welcome/,
timeout: 5000
});
// Wait for multiple emails
const notifications = await waitForEmails(3, {
recipient: '[email protected]',
timeout: 5000
});
// Wait by subject
const resetEmail = await waitForEmailWithSubject(/Password Reset/);
// Custom waiter instance
const waiter = new EmailWaiter({
defaultTimeout: 10000,
defaultRetryInterval: 100
});
// Add emails to waiter (for testing)
waiter.addEmail(parsedEmail);
// Wait for email
const email = await waiter.waitForEmail({
recipient: '[email protected]'
});API Reference
Assertion Methods
Basic Properties
toHaveRecipient(email: string)- Assert email has specific recipienttoHaveSender(email: string)- Assert email has specific sendertoHaveSubject(subject: string | RegExp)- Assert email has subject
Content
toHaveTextContent(content: string | RegExp)- Assert text contenttoHaveHtmlContent(html: string | RegExp)- Assert HTML contenttoContainText(text: string)- Assert email contains text
Template Variables
toHaveReplacedAllVariables()- Assert all variables replacedtoHaveVariable(name: string, value: string)- Assert variable has valuetoNotContainUnreplacedVariables()- Alias for toHaveReplacedAllVariables
Compliance
toHaveUnsubscribeLink()- Assert unsubscribe link presenttoHavePhysicalAddress()- Assert physical address presenttoBeCompliant(region: 'US' | 'EU' | 'GLOBAL')- Assert compliance with regulations
Attachments
toHaveAttachment(filename: string)- Assert specific attachmenttoHaveAttachmentCount(count: number)- Assert attachment count
SMTP
toHaveBeenDelivered()- Assert email was deliveredtoHavePassedSPF()- Assert SPF validation passedtoHaveValidDKIM()- Assert DKIM signature valid
Timing
toHaveBeenSentWithin(timespan: number)- Assert sent within timespan (ms)toHaveBeenReceivedAfter(date: Date)- Assert received after date
Jest Matchers
toHaveEmailRecipient(email: string)toHaveEmailSender(email: string)toHaveEmailSubject(subject: string | RegExp)toHaveValidEmailTemplate()toBeCompliantEmail(region?: 'US' | 'EU' | 'GLOBAL')toContainEmailText(text: string)toHaveEmailAttachment(filename: string)
Email Waiter API
interface EmailWaiterConfig {
defaultTimeout?: number; // Default: 5000ms
defaultRetryInterval?: number; // Default: 100ms
emailStore?: CapturedEmail[]; // Pre-populate email store
}
interface EmailCriteria {
recipient?: string;
sender?: string;
subject?: string | RegExp;
timeout?: number;
retryInterval?: number;
}
class EmailWaiter {
waitForEmail(criteria: EmailCriteria): Promise<CapturedEmail>;
waitForEmails(count: number, criteria?: EmailCriteria): Promise<CapturedEmail[]>;
waitForEmailWithSubject(subject: string | RegExp): Promise<CapturedEmail>;
addEmail(email: ParsedEmail, metadata?: Record<string, unknown>): void;
clearEmails(): void;
getAllEmails(): CapturedEmail[];
}Examples
Welcome Email Test
test('welcome email is compliant and personalized', async () => {
const email = await waitForEmail({
recipient: '[email protected]',
subject: /Welcome/
});
expect(email.email)
.toHaveSender('[email protected]')
.toHaveSubject('Welcome to Our Service')
.toHaveReplacedAllVariables()
.toContainText('[email protected]')
.toHaveUnsubscribeLink()
.toHavePhysicalAddress()
.toBeCompliant('US');
});Password Reset Email Test
test('password reset email has valid token', async () => {
await triggerPasswordReset('[email protected]');
const email = await waitForEmailWithSubject(/Password Reset/);
expect(email.email)
.toHaveSender('[email protected]')
.toHaveRecipient('[email protected]')
.toContainText('reset your password')
.toContainText('expires in 1 hour')
.toHaveBeenSentWithin(5000);
});Notification Email with Attachment
test('daily report email has attachment', async () => {
await generateDailyReport();
const email = await waitForEmail({
recipient: '[email protected]',
subject: /Daily Report/
});
expect(email.email)
.toHaveAttachment('report.pdf')
.toHaveAttachmentCount(1)
.toContainText('attached');
});Template Variable Validation
test('marketing email has all variables replaced', async () => {
const email = await waitForEmail({
recipient: '[email protected]',
subject: /Special Offer/
});
expect(email.email)
.toHaveReplacedAllVariables()
.toHaveVariable('customerName', 'John Doe')
.toHaveVariable('offerPrice', '$19.99')
.toNotContainUnreplacedVariables();
});Compliance Testing
describe('Email Compliance', () => {
test('US CAN-SPAM compliance', async () => {
const email = await waitForEmail({ recipient: '[email protected]' });
expect(email.email).toBeCompliantEmail('US');
});
test('EU GDPR compliance', async () => {
const email = await waitForEmail({ recipient: '[email protected]' });
expect(email.email).toBeCompliantEmail('EU');
});
test('has required compliance elements', async () => {
const email = await waitForEmail({ recipient: '[email protected]' });
expect(email.email)
.toHaveUnsubscribeLink()
.toHavePhysicalAddress();
});
});SMTP Validation
test('email passes SMTP validation', async () => {
const email = await waitForEmail({
recipient: '[email protected]'
});
expect(email.email)
.toHaveBeenDelivered()
.toHavePassedSPF()
.toHaveValidDKIM();
});Integration Status
- Logger integration: Not applicable - Testing package uses console for warnings only
- Docs-Suite: Ready - Complete markdown documentation and TypeScript definitions
- NeverHub: Not applicable - No NeverHub integration needed for testing package
TypeScript Support
Full TypeScript support with strict type checking:
import type {
ParsedEmail,
EmailAttachment,
AssertionResult,
EmailCriteria,
CapturedEmail,
ComplianceRegion,
EmailWaiterConfig
} from '@bernierllc/email-test-assertions';Dependencies
@bernierllc/email-parser- Email parsing functionality@bernierllc/email-template-engine- Template validation support
Error Messages
The package provides clear, actionable error messages:
Expected email to have recipient '[email protected]', but found '[email protected]'
Expected email template to have all variables replaced, but found unreplaced variables: {{userName}}, {{productName}}
Expected email to be compliant with US regulations, but missing:
- Unsubscribe link
- Physical address in footer
Expected email to be captured within 5000ms, but timeout was reachedLicense
Copyright (c) 2025 Bernier LLC. All rights reserved.
See Also
- @bernierllc/email-parser - Parse email content
- @bernierllc/email-template-engine - Template rendering
