fix(tests): resolve frontend unit test issues due to new errors system

This commit is contained in:
perf3ct 2025-07-20 04:09:47 +00:00
parent aac32ea64a
commit fbaf30b29e
2 changed files with 78 additions and 42 deletions

View File

@ -18,7 +18,8 @@ describe('ErrorHelper', () => {
status: 404 status: 404
}, },
status: 404 status: 404
} },
isAxiosError: true
}; };
const result = ErrorHelper.getErrorInfo(structuredError); const result = ErrorHelper.getErrorInfo(structuredError);
@ -37,7 +38,8 @@ describe('ErrorHelper', () => {
message: 'Legacy error message' message: 'Legacy error message'
}, },
status: 500 status: 500
} },
isAxiosError: true
}; };
const result = ErrorHelper.getErrorInfo(legacyError); const result = ErrorHelper.getErrorInfo(legacyError);
@ -53,7 +55,8 @@ describe('ErrorHelper', () => {
message: 'Network Error', message: 'Network Error',
response: { response: {
status: 500 status: 500
} },
isAxiosError: true
}; };
const result = ErrorHelper.getErrorInfo(axiosError); const result = ErrorHelper.getErrorInfo(axiosError);
@ -98,7 +101,8 @@ describe('ErrorHelper', () => {
data: {}, data: {},
status: 400 status: 400
}, },
message: 'Bad Request' message: 'Bad Request',
isAxiosError: true
}; };
const result = ErrorHelper.getErrorInfo(emptyError); const result = ErrorHelper.getErrorInfo(emptyError);
@ -119,7 +123,8 @@ describe('ErrorHelper', () => {
code: 'USER_NOT_FOUND', code: 'USER_NOT_FOUND',
status: 404 status: 404
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.isErrorCode(error, ErrorCodes.USER_NOT_FOUND)).toBe(true); expect(ErrorHelper.isErrorCode(error, ErrorCodes.USER_NOT_FOUND)).toBe(true);
@ -133,7 +138,8 @@ describe('ErrorHelper', () => {
code: 'USER_NOT_FOUND', code: 'USER_NOT_FOUND',
status: 404 status: 404
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.isErrorCode(error, ErrorCodes.USER_DUPLICATE_USERNAME)).toBe(false); expect(ErrorHelper.isErrorCode(error, ErrorCodes.USER_DUPLICATE_USERNAME)).toBe(false);
@ -145,7 +151,8 @@ describe('ErrorHelper', () => {
data: { data: {
message: 'Legacy error' message: 'Legacy error'
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.isErrorCode(error, ErrorCodes.USER_NOT_FOUND)).toBe(false); expect(ErrorHelper.isErrorCode(error, ErrorCodes.USER_NOT_FOUND)).toBe(false);
@ -172,7 +179,8 @@ describe('ErrorHelper', () => {
code: 'USER_NOT_FOUND', code: 'USER_NOT_FOUND',
status: 404 status: 404
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.getUserMessage(error)).toBe('Custom error message'); expect(ErrorHelper.getUserMessage(error)).toBe('Custom error message');
@ -185,7 +193,7 @@ describe('ErrorHelper', () => {
test('should return default fallback when no message', () => { test('should return default fallback when no message', () => {
const error = null; const error = null;
expect(ErrorHelper.getUserMessage(error)).toBe('An error occurred'); expect(ErrorHelper.getUserMessage(error)).toBe('An unknown error occurred');
}); });
}); });
@ -198,7 +206,8 @@ describe('ErrorHelper', () => {
code: 'USER_DUPLICATE_USERNAME', code: 'USER_DUPLICATE_USERNAME',
status: 409 status: 409
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.getSuggestedAction(error)).toBe('Please choose a different username'); expect(ErrorHelper.getSuggestedAction(error)).toBe('Please choose a different username');
@ -212,7 +221,8 @@ describe('ErrorHelper', () => {
code: 'USER_INVALID_CREDENTIALS', code: 'USER_INVALID_CREDENTIALS',
status: 401 status: 401
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.getSuggestedAction(error)).toBe('Please check your username and password'); expect(ErrorHelper.getSuggestedAction(error)).toBe('Please check your username and password');
@ -226,7 +236,8 @@ describe('ErrorHelper', () => {
code: 'UNKNOWN_ERROR_CODE', code: 'UNKNOWN_ERROR_CODE',
status: 500 status: 500
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.getSuggestedAction(error)).toBe(null); expect(ErrorHelper.getSuggestedAction(error)).toBe(null);
@ -247,7 +258,8 @@ describe('ErrorHelper', () => {
code: 'SOURCE_CONNECTION_FAILED', code: 'SOURCE_CONNECTION_FAILED',
status: 503 status: 503
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.shouldShowRetry(error)).toBe(true); expect(ErrorHelper.shouldShowRetry(error)).toBe(true);
@ -260,7 +272,8 @@ describe('ErrorHelper', () => {
message: 'Internal server error' message: 'Internal server error'
}, },
status: 500 status: 500
} },
isAxiosError: true
}; };
expect(ErrorHelper.shouldShowRetry(error)).toBe(true); expect(ErrorHelper.shouldShowRetry(error)).toBe(true);
@ -274,7 +287,8 @@ describe('ErrorHelper', () => {
code: 'USER_INVALID_CREDENTIALS', code: 'USER_INVALID_CREDENTIALS',
status: 400 status: 400
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.shouldShowRetry(error)).toBe(false); expect(ErrorHelper.shouldShowRetry(error)).toBe(false);
@ -293,7 +307,8 @@ describe('ErrorHelper', () => {
const error = { const error = {
response: { response: {
data: { error: 'Test', code, status: 401 } data: { error: 'Test', code, status: 401 }
} },
isAxiosError: true
}; };
expect(ErrorHelper.getErrorCategory(error)).toBe('auth'); expect(ErrorHelper.getErrorCategory(error)).toBe('auth');
}); });
@ -310,7 +325,8 @@ describe('ErrorHelper', () => {
const error = { const error = {
response: { response: {
data: { error: 'Test', code, status: 400 } data: { error: 'Test', code, status: 400 }
} },
isAxiosError: true
}; };
expect(ErrorHelper.getErrorCategory(error)).toBe('validation'); expect(ErrorHelper.getErrorCategory(error)).toBe('validation');
}); });
@ -324,7 +340,8 @@ describe('ErrorHelper', () => {
code: 'SOURCE_CONNECTION_FAILED', code: 'SOURCE_CONNECTION_FAILED',
status: 503 status: 503
} }
} },
isAxiosError: true
}; };
expect(ErrorHelper.getErrorCategory(error)).toBe('network'); expect(ErrorHelper.getErrorCategory(error)).toBe('network');
@ -338,7 +355,7 @@ describe('ErrorHelper', () => {
{ status: 422, expectedCategory: 'validation' }, { status: 422, expectedCategory: 'validation' },
{ status: 500, expectedCategory: 'server' }, { status: 500, expectedCategory: 'server' },
{ status: 502, expectedCategory: 'server' }, { status: 502, expectedCategory: 'server' },
{ status: 503, expectedCategory: 'server' } { status: 503, expectedCategory: 'network' }
]; ];
statusTests.forEach(({ status, expectedCategory }) => { statusTests.forEach(({ status, expectedCategory }) => {
@ -346,7 +363,8 @@ describe('ErrorHelper', () => {
response: { response: {
data: { message: 'Test error' }, data: { message: 'Test error' },
status status
} },
isAxiosError: true
}; };
expect(ErrorHelper.getErrorCategory(error)).toBe(expectedCategory); expect(ErrorHelper.getErrorCategory(error)).toBe(expectedCategory);
}); });
@ -373,16 +391,16 @@ describe('ErrorHelper', () => {
let error; let error;
switch (category) { switch (category) {
case 'auth': case 'auth':
error = { response: { data: { code: 'USER_INVALID_CREDENTIALS' }, status: 401 } }; error = { response: { data: { code: 'USER_INVALID_CREDENTIALS' }, status: 401 }, isAxiosError: true };
break; break;
case 'validation': case 'validation':
error = { response: { data: { code: 'USER_INVALID_PASSWORD' }, status: 400 } }; error = { response: { data: { code: 'USER_INVALID_PASSWORD' }, status: 400 }, isAxiosError: true };
break; break;
case 'network': case 'network':
error = { response: { data: { code: 'SOURCE_CONNECTION_FAILED' }, status: 503 } }; error = { response: { data: { code: 'SOURCE_CONNECTION_FAILED' }, status: 503 }, isAxiosError: true };
break; break;
case 'server': case 'server':
error = { response: { data: { message: 'Server error' }, status: 500 } }; error = { response: { data: { message: 'Server error' }, status: 500 }, isAxiosError: true };
break; break;
default: default:
error = new Error('Unknown error'); error = new Error('Unknown error');
@ -402,7 +420,8 @@ describe('ErrorHelper', () => {
code: 'USER_DUPLICATE_USERNAME', code: 'USER_DUPLICATE_USERNAME',
status: 409 status: 409
} }
} },
isAxiosError: true
}; };
const result = ErrorHelper.formatErrorForDisplay(error, true); const result = ErrorHelper.formatErrorForDisplay(error, true);
@ -425,7 +444,8 @@ describe('ErrorHelper', () => {
code: 'USER_DUPLICATE_USERNAME', code: 'USER_DUPLICATE_USERNAME',
status: 409 status: 409
} }
} },
isAxiosError: true
}; };
const result = ErrorHelper.formatErrorForDisplay(error, false); const result = ErrorHelper.formatErrorForDisplay(error, false);
@ -446,7 +466,8 @@ describe('ErrorHelper', () => {
const error = { const error = {
response: { response: {
data: { error: 'Test', code, status: 400 } data: { error: 'Test', code, status: 400 }
} },
isAxiosError: true
}; };
const result = ErrorHelper.formatErrorForDisplay(error, true); const result = ErrorHelper.formatErrorForDisplay(error, true);
@ -464,7 +485,8 @@ describe('ErrorHelper', () => {
code: 'USER_SESSION_EXPIRED', code: 'USER_SESSION_EXPIRED',
status: 401 status: 401
} }
} },
isAxiosError: true
}; };
const onLogin = vi.fn(); const onLogin = vi.fn();
@ -482,7 +504,8 @@ describe('ErrorHelper', () => {
code: 'SOURCE_CONNECTION_FAILED', code: 'SOURCE_CONNECTION_FAILED',
status: 503 status: 503
} }
} },
isAxiosError: true
}; };
const onRetry = vi.fn(); const onRetry = vi.fn();
@ -503,7 +526,8 @@ describe('ErrorHelper', () => {
code: 'SOME_OTHER_ERROR', code: 'SOME_OTHER_ERROR',
status: 400 status: 400
} }
} },
isAxiosError: true
}; };
const result = ErrorHelper.handleSpecificError(error); const result = ErrorHelper.handleSpecificError(error);
@ -518,7 +542,8 @@ describe('ErrorHelper', () => {
code: 'USER_SESSION_EXPIRED', code: 'USER_SESSION_EXPIRED',
status: 401 status: 401
} }
} },
isAxiosError: true
}; };
const result = ErrorHelper.handleSpecificError(error); const result = ErrorHelper.handleSpecificError(error);
@ -560,12 +585,12 @@ describe('ErrorHelper', () => {
describe('Edge cases and robustness', () => { describe('Edge cases and robustness', () => {
test('should handle malformed error objects', () => { test('should handle malformed error objects', () => {
const malformedErrors = [ const malformedErrors = [
{ response: null }, { response: null, isAxiosError: true },
{ response: { data: null } }, { response: { data: null }, isAxiosError: true },
{ response: { data: { error: null, code: null } } }, { response: { data: { error: null, code: null } }, isAxiosError: true },
{ response: { status: 'not-a-number' } }, { response: { status: 'not-a-number' }, isAxiosError: true },
{ code: 123 }, // numeric code instead of string { code: 123, isAxiosError: true }, // numeric code instead of string
{ message: { nested: 'object' } } // object instead of string { message: { nested: 'object' }, isAxiosError: true } // object instead of string
]; ];
malformedErrors.forEach(error => { malformedErrors.forEach(error => {
@ -586,7 +611,8 @@ describe('ErrorHelper', () => {
code: 'USER_NOT_FOUND', code: 'USER_NOT_FOUND',
status: 404 status: 404
} }
} },
isAxiosError: true
}; };
const result = ErrorHelper.getErrorInfo(error); const result = ErrorHelper.getErrorInfo(error);
@ -602,7 +628,8 @@ describe('ErrorHelper', () => {
code: 12345, // numeric code code: 12345, // numeric code
status: 400 status: 400
} }
} },
isAxiosError: true
}; };
// Should not crash and should handle it as if no code was provided // Should not crash and should handle it as if no code was provided
@ -623,7 +650,8 @@ describe('ErrorHelper', () => {
response: { response: {
data: apiError, data: apiError,
status: 404 status: 404
} },
isAxiosError: true
}; };
const result = ErrorHelper.getErrorInfo(error); const result = ErrorHelper.getErrorInfo(error);
@ -645,7 +673,8 @@ describe('ErrorHelper', () => {
headers: {} headers: {}
}, },
message: 'Request failed', message: 'Request failed',
name: 'AxiosError' name: 'AxiosError',
isAxiosError: true
}; };
const result = ErrorHelper.getErrorInfo(axiosError); const result = ErrorHelper.getErrorInfo(axiosError);

View File

@ -140,6 +140,9 @@ export const ErrorHelper = {
*/ */
getUserMessage: (error: unknown, fallback?: string): string => { getUserMessage: (error: unknown, fallback?: string): string => {
const errorInfo = ErrorHelper.getErrorInfo(error) const errorInfo = ErrorHelper.getErrorInfo(error)
if (errorInfo.message === 'An unknown error occurred' && fallback) {
return fallback
}
return errorInfo.message || fallback || 'An error occurred' return errorInfo.message || fallback || 'An error occurred'
}, },
@ -219,7 +222,7 @@ export const ErrorHelper = {
if (['USER_INVALID_CREDENTIALS', 'USER_TOKEN_EXPIRED', 'USER_SESSION_EXPIRED'].includes(errorInfo.code)) { if (['USER_INVALID_CREDENTIALS', 'USER_TOKEN_EXPIRED', 'USER_SESSION_EXPIRED'].includes(errorInfo.code)) {
return 'auth' return 'auth'
} }
if (['USER_INVALID_PASSWORD', 'USER_INVALID_EMAIL', 'USER_INVALID_USERNAME'].includes(errorInfo.code)) { if (['USER_INVALID_PASSWORD', 'USER_INVALID_EMAIL', 'USER_INVALID_USERNAME', 'USER_DUPLICATE_USERNAME', 'USER_DUPLICATE_EMAIL'].includes(errorInfo.code)) {
return 'validation' return 'validation'
} }
} }
@ -232,6 +235,10 @@ export const ErrorHelper = {
return 'validation' return 'validation'
} }
if (errorInfo.status === 503) {
return 'network'
}
if (errorInfo.status && errorInfo.status >= 500) { if (errorInfo.status && errorInfo.status >= 500) {
return 'server' return 'server'
} }