192 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			5.6 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 { vi, describe, it, expect, beforeAll, beforeEach } from 'vitest';
 | 
						|
import { Toast } from '@coze-arch/bot-semi';
 | 
						|
import { axiosInstance, isApiError, ApiError } from '@coze-arch/bot-http';
 | 
						|
 | 
						|
// Import axios configuration to trigger Toast configuration
 | 
						|
import '../src/axios';
 | 
						|
 | 
						|
vi.mock('@coze-arch/bot-semi', () => ({
 | 
						|
  Toast: {
 | 
						|
    config: vi.fn(),
 | 
						|
    error: vi.fn(),
 | 
						|
  },
 | 
						|
}));
 | 
						|
 | 
						|
// emulating the isApiError function
 | 
						|
vi.mock('@coze-arch/bot-http', () => {
 | 
						|
  // Save the original axiosInstant.interceptors.response.use method
 | 
						|
  const originalUse = vi.fn();
 | 
						|
 | 
						|
  return {
 | 
						|
    axiosInstance: {
 | 
						|
      interceptors: {
 | 
						|
        response: {
 | 
						|
          use: originalUse,
 | 
						|
        },
 | 
						|
      },
 | 
						|
    },
 | 
						|
    isApiError: vi.fn(),
 | 
						|
    ApiError: vi
 | 
						|
      .fn()
 | 
						|
      .mockImplementation(function (this: any, code: string, msg: string) {
 | 
						|
        this.code = code;
 | 
						|
        this.msg = msg;
 | 
						|
        this.config = {};
 | 
						|
        this.name = 'ApiError';
 | 
						|
      }),
 | 
						|
  };
 | 
						|
});
 | 
						|
 | 
						|
describe('axios configuration', () => {
 | 
						|
  let onFulfilled: Function;
 | 
						|
  let onRejected: Function;
 | 
						|
 | 
						|
  beforeAll(async () => {
 | 
						|
    // Import axios configuration to trigger Toast configuration and blocker registration
 | 
						|
    await import('../src/axios');
 | 
						|
 | 
						|
    // Verify that Toast.config is called
 | 
						|
    expect(Toast.config).toHaveBeenCalledWith({ top: 80 });
 | 
						|
 | 
						|
    // Get the registered interceptor function
 | 
						|
    const useArgs = (axiosInstance.interceptors.response.use as any).mock
 | 
						|
      .calls[0];
 | 
						|
    onFulfilled = useArgs[0];
 | 
						|
    onRejected = useArgs[1];
 | 
						|
  });
 | 
						|
 | 
						|
  beforeEach(() => {
 | 
						|
    vi.clearAllMocks();
 | 
						|
  });
 | 
						|
 | 
						|
  describe('response interceptor', () => {
 | 
						|
    it('should return response data directly on success', () => {
 | 
						|
      const mockData = { foo: 'bar' };
 | 
						|
      const mockResponse = { data: mockData };
 | 
						|
 | 
						|
      const result = onFulfilled(mockResponse);
 | 
						|
 | 
						|
      expect(result).toEqual(mockData);
 | 
						|
    });
 | 
						|
 | 
						|
    it('should show error toast when API error occurs', () => {
 | 
						|
      // Create an API error
 | 
						|
      const apiError = new (ApiError as any)('500', 'API Error');
 | 
						|
 | 
						|
      // isApiError returns true
 | 
						|
      (isApiError as any).mockReturnValue(true);
 | 
						|
 | 
						|
      try {
 | 
						|
        onRejected(apiError);
 | 
						|
        // If no errors are thrown, the test should fail
 | 
						|
        expect(true).toBe(false);
 | 
						|
      } catch (error) {
 | 
						|
        expect(isApiError).toHaveBeenCalledWith(apiError);
 | 
						|
        expect(Toast.error).toHaveBeenCalledWith({
 | 
						|
          content: apiError.msg,
 | 
						|
          showClose: false,
 | 
						|
        });
 | 
						|
        expect(error).toBe(apiError);
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not show error toast when __disableErrorToast is true', () => {
 | 
						|
      // Create an API error and set __disableErrorToast to true
 | 
						|
      const apiError = new (ApiError as any)('401', 'Unauthorized');
 | 
						|
      apiError.config.__disableErrorToast = true;
 | 
						|
 | 
						|
      // isApiError returns true
 | 
						|
      (isApiError as any).mockReturnValue(true);
 | 
						|
 | 
						|
      try {
 | 
						|
        onRejected(apiError);
 | 
						|
        // If no errors are thrown, the test should fail
 | 
						|
        expect(true).toBe(false);
 | 
						|
      } catch (error) {
 | 
						|
        expect(isApiError).toHaveBeenCalledWith(apiError);
 | 
						|
        expect(Toast.error).not.toHaveBeenCalled();
 | 
						|
        expect(error).toBe(apiError);
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not show error toast when error has no message', () => {
 | 
						|
      // Create an API error with no message
 | 
						|
      const apiError = new (ApiError as any)('403', undefined);
 | 
						|
 | 
						|
      // isApiError returns true
 | 
						|
      (isApiError as any).mockReturnValue(true);
 | 
						|
 | 
						|
      try {
 | 
						|
        onRejected(apiError);
 | 
						|
        // If no errors are thrown, the test should fail
 | 
						|
        expect(true).toBe(false);
 | 
						|
      } catch (error) {
 | 
						|
        expect(isApiError).toHaveBeenCalledWith(apiError);
 | 
						|
        expect(Toast.error).not.toHaveBeenCalled();
 | 
						|
        expect(error).toBe(apiError);
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not show error toast when isApiError returns false', () => {
 | 
						|
      // Create a normal error
 | 
						|
      const regularError = new Error('Regular Error');
 | 
						|
      (regularError as any).msg = 'Error message';
 | 
						|
 | 
						|
      // isApiError returned false
 | 
						|
      (isApiError as any).mockReturnValue(false);
 | 
						|
 | 
						|
      try {
 | 
						|
        onRejected(regularError);
 | 
						|
        // If no errors are thrown, the test should fail
 | 
						|
        expect(true).toBe(false);
 | 
						|
      } catch (error) {
 | 
						|
        expect(isApiError).toHaveBeenCalledWith(regularError);
 | 
						|
        expect(Toast.error).not.toHaveBeenCalled();
 | 
						|
        expect(error).toBe(regularError);
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    it('should handle null or undefined error', () => {
 | 
						|
      // Test null error
 | 
						|
      try {
 | 
						|
        onRejected(null);
 | 
						|
        // If no errors are thrown, the test should fail
 | 
						|
        expect(true).toBe(false);
 | 
						|
      } catch (error) {
 | 
						|
        expect(isApiError).toHaveBeenCalledWith(null);
 | 
						|
        expect(Toast.error).not.toHaveBeenCalled();
 | 
						|
        expect(error).toBe(null);
 | 
						|
      }
 | 
						|
 | 
						|
      vi.clearAllMocks();
 | 
						|
 | 
						|
      // Test undefined error
 | 
						|
      try {
 | 
						|
        onRejected(undefined);
 | 
						|
        // If no errors are thrown, the test should fail
 | 
						|
        expect(true).toBe(false);
 | 
						|
      } catch (error) {
 | 
						|
        expect(isApiError).toHaveBeenCalledWith(undefined);
 | 
						|
        expect(Toast.error).not.toHaveBeenCalled();
 | 
						|
        expect(error).toBe(undefined);
 | 
						|
      }
 | 
						|
    });
 | 
						|
  });
 | 
						|
});
 |