How to Mock jQuery AJAX Requests in Testing

Mocking jQuery AJAX calls is essential for creating reliable, fast, and isolated unit tests without relying on an active backend server. This article covers the most effective approaches to intercept and simulate $.ajax, $.get, and $.post requests during testing. You will learn how to mock network activity using popular testing tools like Sinon.JS, Jest, and Jasmine, allowing you to test both successful responses and error states deterministically.

1. Using Sinon.JS Fake Server

Sinon.JS is one of the most widely used libraries for mocking network requests in JavaScript. It provides a fake server that seamlessly intercepts XMLHttpRequest calls generated by jQuery.

Installation

npm install --save-dev sinon

Implementation

Set up the fake server before running the test, specify the expected response, and restore the native behavior in the cleanup phase.

describe('jQuery AJAX with Sinon.JS', () => {
  let server;

  beforeEach(() => {
    // Intercept native XHR calls
    server = sinon.fakeServer.create();
    server.autoRespond = true;
  });

  afterEach(() => {
    // Restore native behavior
    server.restore();
  });

  it('fetches user data successfully', (done) => {
    const mockData = { id: 1, name: 'Jane Doe' };

    // Define endpoint, status code, headers, and body
    server.respondWith(
      'GET',
      '/api/user',
      [200, { 'Content-Type': 'application/json' }, JSON.stringify(mockData)]
    );

    $.ajax({
      url: '/api/user',
      method: 'GET',
      dataType: 'json',
      success: (data) => {
        expect(data.name).toBe('Jane Doe');
        done();
      }
    });
  });
});

2. Mocking $.ajax Directly with Jest

If you are using Jest, you can directly spy on and mock the $.ajax method without requiring external server-mocking libraries.

Implementation

Use jest.spyOn to intercept the function call and return a resolved or rejected promise or trigger the appropriate callbacks.

describe('jQuery AJAX with Jest', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });

  it('resolves with mocked data using promises', async () => {
    const mockResponse = { status: 'success', data: [1, 2, 3] };

    // Spy on $.ajax and return a resolved Deferred-like promise
    jest.spyOn($, 'ajax').mockImplementation(() => {
      return $.Deferred().resolve(mockResponse).promise();
    });

    const result = await $.ajax({ url: '/api/items', method: 'GET' });

    expect($.ajax).toHaveBeenCalledWith(
      expect.objectContaining({ url: '/api/items' })
    );
    expect(result.data).toEqual([1, 2, 3]);
  });

  it('handles request failure', (done) => {
    const errorResponse = { statusText: 'Not Found' };

    jest.spyOn($, 'ajax').mockImplementation((options) => {
      if (options.error) {
        options.error(errorResponse, 'error', 'Not Found');
      }
      return $.Deferred().reject(errorResponse).promise();
    });

    $.ajax({
      url: '/api/missing',
      error: (xhr, status, error) => {
        expect(status).toBe('error');
        expect(error).toBe('Not Found');
        done();
      }
    });
  });
});

3. Using Jasmine Ajax (jasmine-ajax)

For projects tested with Jasmine, the official jasmine-ajax plugin provides built-in utilities to capture and reply to requests.

Installation

npm install --save-dev jasmine-ajax

Implementation

Initialize the mock network interface using jasmine.Ajax.install() and define the response using respondWith.

describe('jQuery AJAX with Jasmine', () => {
  beforeEach(() => {
    jasmine.Ajax.install();
  });

  afterEach(() => {
    jasmine.Ajax.uninstall();
  });

  it('simulates a server response', () => {
    const callback = jasmine.createSpy('callback');

    $.get('/api/status', callback);

    const request = jasmine.Ajax.requests.mostRecent();
    expect(request.url).toBe('/api/status');

    request.respondWith({
      status: 200,
      contentType: 'application/json',
      responseText: '{"online": true}'
    });

    expect(callback).toHaveBeenCalledWith({ online: true }, 'success', jasmine.any(Object));
  });
});

Best Practices for Mocking AJAX

  • Clean Up State: Always restore or uninstall mocks in an afterEach block to prevent mocked responses from leaking into subsequent tests.
  • Test Failure Scenarios: Mock non-200 HTTP status codes (such as 400, 401, and 500) and network timeouts to ensure your application handles edge cases gracefully.
  • Assert Payloads: Verify that outgoing payload parameters, headers, and HTTP methods match the requirements of your API.