Hone logo
Hone
Problems

Mocking External API Calls with WireMock and Jest

In modern web development, it's crucial to isolate your code for effective testing. When your application depends on external APIs, directly calling them in tests can lead to slow, unreliable, and costly test suites. This challenge focuses on using WireMock, a powerful HTTP mock server, in conjunction with Jest, a popular JavaScript testing framework, to simulate external API responses and ensure robust, isolated unit and integration tests.

Problem Description

Your task is to create a TypeScript service that fetches data from an external API. You will then use WireMock to mock the responses from this external API and Jest to write tests for your service, verifying that it behaves correctly based on the mocked responses.

Requirements:

  1. Create a Service: Develop a TypeScript class or function that simulates fetching data from a hypothetical external API endpoint (e.g., /api/users/:id). This service should handle potential errors (e.g., 404, 500).
  2. Set up WireMock: Configure WireMock to run as part of your Jest test suite. You'll need to define specific API endpoints and their corresponding mock responses (both success and error cases).
  3. Write Jest Tests: Write Jest tests for your service. These tests should:
    • Verify that your service correctly parses successful API responses.
    • Verify that your service handles API errors gracefully (e.g., returns a specific error object or throws an exception).
    • Ensure that your service makes requests to the correct URL and with the correct HTTP method.

Expected Behavior:

  • When the external API returns a 200 OK with valid user data, your service should return that data.
  • When the external API returns a 404 Not Found, your service should indicate that the user was not found.
  • When the external API returns a 500 Internal Server Error, your service should indicate a server error occurred.
  • Your tests should confirm that the correct WireMock stubs are being hit.

Edge Cases:

  • Consider how your service should behave if the mock API returns an unexpected response format (e.g., invalid JSON).

Examples

Example 1: Successful User Fetch

WireMock Stub Configuration:

{
  "request": {
    "method": "GET",
    "url": "/api/users/123"
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "jsonBody": {
      "id": 123,
      "name": "Alice Smith",
      "email": "alice@example.com"
    }
  }
}

Input to your service: fetchUser(123)

Expected Output from your service:

{
  id: 123,
  name: "Alice Smith",
  email: "alice@example.com"
}

Explanation: The WireMock stub matches the GET request to /api/users/123 and returns a 200 OK with a JSON body. Your service successfully parses this JSON and returns the user object.

Example 2: User Not Found

WireMock Stub Configuration:

{
  "request": {
    "method": "GET",
    "url": "/api/users/999"
  },
  "response": {
    "status": 404,
    "body": "User not found"
  }
}

Input to your service: fetchUser(999)

Expected Output from your service: (This depends on how your service handles errors. For instance, it might throw an error or return null/undefined and a status.)

// Example: Throwing an error
throw new Error("User with ID 999 not found");

// Example: Returning a status object
{ status: 404, message: "User not found" }

Explanation: The WireMock stub matches the GET request to /api/users/999 and returns a 404 Not Found. Your service should detect this and respond accordingly, signaling that the user was not found.

Example 3: Server Error

WireMock Stub Configuration:

{
  "request": {
    "method": "GET",
    "url": "/api/users/456"
  },
  "response": {
    "status": 500,
    "body": "Internal Server Error"
  }
}

Input to your service: fetchUser(456)

Expected Output from your service: (Similar to Example 2, your service should indicate an error.)

// Example: Throwing an error
throw new Error("An internal server error occurred while fetching user 456");

Explanation: The WireMock stub returns a 500 Internal Server Error. Your service must catch this and handle it as a server-side issue.

Constraints

  • Your service should use a standard HTTP client library (e.g., axios, node-fetch, or the built-in fetch if using a newer Node.js version).
  • WireMock should be managed within the Jest lifecycle (e.g., started before tests and stopped after).
  • Your tests should cover at least one success case, one 404 error case, and one 500 error case.
  • The mock API base URL will be http://localhost:8080.

Notes

  • Consider using the wiremock-jest library or manually managing WireMock server lifecycle within your Jest setup and teardown.
  • Think about how you will inject the base URL of the API into your service, making it configurable for testing.
  • Ensure your service's error handling is clear and predictable for testing purposes.
  • When defining WireMock stubs, pay close attention to the url matching and method in the request object.
Loading editor...
typescript