Unit Testing Axios Interceptors in TypeScript: A Comprehensive Guide
Testing asynchronous code, particularly when dealing with external dependencies like Axios, can be a complex undertaking. One common challenge arises when trying to unit test Axios interceptors, which add custom logic to your API requests and responses. This article will guide you through effectively unit testing Axios interceptors within your TypeScript project.
Understanding the Problem
Imagine you have a TypeScript application using Axios to fetch data from a remote API. To handle common tasks like authentication and error handling, you've implemented an Axios interceptor. This interceptor modifies requests before they're sent and responses before they're processed. Now, you want to write unit tests to ensure your interceptor works as expected.
import axios from 'axios';
axios.interceptors.request.use((config) => {
// Add authorization token to request headers
config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`;
return config;
});
axios.interceptors.response.use(
(response) => response,
(error) => {
// Handle error responses
console.error('Error:', error);
return Promise.reject(error);
}
);
The problem arises because you're dealing with asynchronous operations and external dependencies. You need to test the interceptor's logic without actually making real network requests, potentially causing side effects.
Testing the Interceptor Logic
Here's a breakdown of the most common approach to unit testing Axios interceptors in TypeScript:
-
Mock the Axios Instance: The key is to create a mock instance of Axios that allows you to control its behavior and assertions. Libraries like
axios-mock-adapter
andjest-mock-axios
can be helpful here. -
Control Request and Response Flows: Using the mocked Axios instance, you can set up expectations for specific requests and responses. This allows you to test different scenarios, like successful requests, error responses, and how your interceptor modifies them.
-
Test Request Modification: Verify that the interceptor adds the authorization token correctly to the request headers.
-
Test Response Handling: Ensure the interceptor handles successful and error responses as expected.
Example with Jest and jest-mock-axios
Let's illustrate this process using Jest and jest-mock-axios
:
import axios from 'axios';
import { AxiosResponse } from 'axios';
import MockAdapter from 'axios-mock-adapter';
describe('Axios Interceptors', () => {
let mock: MockAdapter;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.reset();
});
it('should add authorization token to request headers', () => {
const token = 'test-token';
localStorage.setItem('token', token);
mock.onGet('/api/users').reply(200, { data: 'success' });
return axios.get('/api/users').then((response: AxiosResponse) => {
expect(response.config.headers.Authorization).toBe(`Bearer ${token}`);
});
});
it('should handle error responses', () => {
mock.onGet('/api/users').reply(500, { error: 'server error' });
return axios.get('/api/users').catch((error) => {
expect(error.response.status).toBe(500);
});
});
});
In this example:
- We use
jest-mock-axios
to create a mock adapter for our Axios instance. - We define
beforeEach
andafterEach
hooks to reset the mock after each test. - The first test checks if the interceptor adds the token to the request headers.
- The second test ensures the interceptor handles the error response correctly.
Conclusion
Unit testing Axios interceptors is crucial for building robust and reliable applications. By using mock libraries and controlled test scenarios, you can thoroughly test your interceptor's logic and ensure it functions correctly. Remember to follow best practices for mocking, testing asynchronous code, and creating isolated unit tests.
Further Resources:
- Jest: https://jestjs.io/
- axios-mock-adapter: https://www.npmjs.com/package/axios-mock-adapter
- jest-mock-axios: https://www.npmjs.com/package/jest-mock-axios