Hone logo
Hone
Problems

Mocking API Endpoints with Jest

This challenge focuses on creating a robust way to mock API endpoints within your Jest test suite. Effectively stubbing external services allows you to isolate your code, ensure test predictability, and speed up your test execution by avoiding actual network requests. You will implement a system to define and manage mock responses for HTTP requests.

Problem Description

Your task is to create a "stub server" using Jest to mock HTTP requests. This stub server should intercept outgoing HTTP requests made by your application during testing and return predefined responses. This allows you to test components that rely on external APIs without actually making network calls.

Key Requirements:

  1. Intercept Requests: The stub server must be able to intercept HTTP requests (e.g., GET, POST, PUT, DELETE) made by your application code.
  2. Define Mock Responses: You should be able to define specific mock responses for different URL paths and HTTP methods. This includes setting the status code, response body (JSON or plain text), and custom headers.
  3. Handle Different Methods: The stub server should support common HTTP methods.
  4. Reset Mocks: Provide a mechanism to easily clear and reset all defined mocks between test runs or test cases.
  5. Integration with Jest: The stubbing mechanism should integrate seamlessly with Jest, ideally using its mocking capabilities.

Expected Behavior:

When your application code makes an HTTP request that matches a configured mock:

  • The request should be intercepted.
  • The predefined status code, response body, and headers should be returned.
  • The actual network request should not be made.

If a request does not match any configured mock, it should either be allowed to proceed (in a development or integration testing environment) or potentially fail (in a unit testing scenario, depending on the setup). For this challenge, assume unmatched requests should result in an error or be explicitly ignored.

Edge Cases:

  • Requests to different HTTP methods on the same URL path.
  • Requests with different query parameters or request bodies (though for this challenge, matching on URL path and method is sufficient).
  • Handling of different content types in responses.

Examples

Example 1: Mocking a GET Request

Let's say your application makes a GET request to /api/users/123.

  • Input (during test execution): An HTTP GET request to http://localhost:3000/api/users/123.
  • Mock Configuration:
    stubServer.mockGet('/api/users/123', {
        statusCode: 200,
        body: { id: 123, name: 'Alice' },
        headers: { 'Content-Type': 'application/json' }
    });
    
  • Output (returned to application code):
    • Status Code: 200
    • Response Body: { id: 123, name: 'Alice' }
    • Headers: { 'Content-Type': 'application/json' }
  • Explanation: The stub server intercepts the GET request to the specified URL and returns the configured JSON object as the response body with a 200 status code.

Example 2: Mocking a POST Request with Different Response

Imagine a POST request to /api/products.

  • Input (during test execution): An HTTP POST request to http://localhost:3000/api/products with a request body like { name: 'New Gadget', price: 99.99 }.
  • Mock Configuration:
    stubServer.mockPost('/api/products', {
        statusCode: 201,
        body: { id: 'abc-456', name: 'New Gadget', price: 99.99 },
        headers: { 'Content-Type': 'application/json' }
    });
    
  • Output (returned to application code):
    • Status Code: 201
    • Response Body: { id: 'abc-456', name: 'New Gadget', price: 99.99 }
    • Headers: { 'Content-Type': 'application/json' }
  • Explanation: The stub server intercepts the POST request and returns a 201 Created status with the new product's details.

Example 3: Handling Unmatched Requests

If a GET request is made to /api/settings but no mock is defined for it.

  • Input (during test execution): An HTTP GET request to http://localhost:3000/api/settings.
  • Mock Configuration: (No configuration for /api/settings)
  • Output (returned to application code): An error is thrown, indicating an unexpected request.
  • Explanation: Since no mock was defined for this specific request, the stub server flags it as an unhandled request, which is crucial for ensuring tests only interact with intended mocked endpoints.

Constraints

  • Your solution should primarily leverage Jest's mocking capabilities (e.g., jest.fn(), jest.spyOn(), or potentially libraries that integrate with Jest like jest-fetch-mock or msw if you choose to explore them).
  • The stub server should be designed to be easily set up and torn down within Jest's beforeEach and afterEach hooks.
  • The mock definition structure should be clear and concise.
  • Performance is important; the stubbing mechanism should not significantly slow down your test suite.

Notes

Consider how you will manage the state of your stub server. It should be cleared before each test to prevent mocks from one test affecting another. Think about the underlying HTTP client your application uses (e.g., fetch, axios) and how you can intercept calls made through it. You might need to write a small wrapper or use a library designed for this purpose. The goal is to create a reusable pattern for mocking.

Loading editor...
typescript