Testing

Mail.fake() / Mail.restore()

Enable fake mode to intercept all emails instead of sending them. This is the primary testing pattern:

import { Mail } from '@impruthvi/nodemail';

beforeEach(() => {
  Mail.fake();    // All emails will be stored, not sent
});

afterEach(() => {
  Mail.restore(); // Restore real mail system
});
MethodSignatureDescription
Mail.fake()Mail.fake(): MailFakeEnable fake mode. Returns the MailFake instance.
Mail.restore()Mail.restore(): voidRestore the real mail system (disable fake mode).
Mail.getFake()Mail.getFake(): MailFake | nullGet the current MailFake instance (or null if not faking).

Send Assertions

MethodSignatureDescription
assertSent()Mail.assertSent<T>(MailableClass, callback?)Assert a mailable was sent (optionally matching a condition)
assertSentCount()Mail.assertSentCount<T>(MailableClass, count)Assert a mailable was sent exactly N times
assertNotSent()Mail.assertNotSent<T>(MailableClass, callback?)Assert a mailable was NOT sent
assertNothingSent()Mail.assertNothingSent()Assert no emails were sent at all
// Assert WelcomeEmail was sent
Mail.assertSent(WelcomeEmail);

// Assert with conditions
Mail.assertSent(WelcomeEmail, (mail) => {
  return mail.hasTo('user@example.com') && mail.subjectContains('Welcome');
});

// Assert sent exactly 2 times
Mail.assertSentCount(WelcomeEmail, 2);

// Assert a specific mailable was NOT sent
Mail.assertNotSent(PasswordResetEmail);

// Assert nothing was sent at all
Mail.assertNothingSent();

Queue Assertions

MethodSignatureDescription
assertQueued()Mail.assertQueued<T>(MailableClass, callback?)Assert a mailable was queued
assertQueuedCount()Mail.assertQueuedCount<T>(MailableClass, count)Assert a mailable was queued exactly N times
assertNotQueued()Mail.assertNotQueued<T>(MailableClass, callback?)Assert a mailable was NOT queued
assertNothingQueued()Mail.assertNothingQueued()Assert nothing was queued
// Assert WelcomeEmail was queued
Mail.assertQueued(WelcomeEmail);

// Assert with conditions
Mail.assertQueued(WelcomeEmail, (mail) => mail.hasTo('user@example.com'));

// Assert queued exactly once
Mail.assertQueuedCount(WelcomeEmail, 1);

// Assert nothing was queued
Mail.assertNothingQueued();

Retrieval Methods

MethodSignatureDescription
sent()Mail.sent<T>(MailableClass?): AssertableMessage[]Get all sent messages (optionally filtered)
queued()Mail.queued<T>(MailableClass?): AssertableMessage[]Get all queued messages (optionally filtered)
hasSent()Mail.hasSent(): booleanCheck if any messages were sent
hasQueued()Mail.hasQueued(): booleanCheck if any messages were queued
// Get all sent WelcomeEmails
const messages = Mail.sent(WelcomeEmail);

// Inspect the first one
const first = messages[0];
console.log(first.getTo());      // ['user@example.com']
console.log(first.getSubject()); // 'Welcome, John!'

Failure Simulation

MethodSignatureDescription
simulateFailures()fake.simulateFailures(count: number)Simulate failures for the first N sends
resetFailures()fake.resetFailures()Clear failure simulation state
clear()fake.clear()Clear all sent/queued messages and reset failures
sentCount()fake.sentCount(): numberGet the number of sent messages
queuedCount()fake.queuedCount(): numberGet the number of queued messages
const fake = Mail.fake();

// First 2 sends will return { success: false }
fake.simulateFailures(2);

// Test failover behavior...

fake.resetFailures(); // Stop simulating failures
fake.clear();         // Reset all state

AssertableMessage

Returned by Mail.sent() and Mail.queued(). Provides methods to inspect message properties.

Recipients

MethodSignatureDescription
hasTo()hasTo(email: string): booleanCheck if message has a specific TO recipient
hasCc()hasCc(email: string): booleanCheck if message has a specific CC recipient
hasBcc()hasBcc(email: string): booleanCheck if message has a specific BCC recipient
getTo()getTo(): string[]Get all TO recipients
getCc()getCc(): string[]Get all CC recipients
getBcc()getBcc(): string[]Get all BCC recipients

Sender

MethodSignatureDescription
hasFrom()hasFrom(email: string): booleanCheck if message has a specific FROM address
getFrom()getFrom(): string | undefinedGet the FROM address
hasReplyTo()hasReplyTo(email: string): booleanCheck for a specific reply-to address

Subject

MethodSignatureDescription
hasSubject()hasSubject(subject: string): booleanExact subject match
subjectContains()subjectContains(text: string): booleanCase-insensitive substring match
getSubject()getSubject(): stringGet the subject

Content

MethodSignatureDescription
hasHtml()hasHtml(): booleanCheck if message has HTML content
htmlContains()htmlContains(text: string): booleanCheck if HTML contains a string
getHtml()getHtml(): string | undefinedGet the HTML content
hasText()hasText(): booleanCheck if message has plain text content
textContains()textContains(text: string): booleanCheck if plain text contains a string
getText()getText(): string | undefinedGet the plain text content

Attachments

MethodSignatureDescription
hasAttachments()hasAttachments(): booleanCheck if message has any attachments
hasAttachment()hasAttachment(filename: string): booleanCheck for a specific attachment by filename
getAttachments()getAttachments(): Attachment[]Get all attachments

Headers

MethodSignatureDescription
hasHeader()hasHeader(name: string, value?: string): booleanCheck for header (optionally with specific value)
getHeader()getHeader(name: string): string | undefinedGet a header value

Template

MethodSignatureDescription
hasTemplate()hasTemplate(template: string): booleanCheck if a specific template was used
getTemplate()getTemplate(): string | undefinedGet the template name
hasData()hasData(key: string, value?: unknown): booleanCheck for template data (optionally with specific value)
getData()getData(key: string): unknownGet a template data value
getAllData()getAllData(): Record<string, unknown> | undefinedGet all template data

Markdown

MethodSignatureDescription
isMarkdown()isMarkdown(): booleanCheck if message was built from markdown
getMarkdown()getMarkdown(): string | undefinedGet the raw markdown source
markdownContains()markdownContains(text: string): booleanCheck if markdown source contains a string

Failover

MethodSignatureDescription
wasFailoverUsed()wasFailoverUsed(): booleanCheck if failover was triggered
getProvider()getProvider(): string | undefinedGet the provider that actually sent the message
getFailoverAttempts()getFailoverAttempts(): FailoverDetail[]Get all failover attempt details
getResponse()getResponse(): MailResponse | undefinedGet the full MailResponse

Other

MethodSignatureDescription
getOptions()getOptions(): MailOptionsGet the underlying mail options
getMailable()getMailable(): Mailable | undefinedGet the mailable instance (if any)

Real-World Test Example

import { Mail, Mailable } from '@impruthvi/nodemail';

class WelcomeEmail extends Mailable {
  constructor(public userName: string) {
    super();
  }

  build() {
    return this
      .subject(`Welcome, ${this.userName}!`)
      .html(`<h1>Hello ${this.userName}!</h1>`)
      .from('noreply@example.com');
  }
}

class PasswordResetEmail extends Mailable {
  constructor(public resetUrl: string) {
    super();
  }

  build() {
    return this
      .subject('Reset Your Password')
      .html(`<a href="${this.resetUrl}">Reset</a>`);
  }
}

describe('User Registration', () => {
  beforeEach(() => {
    Mail.fake();
  });

  afterEach(() => {
    Mail.restore();
  });

  it('sends welcome email on registration', async () => {
    // Application code that sends email
    await Mail.to('john@example.com').send(new WelcomeEmail('John'));

    // Assertions
    Mail.assertSent(WelcomeEmail);
    Mail.assertSent(WelcomeEmail, (mail) => {
      return mail.hasTo('john@example.com') &&
             mail.hasSubject('Welcome, John!') &&
             mail.hasFrom('noreply@example.com') &&
             mail.htmlContains('Hello John');
    });
    Mail.assertSentCount(WelcomeEmail, 1);
    Mail.assertNotSent(PasswordResetEmail);
  });

  it('does not send email when validation fails', async () => {
    // Code that doesn't send email
    Mail.assertNothingSent();
  });

  it('queues welcome email for background sending', async () => {
    await Mail.to('john@example.com').queue(new WelcomeEmail('John'));

    Mail.assertQueued(WelcomeEmail);
    Mail.assertQueued(WelcomeEmail, (mail) => mail.hasTo('john@example.com'));
    Mail.assertNothingSent(); // Queued, not sent
  });
});