You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
7.0 KiB
268 lines
7.0 KiB
import { message, notification } from 'antd';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { errorConfig } from './requestErrorConfig';
|
|
|
|
vi.mock('antd', () => ({
|
|
message: {
|
|
warning: vi.fn(),
|
|
error: vi.fn(),
|
|
},
|
|
notification: {
|
|
open: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
vi.mock('@umijs/max', () => ({
|
|
getIntl: vi.fn(() => ({
|
|
formatMessage: vi.fn(({ defaultMessage }) => defaultMessage),
|
|
})),
|
|
}));
|
|
|
|
describe('requestErrorConfig', () => {
|
|
// biome-ignore lint/style/noNonNullAssertion: config handlers are always defined
|
|
const errorThrower = errorConfig.errorConfig!.errorThrower!;
|
|
// biome-ignore lint/style/noNonNullAssertion: config handlers are always defined
|
|
const errorHandler = errorConfig.errorConfig!.errorHandler!;
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('errorThrower', () => {
|
|
it('should throw error when success is false', () => {
|
|
const response = {
|
|
success: false,
|
|
data: null,
|
|
errorCode: 400,
|
|
errorMessage: 'Bad Request',
|
|
showType: 2,
|
|
};
|
|
|
|
expect(() => {
|
|
errorThrower(response);
|
|
}).toThrow('Bad Request');
|
|
});
|
|
|
|
it('should not throw error when success is true', () => {
|
|
const response = {
|
|
success: true,
|
|
data: { id: 1 },
|
|
};
|
|
|
|
expect(() => {
|
|
errorThrower(response);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should throw BizError with correct info', () => {
|
|
const response = {
|
|
success: false,
|
|
data: { detail: 'more info' },
|
|
errorCode: 403,
|
|
errorMessage: 'Forbidden',
|
|
showType: 3,
|
|
};
|
|
|
|
expect.assertions(5);
|
|
try {
|
|
errorThrower(response);
|
|
} catch (error: any) {
|
|
expect(error.name).toBe('BizError');
|
|
expect(error.info.errorCode).toBe(403);
|
|
expect(error.info.errorMessage).toBe('Forbidden');
|
|
expect(error.info.showType).toBe(3);
|
|
expect(error.info.data).toEqual({ detail: 'more info' });
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('errorHandler', () => {
|
|
it('should rethrow error when skipErrorHandler is true', () => {
|
|
const error = new Error('Test error');
|
|
const opts = { skipErrorHandler: true };
|
|
|
|
expect(() => {
|
|
errorHandler(error, opts);
|
|
}).toThrow('Test error');
|
|
});
|
|
|
|
it('should handle SILENT showType', () => {
|
|
const error: any = new Error('Silent error');
|
|
error.name = 'BizError';
|
|
error.info = {
|
|
errorCode: 1001,
|
|
errorMessage: 'Silent error',
|
|
showType: 0,
|
|
};
|
|
|
|
errorHandler(error, {});
|
|
|
|
expect(message.warning).not.toHaveBeenCalled();
|
|
expect(message.error).not.toHaveBeenCalled();
|
|
expect(notification.open).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle WARN_MESSAGE showType', () => {
|
|
const error: any = new Error('Warning');
|
|
error.name = 'BizError';
|
|
error.info = {
|
|
errorCode: 1002,
|
|
errorMessage: 'This is a warning',
|
|
showType: 1,
|
|
};
|
|
|
|
errorHandler(error, {});
|
|
|
|
expect(message.warning).toHaveBeenCalledWith('This is a warning');
|
|
});
|
|
|
|
it('should handle ERROR_MESSAGE showType', () => {
|
|
const error: any = new Error('Error message');
|
|
error.name = 'BizError';
|
|
error.info = {
|
|
errorCode: 1003,
|
|
errorMessage: 'This is an error',
|
|
showType: 2,
|
|
};
|
|
|
|
errorHandler(error, {});
|
|
|
|
expect(message.error).toHaveBeenCalledWith('This is an error');
|
|
});
|
|
|
|
it('should handle NOTIFICATION showType', () => {
|
|
const error: any = new Error('Notification');
|
|
error.name = 'BizError';
|
|
error.info = {
|
|
errorCode: 1004,
|
|
errorMessage: 'This is a notification',
|
|
showType: 3,
|
|
};
|
|
|
|
errorHandler(error, {});
|
|
|
|
expect(notification.open).toHaveBeenCalledWith({
|
|
title: 1004,
|
|
description: 'This is a notification',
|
|
});
|
|
});
|
|
|
|
it('should handle REDIRECT showType', () => {
|
|
const error: any = new Error('Redirect');
|
|
error.name = 'BizError';
|
|
error.info = {
|
|
errorCode: 401,
|
|
errorMessage: 'Unauthorized',
|
|
showType: 9,
|
|
};
|
|
|
|
errorHandler(error, {});
|
|
|
|
// REDIRECT 分支不应触发任何消息/通知提示
|
|
expect(message.warning).not.toHaveBeenCalled();
|
|
expect(message.error).not.toHaveBeenCalled();
|
|
expect(notification.open).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle default case for unknown showType', () => {
|
|
const error: any = new Error('Unknown type');
|
|
error.name = 'BizError';
|
|
error.info = {
|
|
errorCode: 1005,
|
|
errorMessage: 'Unknown error type',
|
|
showType: 99,
|
|
};
|
|
|
|
errorHandler(error, {});
|
|
|
|
expect(message.error).toHaveBeenCalledWith('Unknown error type');
|
|
});
|
|
|
|
it('should handle axios response error', () => {
|
|
const error: any = new Error('Axios error');
|
|
error.response = {
|
|
status: 500,
|
|
data: {},
|
|
};
|
|
|
|
errorHandler(error, {});
|
|
|
|
expect(message.error).toHaveBeenCalledWith('Response status:500');
|
|
});
|
|
|
|
it('should handle offline error', () => {
|
|
const error: any = new Error('Network error');
|
|
error.request = {};
|
|
|
|
const originalOnLine = navigator.onLine;
|
|
Object.defineProperty(navigator, 'onLine', {
|
|
writable: true,
|
|
value: false,
|
|
});
|
|
|
|
try {
|
|
errorHandler(error, {});
|
|
|
|
expect(message.error).toHaveBeenCalledWith(
|
|
'Network unavailable. Please check your connection and try again.',
|
|
);
|
|
} finally {
|
|
Object.defineProperty(navigator, 'onLine', {
|
|
writable: true,
|
|
value: originalOnLine,
|
|
});
|
|
}
|
|
});
|
|
|
|
it('should handle request error with no response', () => {
|
|
const error: any = new Error('Request error');
|
|
error.request = {};
|
|
|
|
errorHandler(error, {});
|
|
|
|
expect(message.error).toHaveBeenCalledWith(
|
|
'None response! Please retry.',
|
|
);
|
|
});
|
|
|
|
it('should handle generic error', () => {
|
|
const error: any = new Error('Generic error');
|
|
|
|
errorHandler(error, {});
|
|
|
|
expect(message.error).toHaveBeenCalledWith(
|
|
'Request error, please retry.',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('requestInterceptors', () => {
|
|
// The interceptor is registered as a plain function (not a tuple),
|
|
// so narrow the union type to a callable for the test.
|
|
const interceptor = errorConfig.requestInterceptors?.[0] as (config: {
|
|
url?: string;
|
|
method?: string;
|
|
}) => { url?: string };
|
|
|
|
it('should pass through config without modification', () => {
|
|
const config = {
|
|
url: 'https://api.example.com/users',
|
|
method: 'GET',
|
|
};
|
|
|
|
const result = interceptor(config);
|
|
|
|
// Token attachment is intentionally commented out in the source;
|
|
// interceptor currently returns config as-is
|
|
expect(result.url).toBe('https://api.example.com/users');
|
|
});
|
|
|
|
it('should handle URL without config', () => {
|
|
const config = {};
|
|
|
|
const result = interceptor(config);
|
|
|
|
expect(result.url).toBeUndefined();
|
|
});
|
|
});
|
|
});
|
|
|