From b53f260ecf540d8da262f39d769acc29b9bc43b3 Mon Sep 17 00:00:00 2001 From: Gustav Hansen Date: Wed, 15 Mar 2023 14:05:11 +0100 Subject: [PATCH 1/3] useAPIErrorHandler: Handle AxiosError --- .../tests/useAPIErrorHandler.test.js | 30 ++++++++++++++++++- .../useAPIErrorHandler/useAPIErrorHandler.js | 6 ++++ .../utils/formatAxiosError/index.js | 13 ++++++++ .../formatAxiosError/tests/index.test.js | 26 ++++++++++++++++ .../utils/getPrefixedId/index.js | 14 +++++++++ .../utils/normalizeAPIError/index.js | 15 +--------- 6 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/index.js create mode 100644 packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/tests/index.test.js create mode 100644 packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js diff --git a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/tests/useAPIErrorHandler.test.js b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/tests/useAPIErrorHandler.test.js index 1f7dde3a4f..30dd26497d 100644 --- a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/tests/useAPIErrorHandler.test.js +++ b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/tests/useAPIErrorHandler.test.js @@ -1,5 +1,6 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { useIntl } from 'react-intl'; +import { AxiosError } from 'axios'; import { useAPIErrorHandler } from '../useAPIErrorHandler'; @@ -19,6 +20,10 @@ function setup(...args) { } describe('useAPIErrorHandler', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + test('exports formatAPIError()', async () => { const handler = await setup(); @@ -80,6 +85,29 @@ describe('useAPIErrorHandler', () => { }); expect(message).toBe('Field contains errors\nField must be unique'); - expect(formatMessage).toBeCalledTimes(3); + expect(formatMessage).toBeCalledTimes(2); + }); + + test('formats AxiosErrors', async () => { + let message; + const handler = await setup(); + const { formatAPIError } = handler.result.current; + + const axiosError = new AxiosError( + 'Error message', + '409', + undefined, + {}, + { + status: 405, + data: { message: 'Error message' }, + } + ); + + act(() => { + message = formatAPIError(axiosError); + }); + + expect(message).toBe('Error message'); }); }); diff --git a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/useAPIErrorHandler.js b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/useAPIErrorHandler.js index b05e167f20..8e53a3a01a 100644 --- a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/useAPIErrorHandler.js +++ b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/useAPIErrorHandler.js @@ -1,6 +1,8 @@ import { useIntl } from 'react-intl'; +import { AxiosError } from 'axios'; import { formatAPIError } from './utils/formatAPIError'; +import { formatAxiosError } from './utils/formatAxiosError'; /** * Hook that exports an error message formatting function. @@ -15,6 +17,10 @@ export function useAPIErrorHandler(intlMessagePrefixCallback) { return { formatAPIError(error) { + if (error instanceof AxiosError) { + return formatAxiosError(error, { intlMessagePrefixCallback, formatMessage }); + } + return formatAPIError(error, { intlMessagePrefixCallback, formatMessage }); }, }; diff --git a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/index.js b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/index.js new file mode 100644 index 0000000000..033fc0539b --- /dev/null +++ b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/index.js @@ -0,0 +1,13 @@ +import { getPrefixedId } from '../getPrefixedId'; + +export function formatAxiosError(error, { intlMessagePrefixCallback, formatMessage }) { + const { code, message } = error; + + return formatMessage({ + id: getPrefixedId(message, intlMessagePrefixCallback), + defaultMessage: message, + values: { + code, + }, + }); +} diff --git a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/tests/index.test.js b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/tests/index.test.js new file mode 100644 index 0000000000..9d1215b8a3 --- /dev/null +++ b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/tests/index.test.js @@ -0,0 +1,26 @@ +import { AxiosError } from 'axios'; + +import { formatAxiosError } from '..'; + +describe('formatAxiosError', () => { + test('serializes AxiosError', () => { + const error = new AxiosError( + 'Error message', + '409', + undefined, + {}, + { + status: 405, + data: { message: 'Error message' }, + } + ); + + expect(formatAxiosError(error, { formatMessage: (obj) => obj })).toStrictEqual({ + defaultMessage: 'Error message', + id: 'apiError.Error message', + values: { + code: '409', + }, + }); + }); +}); diff --git a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js new file mode 100644 index 0000000000..01335314d2 --- /dev/null +++ b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js @@ -0,0 +1,14 @@ +const ERROR_PREFIX = 'apiError.'; + +export function getPrefixedId(message, callback) { + const prefixedMessage = `${ERROR_PREFIX}${message}`; + + // if a prefix function has been passed in it is used to + // prefix the id, e.g. to allow an error message to be + // set only for a localization namespace + if (callback) { + return callback(prefixedMessage); + } + + return prefixedMessage; +} diff --git a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/normalizeAPIError/index.js b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/normalizeAPIError/index.js index fc0a405255..710902a3f1 100644 --- a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/normalizeAPIError/index.js +++ b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/normalizeAPIError/index.js @@ -1,17 +1,4 @@ -const ERROR_PREFIX = 'apiError.'; - -function getPrefixedId(message, callback) { - const prefixedMessage = `${ERROR_PREFIX}${message}`; - - // if a prefix function has been passed in it is used to - // prefix the id, e.g. to allow an error message to be - // set only for a localization namespace - if (callback) { - return callback(prefixedMessage); - } - - return prefixedMessage; -} +import { getPrefixedId } from '../getPrefixedId'; function normalizeError(error, { name, intlMessagePrefixCallback }) { const { message, path } = error; From 7f11c8bbdfb86665528f3aab63daea844db005aa Mon Sep 17 00:00:00 2001 From: Gustav Hansen Date: Wed, 15 Mar 2023 15:26:59 +0100 Subject: [PATCH 2/3] useAPIErrorHandler: Stop testing react-intl internals --- .../utils/formatAxiosError/tests/index.test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/tests/index.test.js b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/tests/index.test.js index 9d1215b8a3..52fc44ded8 100644 --- a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/tests/index.test.js +++ b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/formatAxiosError/tests/index.test.js @@ -4,6 +4,7 @@ import { formatAxiosError } from '..'; describe('formatAxiosError', () => { test('serializes AxiosError', () => { + const spy = jest.fn((obj) => obj); const error = new AxiosError( 'Error message', '409', @@ -15,7 +16,9 @@ describe('formatAxiosError', () => { } ); - expect(formatAxiosError(error, { formatMessage: (obj) => obj })).toStrictEqual({ + formatAxiosError(error, { formatMessage: spy }); + + expect(spy).toHaveBeenCalledWith({ defaultMessage: 'Error message', id: 'apiError.Error message', values: { From 17f773ebd390eb72fd32cf434eeaad250be7abab Mon Sep 17 00:00:00 2001 From: Gustav Hansen Date: Wed, 15 Mar 2023 15:27:37 +0100 Subject: [PATCH 3/3] useAPIErrorHandler: Improve type-safety of getPrefixedId() --- .../src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js index 01335314d2..16c40f81f2 100644 --- a/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js +++ b/packages/core/helper-plugin/lib/src/hooks/useAPIErrorHandler/utils/getPrefixedId/index.js @@ -6,7 +6,7 @@ export function getPrefixedId(message, callback) { // if a prefix function has been passed in it is used to // prefix the id, e.g. to allow an error message to be // set only for a localization namespace - if (callback) { + if (typeof callback === 'function') { return callback(prefixedMessage); }