如何测试带有Interceptor的Axios服务?Jest测试拦截器难题
问题描述
我有一个全局使用的Axios拦截器实例,代码如下:
export const http = axios.create({ baseURL: process.env.REACT_APP_API_BASE_URL, headers: { "CONTENT-TYPE": "application/json", ACCEPT: "application/json", }, }); /** * Add access token in the authorization header of the given config. * * @param {Object} axiosConfig Axios config object. * @param {String} accessToken * @returns {Object} Axios config object. */ const configWithAccessToken = ( axiosConfig: AxiosRequestConfig, accessToken: string | null ): AxiosRequestConfig => ({ ...axiosConfig, headers: { ...axiosConfig.headers, Authorization: `Bearer ${accessToken}`, }, }); /** * Request interceptors for axios instance. * * @returns {Object} */ http.interceptors.request.use( (requestConfig: AxiosRequestConfig): AxiosRequestConfig | any => { const accessToken = getAccessToken(); return configWithAccessToken(requestConfig, accessToken); }, (requestError) => { throw requestError; } ); /** * Response interceptor for axios instance. * * @returns {Object} */ http.interceptors.response.use( (response) => { return response?.data; }, (error) => { if (isEmpty(error)) { throw new Error(error); } const { data } = error?.response; throw data; } );
我要测试的服务函数是:
export const fetchAll = () => { const url = 'somethingurl/students'; return http.get(url); };
测试时拦截器总会被触发,试过Jest Mock但没用,请问怎么绕过拦截器或者正确Mock这个服务?
解决方案
方法1:直接Mock自定义的Axios实例(推荐)
不需要处理拦截器,直接Mock你导出的http实例的get方法,请求根本不会走到拦截器逻辑里。
测试文件代码示例:
import { http } from './path-to-your-axios-instance'; import { fetchAll } from './path-to-your-service'; // Mock http.get 方法 jest.mock('./path-to-your-axios-instance', () => ({ http: { get: jest.fn() } })); describe('fetchAll', () => { it('should call http.get with correct URL', async () => { // 模拟成功返回的数据 const mockData = [{ id: 1, name: 'Student A' }]; (http.get as jest.Mock).mockResolvedValue(mockData); const result = await fetchAll(); expect(http.get).toHaveBeenCalledWith('somethingurl/students'); expect(result).toEqual(mockData); }); it('should handle error correctly', async () => { // 模拟错误返回 const mockError = { message: 'Failed to fetch' }; (http.get as jest.Mock).mockRejectedValue(mockError); await expect(fetchAll()).rejects.toEqual(mockError); }); });
方法2:清除Axios实例的拦截器
如果需要真实调用Axios但跳过拦截器,可以在测试前清除实例的请求和响应拦截器:
import { http } from './path-to-your-axios-instance'; import { fetchAll } from './path-to-your-service'; import MockAdapter from 'axios-mock-adapter'; describe('fetchAll', () => { beforeEach(() => { // 清除所有请求拦截器 http.interceptors.request.clear(); // 清除所有响应拦截器 http.interceptors.response.clear(); }); it('should make a GET request to correct URL', async () => { // 用axios-mock-adapter Mock请求 const mockAdapter = new MockAdapter(http); mockAdapter.onGet('somethingurl/students').reply(200, [{ id: 1 }]); const result = await fetchAll(); expect(result).toEqual([{ id: 1 }]); }); });
注意:需要先安装依赖包:npm install axios-mock-adapter --save-dev
方法3:Mock拦截器依赖的函数
如果拦截器里用到了getAccessToken这类外部函数,可以Mock这个函数来避免拦截器抛出问题:
import { getAccessToken } from './path-to-your-auth-utils'; import { fetchAll } from './path-to-your-service'; import { http } from './path-to-your-axios-instance'; import MockAdapter from 'axios-mock-adapter'; jest.mock('./path-to-your-auth-utils', () => ({ getAccessToken: jest.fn().mockReturnValue('mock-token') })); describe('fetchAll', () => { it('should include token in headers', async () => { const mockAdapter = new MockAdapter(http); mockAdapter.onGet('somethingurl/students').reply((config) => { expect(config.headers.Authorization).toBe('Bearer mock-token'); return [200, []]; }); await fetchAll(); }); });
内容的提问来源于stack exchange,提问作者Biswas Rai
相关产品推荐
相关产品推荐

