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);
 | 
						|
  });
 | 
						|
});
 |