161 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
| /*
 | |
|  * Copyright 2025 coze-dev Authors
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
|  
 | |
| import { type AxiosError, AxiosHeaders } from 'axios';
 | |
| import { logger } from '@coze-arch/logger';
 | |
| 
 | |
| import {
 | |
|   reportHttpError,
 | |
|   ReportEventNames,
 | |
|   ApiError,
 | |
|   isApiError,
 | |
| } from '../src/api-error';
 | |
| 
 | |
| vi.mock('@coze-arch/logger', () => ({
 | |
|   logger: {
 | |
|     info: vi.fn(),
 | |
|     persist: {
 | |
|       error: vi.fn(),
 | |
|     },
 | |
|   },
 | |
| }));
 | |
| describe('reportHttpError', () => {
 | |
|   const error: AxiosError = {
 | |
|     response: {
 | |
|       data: {
 | |
|         code: '500',
 | |
|         msg: 'Internal Server Error',
 | |
|       },
 | |
|       status: 500,
 | |
|       statusText: '',
 | |
|       config: {
 | |
|         headers: new AxiosHeaders(),
 | |
|       },
 | |
|       headers: {
 | |
|         'x-tt-logid': '1234567890',
 | |
|       },
 | |
|     },
 | |
|     config: {
 | |
|       method: 'GET',
 | |
|       headers: new AxiosHeaders(),
 | |
|       url: '/users',
 | |
|     },
 | |
|     message: 'Request failed with status code 500',
 | |
|     name: 'AxiosError',
 | |
|     isAxiosError: true,
 | |
|     toJSON: () => ({}),
 | |
|   };
 | |
|   it('if no response data, should report http error', () => {
 | |
|     const eventName = ReportEventNames.ApiError;
 | |
|     const noResponseError: AxiosError = {
 | |
|       response: {
 | |
|         data: {
 | |
|           code: '',
 | |
|         },
 | |
|         status: 500,
 | |
|         statusText: '',
 | |
|         config: {
 | |
|           headers: new AxiosHeaders(),
 | |
|         },
 | |
|         headers: {
 | |
|           'x-tt-logid': '1234567890',
 | |
|         },
 | |
|       },
 | |
|       config: {
 | |
|         method: 'GET',
 | |
|         headers: new AxiosHeaders(),
 | |
|         url: '/users',
 | |
|       },
 | |
|       message: 'Request failed with status code 500',
 | |
|       name: 'AxiosError',
 | |
|       isAxiosError: true,
 | |
|       toJSON: () => ({}),
 | |
|     };
 | |
| 
 | |
|     reportHttpError(eventName, noResponseError);
 | |
| 
 | |
|     expect(logger.persist.error).toBeCalledWith({
 | |
|       eventName,
 | |
|       error: noResponseError,
 | |
|       meta: {
 | |
|         message: error.message,
 | |
|         name: error.name,
 | |
|         httpStatusCode: '500',
 | |
|         httpMethod: 'GET',
 | |
|         urlPath: '/users',
 | |
|         logId: '1234567890',
 | |
|         customErrorCode: '',
 | |
|         customErrorMsg: '',
 | |
|       },
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   it('should report http error', () => {
 | |
|     const eventName = ReportEventNames.ApiError;
 | |
| 
 | |
|     reportHttpError(eventName, error);
 | |
| 
 | |
|     expect(logger.persist.error).toHaveBeenCalledWith({
 | |
|       eventName,
 | |
|       error,
 | |
|       meta: {
 | |
|         message: error.message,
 | |
|         name: error.name,
 | |
|         httpStatusCode: '500',
 | |
|         httpMethod: 'GET',
 | |
|         urlPath: '/users',
 | |
|         logId: '1234567890',
 | |
|         customErrorCode: '500',
 | |
|         customErrorMsg: 'Internal Server Error',
 | |
|       },
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   it('should handle error when reporting http catch', () => {
 | |
|     const eventName = ReportEventNames.ApiError;
 | |
| 
 | |
|     (logger.persist.error as any).mockImplementation(() => {
 | |
|       throw new Error('Failed to persist error');
 | |
|     });
 | |
| 
 | |
|     expect(() => {
 | |
|       reportHttpError(eventName, error);
 | |
|     }).toThrowError('Failed to persist error');
 | |
|   });
 | |
| });
 | |
| 
 | |
| describe('isApiError', () => {
 | |
|   it('should return true if error is an instance of ApiError', () => {
 | |
|     const error = new ApiError('500', 'Internal Server Error', {
 | |
|       data: {},
 | |
|       status: 500,
 | |
|       statusText: 'Internal Server Error',
 | |
|       headers: new AxiosHeaders(),
 | |
|       config: {
 | |
|         headers: new AxiosHeaders(),
 | |
|       },
 | |
|     });
 | |
|     const result = isApiError(error);
 | |
|     expect(result).toBe(true);
 | |
|   });
 | |
| 
 | |
|   it('should return false if error is not an instance of ApiError', () => {
 | |
|     const error = new Error('OtherError');
 | |
|     const result = isApiError(error);
 | |
|     expect(result).toBe(false);
 | |
|   });
 | |
| });
 |