在Jest和TypeScript中Mock Axios自定义错误失败的解决方法
在Jest+TypeScript环境中正确Mock Axios的401错误响应
问题背景
测试GetToken函数时,期望捕获带有errors数组的Axios 401错误,提取数组中第一个元素的detail作为错误信息,但实际测试失败:错误信息返回Request failed with status code 400,且代码进入了普通Error的处理分支。
错误原因
- Mock未生效:
getToken.ts中每次调用都新建了axios实例,而非复用axios-instance.ts导出的实例,导致Jest对axiosInstance的Mock完全没作用。 - Mock对象类型错误:直接用普通对象作为拒绝值,不是
AxiosError实例,导致e instanceof AxiosError判断不成立,无法进入自定义错误处理分支。
修复步骤
步骤1:修改getToken.ts,复用全局axios实例
把函数内部创建的api替换为导入的axiosInstance,确保请求走Mock的实例:
import axios, { AxiosError } from 'axios'; import { axiosInstance } from '../../utils/axios-instance'; import path from 'path'; // 类型定义(根据实际项目调整) interface ITokenParams { client_id: string; client_secret: string; code: string; grant_type: string; } interface ITokenResult { /* 实际返回类型 */ } interface IApiError { detail: string; } interface IError { error: boolean; module: string; method: string; message?: string; } const GetToken = async (params: ITokenParams): Promise<ITokenResult | IError> => { try { // 替换为复用全局axios实例 const { data } = await axiosInstance.post<ITokenResult>("https://someURL", { ...params }); return data; } catch (e) { let err: IError = { error: true, module: path.basename(__filename), method: GetToken.name }; if (e instanceof AxiosError && e.response?.data?.errors) { let errorsArray: IApiError[] = e.response.data.errors; err.message = errorsArray.length > 0 ? errorsArray[0].detail : e.message; } else if (e instanceof Error) { err.message = e.message; } return err; } }; export default GetToken;
步骤2:修改测试文件,创建正确的AxiosError实例
使用axios.createError方法生成符合要求的AxiosError实例,确保instanceof判断通过:
import { axiosInstance } from '../../utils/axios-instance'; import GetToken from '@App/api/oauth/getToken'; import axios, { AxiosError } from 'axios'; jest.mock('../../utils/axios-instance.ts'); describe('Token from OAuth', () => { test('Return error for expired code', async () => { // 定义自定义错误响应数据 const errorResponse = { errors: [{ detail: 'a' }] }; // 创建AxiosError实例 const mockError = axios.createError( 'Unauthorized', undefined, 401, {}, { data: errorResponse } ); const expectedResult = { error: true, module: 'getToken.ts', method: 'GetToken', message: 'a' }; // 类型断言为Mock实例 const mockedAxios = axiosInstance as jest.Mocked<typeof axiosInstance>; // Mock post方法的拒绝返回值 mockedAxios.post.mockRejectedValueOnce(mockError); const result = await GetToken({ client_id: process.env.APPLICATION_ID || '', client_secret: process.env.APPLICATION_SECRET || '', code: "some-codes", grant_type: "authorization_code" }); expect(result).toEqual(expectedResult); // 验证post方法的调用参数 expect(mockedAxios.post).toHaveBeenCalledWith( "https://someURL", { client_id: process.env.APPLICATION_ID || '', client_secret: process.env.APPLICATION_SECRET || '', code: "some-codes", grant_type: "authorization_code" } ); }); });
关键说明
- 复用axios实例:只有请求使用被Mock的实例,Jest的Mock逻辑才会生效;
- AxiosError实例化:必须用官方提供的
createError方法创建错误对象,才能通过instanceof AxiosError的类型校验,进入自定义错误处理分支。
内容的提问来源于stack exchange,提问作者BK52
相关产品推荐
相关产品推荐

