🥅(frontend) handle api errors
- add hook to handle api errors. - add related component tests
This commit is contained in:
committed by
Sebastien Nobour
parent
b5d8e92d1e
commit
25898bbb64
174
src/frontend/apps/desk/src/api/__tests__/parseAPIError.test.tsx
Normal file
174
src/frontend/apps/desk/src/api/__tests__/parseAPIError.test.tsx
Normal file
@@ -0,0 +1,174 @@
|
||||
import { APIError } from '@/api';
|
||||
|
||||
import {
|
||||
parseAPIError,
|
||||
parseAPIErrorCause,
|
||||
parseServerAPIError,
|
||||
} from '../parseAPIError';
|
||||
|
||||
describe('parseAPIError', () => {
|
||||
const handleErrorMock = jest.fn();
|
||||
const handleServerErrorMock = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should handle specific API error and return no unhandled causes', () => {
|
||||
const error = new APIError('client error', {
|
||||
cause: ['Mail domain with this name already exists.'],
|
||||
status: 400,
|
||||
});
|
||||
|
||||
const result = parseAPIError({
|
||||
error,
|
||||
errorParams: {
|
||||
name: {
|
||||
causes: ['Mail domain with this name already exists.'],
|
||||
handleError: handleErrorMock,
|
||||
},
|
||||
},
|
||||
serverErrorParams: {
|
||||
defaultMessage: 'Server error',
|
||||
handleError: handleServerErrorMock,
|
||||
},
|
||||
});
|
||||
|
||||
expect(handleErrorMock).toHaveBeenCalled();
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return unhandled causes when no match is found', () => {
|
||||
const error = new APIError('client error', {
|
||||
cause: ['Unhandled error'],
|
||||
status: 400,
|
||||
});
|
||||
|
||||
const result = parseAPIError({
|
||||
error,
|
||||
errorParams: {
|
||||
name: {
|
||||
causes: ['Mail domain with this name already exists.'],
|
||||
handleError: handleErrorMock,
|
||||
},
|
||||
},
|
||||
serverErrorParams: {
|
||||
defaultMessage: 'Server error',
|
||||
handleError: handleServerErrorMock,
|
||||
},
|
||||
});
|
||||
|
||||
expect(handleErrorMock).not.toHaveBeenCalled();
|
||||
expect(result).toEqual(['Unhandled error']);
|
||||
});
|
||||
|
||||
it('should handle server errors correctly and prepend server error message', () => {
|
||||
const error = new APIError('server error', { status: 500 });
|
||||
|
||||
const result = parseAPIError({
|
||||
error,
|
||||
errorParams: undefined,
|
||||
serverErrorParams: {
|
||||
defaultMessage: 'Server error occurred',
|
||||
handleError: handleServerErrorMock,
|
||||
},
|
||||
});
|
||||
|
||||
expect(handleServerErrorMock).toHaveBeenCalled();
|
||||
expect(result).toEqual(['Server error occurred']);
|
||||
});
|
||||
|
||||
it('should handle absence of errors gracefully', () => {
|
||||
const result = parseAPIError({
|
||||
error: null,
|
||||
errorParams: {
|
||||
name: {
|
||||
causes: ['Mail domain with this name already exists.'],
|
||||
handleError: handleErrorMock,
|
||||
},
|
||||
},
|
||||
serverErrorParams: {
|
||||
defaultMessage: 'Server error',
|
||||
handleError: handleServerErrorMock,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseAPIErrorCause', () => {
|
||||
it('should handle specific errors and call handleError', () => {
|
||||
const handleErrorMock = jest.fn();
|
||||
const causes = ['Mail domain with this name already exists.'];
|
||||
|
||||
const errorParams = {
|
||||
name: {
|
||||
causes: ['Mail domain with this name already exists.'],
|
||||
handleError: handleErrorMock,
|
||||
},
|
||||
};
|
||||
|
||||
const result = parseAPIErrorCause({ causes, errorParams });
|
||||
|
||||
expect(handleErrorMock).toHaveBeenCalled();
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle multiple causes and return unhandled causes', () => {
|
||||
const handleErrorMock = jest.fn();
|
||||
const causes = [
|
||||
'Mail domain with this name already exists.',
|
||||
'Unhandled error',
|
||||
];
|
||||
|
||||
const errorParams = {
|
||||
name: {
|
||||
causes: ['Mail domain with this name already exists.'],
|
||||
handleError: handleErrorMock,
|
||||
},
|
||||
};
|
||||
|
||||
const result = parseAPIErrorCause({ causes, errorParams });
|
||||
|
||||
expect(handleErrorMock).toHaveBeenCalled();
|
||||
expect(result).toEqual(['Unhandled error']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseServerAPIError', () => {
|
||||
it('should prepend the server error message when there are other causes', () => {
|
||||
const causes = ['Some other error'];
|
||||
const serverErrorParams = {
|
||||
defaultMessage: 'Server error',
|
||||
};
|
||||
|
||||
const result = parseServerAPIError({ causes, serverErrorParams });
|
||||
|
||||
expect(result).toEqual(['Server error', 'Some other error']);
|
||||
});
|
||||
|
||||
it('should only return server error message when no other causes exist', () => {
|
||||
const causes: string[] = [];
|
||||
const serverErrorParams = {
|
||||
defaultMessage: 'Server error',
|
||||
};
|
||||
|
||||
const result = parseServerAPIError({ causes, serverErrorParams });
|
||||
|
||||
expect(result).toEqual(['Server error']);
|
||||
});
|
||||
|
||||
it('should call handleError when provided as a param', () => {
|
||||
const handleErrorMock = jest.fn();
|
||||
const causes: string[] = [];
|
||||
const serverErrorParams = {
|
||||
defaultMessage: 'Server error',
|
||||
handleError: handleErrorMock,
|
||||
};
|
||||
|
||||
parseServerAPIError({ causes, serverErrorParams });
|
||||
|
||||
expect(handleErrorMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
83
src/frontend/apps/desk/src/api/parseAPIError.ts
Normal file
83
src/frontend/apps/desk/src/api/parseAPIError.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { APIError } from '@/api/index';
|
||||
|
||||
type ErrorParams = {
|
||||
[fieldName: string]: {
|
||||
causes: string[];
|
||||
causeShown?: string;
|
||||
handleError: () => void;
|
||||
};
|
||||
};
|
||||
|
||||
type ServerErrorParams = {
|
||||
defaultMessage: string;
|
||||
handleError?: () => void;
|
||||
};
|
||||
|
||||
export type parseAPIErrorParams = {
|
||||
error: APIError | null;
|
||||
errorParams?: ErrorParams;
|
||||
serverErrorParams: ServerErrorParams;
|
||||
};
|
||||
export const parseAPIError = ({
|
||||
error,
|
||||
errorParams,
|
||||
serverErrorParams,
|
||||
}: parseAPIErrorParams) => {
|
||||
if (!error || !serverErrorParams?.defaultMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
let causes: string[] =
|
||||
error.cause?.length && errorParams
|
||||
? parseAPIErrorCause({ causes: error.cause, errorParams })
|
||||
: [];
|
||||
|
||||
if (error?.status === 500 || !error?.status) {
|
||||
causes = parseServerAPIError({ causes, serverErrorParams });
|
||||
}
|
||||
|
||||
return causes;
|
||||
};
|
||||
|
||||
export const parseAPIErrorCause = ({
|
||||
causes,
|
||||
errorParams,
|
||||
}: {
|
||||
causes: string[];
|
||||
errorParams: ErrorParams;
|
||||
}): string[] =>
|
||||
causes.reduce((arrayCauses, cause) => {
|
||||
const foundErrorParams = Object.values(errorParams).find((params) =>
|
||||
params.causes.find((knownCause) => knownCause.match(cause)),
|
||||
);
|
||||
|
||||
if (!foundErrorParams) {
|
||||
arrayCauses.push(cause);
|
||||
}
|
||||
|
||||
if (foundErrorParams?.causeShown) {
|
||||
arrayCauses.push(foundErrorParams.causeShown);
|
||||
}
|
||||
|
||||
if (typeof foundErrorParams?.handleError === 'function') {
|
||||
foundErrorParams.handleError();
|
||||
}
|
||||
|
||||
return arrayCauses;
|
||||
}, [] as string[]);
|
||||
|
||||
export const parseServerAPIError = ({
|
||||
causes,
|
||||
serverErrorParams,
|
||||
}: {
|
||||
causes: string[];
|
||||
serverErrorParams: ServerErrorParams;
|
||||
}): string[] => {
|
||||
causes.unshift(serverErrorParams.defaultMessage);
|
||||
|
||||
if (typeof serverErrorParams?.handleError === 'function') {
|
||||
serverErrorParams.handleError();
|
||||
}
|
||||
|
||||
return causes;
|
||||
};
|
||||
@@ -2,4 +2,4 @@ export * from './useMailDomains';
|
||||
export * from './useMailDomain';
|
||||
export * from './useCreateMailbox';
|
||||
export * from './useMailboxes';
|
||||
export * from './useCreateMailDomain';
|
||||
export * from './useAddMailDomain';
|
||||
|
||||
Reference in New Issue
Block a user