Mocking AutoSend transactional email endpoints in Vitest and Jest CI/CD test suites

How do we write clean unit and integration tests for email dispatch logic without hitting live network endpoints or spending API quota in CI/CD pipelines?

Testing Email Integration Logic in CI/CD

Making live HTTP calls during automated unit test runs slows down test suite execution, exhausts rate limits, and causes transient network failures in CI/CD pipelines.

Method 1: Mocking Global Fetch in Vitest / Jest

import { vi, test, expect } from 'vitest';
import { sendWelcomeEmail } from './email';

test('sends welcome email with correct payload', async () => {
  const fetchMock = vi.fn().mockResolvedValue({
    ok: true,
    json: async () => ({ id: 'msg_test_123' })
  });
  global.fetch = fetchMock;

  await sendWelcomeEmail('test@example.com', 'Alex');

  expect(fetchMock).toHaveBeenCalledWith(
    'https://api.autosend.com/v1/mails/send',
    expect.objectContaining({
      method: 'POST',
      body: expect.stringContaining('test@example.com')
    })
  );
});

Method 2: MSW (Mock Service Worker) for Integration Tests

Interfacing with MSW allows intercepting REST calls at the network boundary without modifying application code:

import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';

export const handlers = [
  http.post('https://api.autosend.com/v1/mails/send', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json({
      success: true,
      messageId: 'msg_mock_456'
    }, { status: 200 });
  })
];

export const server = setupServer(...handlers);

Relevant Documentation