Testing API Interactions with WireMock and Jest
This challenge focuses on using WireMock to mock an external API and Jest to test a function that interacts with that API. Mocking external dependencies is crucial for isolated unit testing, ensuring your code behaves as expected regardless of the availability or behavior of external services. You'll implement a Jest test suite that leverages WireMock to simulate API responses and verify the correct behavior of a function that consumes those responses.
Problem Description
You are tasked with creating a Jest test suite for a function called fetchUserData which retrieves user data from a hypothetical API endpoint /users/{userId}. The API is external and unreliable, so you need to mock it using WireMock. Your test suite should:
- Start WireMock: Before each test, start a WireMock server on a specified port (e.g., 8080).
- Configure WireMock: Configure WireMock to respond to requests to
/users/{userId}with a predefined JSON response based on theuserIdprovided in the request. You'll need to define at least two different responses for different user IDs. - Implement
fetchUserData: ThefetchUserDatafunction takes auserIdas input and makes a GET request to the WireMock server to retrieve user data. It parses the JSON response and returns aUserDataobject. - Write Jest Tests: Write at least two Jest tests that:
- Verify that
fetchUserDatacorrectly parses the JSON response from WireMock for a specificuserId. - Verify that
fetchUserDatahandles a scenario where WireMock returns an error (e.g., a 500 status code). You'll need to configure WireMock to simulate this error for a specificuserId.
- Verify that
- Stop WireMock: After each test, stop the WireMock server.
Expected Behavior:
- The Jest tests should pass when WireMock is configured correctly and the
fetchUserDatafunction behaves as expected. - The tests should fail if WireMock is not started, configured incorrectly, or if
fetchUserDatadoes not handle the API responses correctly. - The tests should be isolated and not dependent on the actual API.
Interface:
interface UserData {
id: number;
name: string;
email: string;
}
async function fetchUserData(userId: number): Promise<UserData> {
// Implementation is not provided - you need to write this.
// It should make a GET request to WireMock and parse the JSON response.
throw new Error("fetchUserData not implemented");
}
Examples
Example 1:
Input: userId = 1
WireMock Response: { "id": 1, "name": "John Doe", "email": "john.doe@example.com" }
Output: { id: 1, name: 'John Doe', email: 'john.doe@example.com' }
Explanation: fetchUserData makes a request to WireMock for user ID 1, WireMock returns the specified JSON, and fetchUserData parses and returns the UserData object.
Example 2:
Input: userId = 2
WireMock Response: { "id": 2, "name": "Jane Smith", "email": "jane.smith@example.com" }
Output: { id: 2, name: 'Jane Smith', email: 'jane.smith@example.com' }
Explanation: Similar to Example 1, but for a different user ID and response.
Example 3:
Input: userId = 3
WireMock Response: HTTP Status Code: 500 Internal Server Error
Output: Jest test should throw an error indicating that fetchUserData failed to handle the error.
Explanation: fetchUserData makes a request to WireMock for user ID 3, WireMock returns a 500 error, and fetchUserData should handle this error gracefully (e.g., by throwing an exception or returning an error object).
Constraints
- WireMock should be started and stopped before and after each test.
- The WireMock server should run on port 8080.
- The
fetchUserDatafunction should be asynchronous. - The Jest tests should use
async/awaitfor asynchronous operations. - You are allowed to use any reasonable Jest matchers.
- The
fetchUserDatafunction should not contain any hardcoded API endpoints. It should use theuserIdparameter to construct the URL.
Notes
- You'll need to install the necessary dependencies:
jest,@types/jest,wiremock-node. - Consider using a library like
node-fetchor the built-infetchAPI to make HTTP requests. - Think about how to handle potential errors during the API request and response parsing.
- The WireMock configuration can be done programmatically within the test suite.
- Focus on writing clean, readable, and maintainable code. Proper error handling is important.
- Remember to clean up WireMock after each test to avoid conflicts.