diff --git a/src/library-authoring/create-library/CreateLibrary.test.tsx b/src/library-authoring/create-library/CreateLibrary.test.tsx index d88a3b721e..73517f788d 100644 --- a/src/library-authoring/create-library/CreateLibrary.test.tsx +++ b/src/library-authoring/create-library/CreateLibrary.test.tsx @@ -15,7 +15,7 @@ import { getContentLibraryV2CreateApiUrl } from './data/api'; let store; const mockNavigate = jest.fn(); -let axiosMock; +let axiosMock: MockAdapter; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -60,11 +60,7 @@ describe('', () => { }); store = initializeStore(); - // The API method to get the Meilisearch connection details uses Axios: axiosMock = new MockAdapter(getAuthenticatedHttpClient()); - axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(200, { - id: 'library-id', - }); }); afterEach(() => { @@ -73,7 +69,11 @@ describe('', () => { queryClient.clear(); }); - it('call api data with correct data', async () => { + test('call api data with correct data', async () => { + axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(200, { + id: 'library-id', + }); + const { getByRole, getByTestId } = render(); const titleInput = getByRole('textbox', { name: /library name/i }); @@ -98,4 +98,35 @@ describe('', () => { expect(mockNavigate).toHaveBeenCalledWith('/library/library-id'); }); }); + + test('show api error', async () => { + axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(400, { + field: 'Error message', + }); + const { getByRole, getByTestId } = render(); + + const titleInput = getByRole('textbox', { name: /library name/i }); + userEvent.click(titleInput); + userEvent.type(titleInput, 'Test Library Name'); + + const orgInput = getByTestId('autosuggest-textbox-input'); + userEvent.click(orgInput); + userEvent.type(orgInput, 'org1'); + userEvent.tab(); + + const slugInput = getByRole('textbox', { name: /library id/i }); + userEvent.click(slugInput); + userEvent.type(slugInput, 'test_library_slug'); + + fireEvent.click(getByRole('button', { name: /create/i })); + await waitFor(() => { + expect(axiosMock.history.post.length).toBe(1); + expect(axiosMock.history.post[0].data).toBe( + '{"description":"","title":"Test Library Name","org":"org1","slug":"test_library_slug"}', + ); + expect(mockNavigate).not.toHaveBeenCalled(); + expect(getByRole('alert')).toHaveTextContent('Request failed with status code 400'); + expect(getByRole('alert')).toHaveTextContent('{"field":"Error message"}'); + }); + }); }); diff --git a/src/library-authoring/create-library/CreateLibrary.tsx b/src/library-authoring/create-library/CreateLibrary.tsx index 5c245d937f..3fdf765def 100644 --- a/src/library-authoring/create-library/CreateLibrary.tsx +++ b/src/library-authoring/create-library/CreateLibrary.tsx @@ -8,6 +8,7 @@ import { Form, StatefulButton, } from '@openedx/paragon'; +import axios from 'axios'; import { Formik } from 'formik'; import { useNavigate } from 'react-router-dom'; import * as Yup from 'yup'; @@ -27,7 +28,7 @@ const CreateLibrary = () => { const intl = useIntl(); const navigate = useNavigate(); - const [apiError, setApiError] = useState(); + const [apiError, setApiError] = useState(); const { noSpaceRule, specialCharsRule } = REGEX_RULES; const validSlugIdRegex = /^[a-zA-Z\d]+(?:[\w -]*[a-zA-Z\d]+)*$/; @@ -54,7 +55,6 @@ const CreateLibrary = () => { org: '', slug: '', }} - validationSchema={ Yup.object().shape({ title: Yup.string() @@ -74,15 +74,20 @@ const CreateLibrary = () => { ), }) } - onSubmit={async (values: CreateContentLibraryDto) => { setApiError(undefined); try { const data = await mutateAsync(values); navigate(`/library/${data.id}`); - } catch (error) { - if (error instanceof Error) { - setApiError(error.message); + } catch (error: any) { + if (axios.isAxiosError(error)) { + setApiError(( + <> + {error.message} +
+ {JSON.stringify(error.response?.data)} + + )); } } }}