Mocking Axios Requests with MSW and Axios Mock Adapter

Mocking Axios HTTP requests is a fundamental practice in modern JavaScript and TypeScript development for creating reliable, fast, and deterministic tests. This article demonstrates how to intercept and simulate network calls using two prominent solutions: axios-mock-adapter, an Axios-specific mocking tool, and Mock Service Worker (MSW), an API mocking library that intercepts requests at the network level. You will learn the setup, implementation, and best practices for both approaches in testing environments such as Jest or Vitest.


Method 1: Mocking with axios-mock-adapter

axios-mock-adapter allows you to wrap an Axios instance and define mock responses for specific request paths, HTTP methods, and parameters. It works directly inside the Axios request pipeline.

1. Installation

npm install axios-mock-adapter --save-dev

2. Basic Implementation

Consider an API module that fetches user details:

// api.js
import axios from 'axios';

export const fetchUser = async (userId) => {
  const response = await axios.get(`/api/users/${userId}`);
  return response.data;
};

You can test this function by attaching MockAdapter to the default or custom Axios instance:

// api.test.js
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { fetchUser } from './api';

describe('fetchUser with axios-mock-adapter', () => {
  let mock;

  beforeEach(() => {
    mock = new MockAdapter(axios);
  });

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

  it('fetches user successfully', async () => {
    const mockData = { id: 1, name: 'Jane Doe' };
    
    // Define the mock behavior
    mock.onGet('/api/users/1').reply(200, mockData);

    const result = await fetchUser(1);
    expect(result).toEqual(mockData);
  });

  it('handles 404 errors', async () => {
    mock.onGet('/api/users/99').reply(404);

    await expect(fetchUser(99)).rejects.toThrow();
  });
});

Key Features of axios-mock-adapter:


Method 2: Mocking with Mock Service Worker (MSW)

MSW intercepts requests at the network level using the fetch interceptor or Service Workers, making your tests client-agnostic. This means your mocks will continue to work even if you replace Axios with another client like native fetch.

1. Installation

npm install msw --save-dev

2. Basic Implementation (Node/Jest/Vitest Environment)

Step A: Define Request Handlers
// mocks/handlers.js
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('https://api.example.com/users/:id', ({ params }) => {
    const { id } = params;

    if (id === '1') {
      return HttpResponse.json({ id: 1, name: 'Jane Doe' }, { status: 200 });
    }

    return new HttpResponse(null, { status: 404 });
  }),
];
Step B: Set Up the Test Server
// mocks/server.js
import { setupServer } from 'msw/node';
import { handlers } from './handlers';

export const server = setupServer(...handlers);
Step C: Integrate Server into Test Lifecycle
// api.test.js
import axios from 'axios';
import { server } from './mocks/server';
import { http, HttpResponse } from 'msw';

// Lifecycle setup for MSW
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

const fetchUser = async (id) => {
  const response = await axios.get(`https://api.example.com/users/${id}`);
  return response.data;
};

describe('fetchUser with MSW', () => {
  it('returns user data for valid id', async () => {
    const data = await fetchUser(1);
    expect(data).toEqual({ id: 1, name: 'Jane Doe' });
  });

  it('handles server errors via runtime overrides', async () => {
    // Override handler for this specific test case
    server.use(
      http.get('https://api.example.com/users/1', () => {
        return new HttpResponse(null, { status: 500 });
      })
    );

    await expect(fetchUser(1)).rejects.toThrow();
  });
});

Comparing axios-mock-adapter and MSW

Feature axios-mock-adapter MSW (Mock Service Worker)
Interception Level Axios instance level Network level (Interceptors/Service Worker)
Client Dependency Bound exclusively to Axios Client-agnostic (fetch, Axios, GraphQL, etc.)
Setup Complexity Low (minimal boilerplate) Moderate (requires handler and server setup)
Browser Support Yes (in-memory adapter) Yes (via actual Service Workers)
Best For Isolated unit tests using Axios directly Integration tests, end-to-end setups, and cross-framework codebases

Choosing the Right Tool

Use axios-mock-adapter when you have a legacy or targeted codebase that relies solely on Axios, and you require quick setup with minimal configuration. Choose MSW when building modern, decoupled applications where network-level mocking, adherence to web standards, and sharing mock definitions between unit tests, development servers, and end-to-end tests are priorities.