Guide: Jest / Vitest Integration

Set up Receiver.email with Jest or Vitest for email testing in TypeScript/JavaScript projects.

Installation

bash
npm install --save-dev @receiverdotemail/sdk

Setup

Create a helper file for initializing the client:

test/helpers/receiver.ts
import { ReceiverClient } from "@receiverdotemail/sdk";

export const receiver = new ReceiverClient({
  apiKey: process.env.RECEIVER_API_KEY!,
});

export const PROJECT_ID = process.env.RECEIVER_PROJECT_ID || "proj_abc123";
// Any prefix + this suffix is a valid inbox for the project
export const EMAIL_SUFFIX =
  process.env.RECEIVER_EMAIL_SUFFIX || "[email protected]";

export function testEmail(prefix: string): string {
  return `${prefix}-${Date.now()}${EMAIL_SUFFIX}`;
}

Configure Timeouts

Email tests use long-polling (up to 30s), so increase the default test timeout:

Jest

jest.config.ts
export default {
  testTimeout: 60_000, // 60 seconds
  // ... other config
};

Vitest

vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    testTimeout: 60_000, // 60 seconds
  },
});

Write Tests

test/email-flows.test.ts
import { receiver, PROJECT_ID, testEmail } from "./helpers/receiver";

describe("Email Flows", () => {
  describe("Welcome Email", () => {
    it("sends a welcome email on signup", async () => {
      const addr = testEmail("welcome");

      // Trigger signup in your app
      await app.signup({ email: addr, password: "Test123!" });

      // Wait for the welcome email
      const email = await receiver.emails.waitFor({
        projectId: PROJECT_ID,
        recipient: addr,
        timeout: 30,
      });

      expect(email).not.toBeNull();
      expect(email.subject.toLowerCase()).toContain("welcome");
      expect(email.links.length).toBeGreaterThan(0);
    });
  });

  describe("Password Reset", () => {
    it("sends a reset email with a valid link", async () => {
      const addr = testEmail("reset");

      await app.requestPasswordReset(addr);

      const email = await receiver.emails.waitFor({
        projectId: PROJECT_ID,
        recipient: addr,
        timeout: 30,
      });

      expect(email).not.toBeNull();
      expect(email.subject.toLowerCase()).toContain("reset");

      const resetLink = email.links.find((l) =>
        l.includes("/reset")
      );
      expect(resetLink).toBeDefined();
    });
  });

  describe("OTP Verification", () => {
    it("sends a valid 6-digit OTP", async () => {
      const addr = testEmail("otp");

      await app.sendOtp(addr);

      const email = await receiver.emails.waitFor({
        projectId: PROJECT_ID,
        recipient: addr,
        timeout: 30,
      });

      expect(email).not.toBeNull();

      const otp = email.subject.match(/\d{6}/)?.[0]
        || email.textBody?.match(/\d{6}/)?.[0];

      expect(otp).toBeDefined();
      expect(otp).toHaveLength(6);
    });
  });

  describe("Email Content", () => {
    it("has correct HTML and text bodies", async () => {
      const addr = testEmail("content");

      await app.sendNotification(addr, "Test notification");

      const email = await receiver.emails.waitFor({
        projectId: PROJECT_ID,
        recipient: addr,
        timeout: 30,
      });

      expect(email).not.toBeNull();
      expect(email.textBody).toContain("Test notification");
      expect(email.htmlBody).toContain("Test notification");
    });
  });
});

Running Tests

bash
# Set your API key
export RECEIVER_API_KEY="recv_live_..."

# Jest
npx jest test/email-flows.test.ts

# Vitest
npx vitest run test/email-flows.test.ts

# Watch mode (Vitest)
npx vitest test/email-flows.test.ts

Tips

  • Unique addresses: The testEmail() helper generates unique addresses per test run, preventing interference.
  • Keep the client shared: Initialize the ReceiverClient once and reuse it across tests.
  • Per-test timeout override: For individual slow tests, pass the timeout as the third argument to it(): it("test", async () => { ... }, 90_000).
  • Don't forget .env: For local development, use a .env file loaded by dotenv.

Next Steps