import React from 'react'; import type MockAdapter from 'axios-mock-adapter'; import userEvent from '@testing-library/user-event'; import { fireEvent, initializeMocks, render, screen, waitFor, } from '../../testUtils'; import { studioHomeMock } from '../../studio-home/__mocks__'; import { getStudioHomeApiUrl } from '../../studio-home/data/api'; import { getApiWaffleFlagsUrl } from '../../data/api'; import { CreateLibrary } from '.'; import { getContentLibraryV2CreateApiUrl } from './data/api'; const mockNavigate = jest.fn(); let axiosMock: MockAdapter; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: () => mockNavigate, })); jest.mock('../../generic/data/apiHooks', () => ({ ...jest.requireActual('../../generic/data/apiHooks'), useOrganizationListData: () => ({ data: ['org1', 'org2', 'org3', 'org4', 'org5'], isLoading: false, }), })); describe('', () => { beforeEach(() => { axiosMock = initializeMocks().axiosMock; axiosMock .onGet(getApiWaffleFlagsUrl(undefined)) .reply(200, {}); }); afterEach(() => { jest.clearAllMocks(); axiosMock.restore(); }); test('call api data with correct data', async () => { const user = userEvent.setup(); axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock); axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(200, { id: 'library-id', }); render(); const titleInput = await screen.findByRole('textbox', { name: /library name/i }); await user.click(titleInput); await user.type(titleInput, 'Test Library Name'); const orgInput = await screen.findByRole('combobox', { name: /organization/i }); await user.click(orgInput); await user.type(orgInput, 'org1'); await user.tab(); const slugInput = await screen.findByRole('textbox', { name: /library id/i }); await user.click(slugInput); await user.type(slugInput, 'test_library_slug'); fireEvent.click(await screen.findByRole('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).toHaveBeenCalledWith('/library/library-id'); }); }); test('cannot create new org unless allowed', async () => { const user = userEvent.setup(); axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock); axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(200, { id: 'library-id', }); render(); const titleInput = await screen.findByRole('textbox', { name: /library name/i }); await user.click(titleInput); await user.type(titleInput, 'Test Library Name'); // We cannot create a new org, and so we're restricted to the allowed list const orgOptions = screen.getByTestId('autosuggest-iconbutton'); await user.click(orgOptions); expect(screen.getByText('org1')).toBeInTheDocument(); ['org2', 'org3', 'org4', 'org5'].forEach((org) => expect(screen.queryByText(org)).not.toBeInTheDocument()); const orgInput = await screen.findByRole('combobox', { name: /organization/i }); await user.click(orgInput); await user.type(orgInput, 'NewOrg'); await user.tab(); const slugInput = await screen.findByRole('textbox', { name: /library id/i }); await user.click(slugInput); await user.type(slugInput, 'test_library_slug'); fireEvent.click(await screen.findByRole('button', { name: /create/i })); await waitFor(() => { expect(axiosMock.history.post.length).toBe(0); }); expect(await screen.findByText('Required field.')).toBeInTheDocument(); }); test('can create new org if allowed', async () => { const user = userEvent.setup(); axiosMock.onGet(getStudioHomeApiUrl()).reply(200, { ...studioHomeMock, allow_to_create_new_org: true, }); axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(200, { id: 'library-id', }); render(); const titleInput = await screen.findByRole('textbox', { name: /library name/i }); await user.click(titleInput); await user.type(titleInput, 'Test Library Name'); // We can create a new org, so we're also allowed to use any existing org const orgOptions = screen.getByTestId('autosuggest-iconbutton'); await user.click(orgOptions); ['org1', 'org2', 'org3', 'org4', 'org5'].forEach((org) => expect(screen.queryByText(org)).toBeInTheDocument()); const orgInput = await screen.findByRole('combobox', { name: /organization/i }); await user.click(orgInput); await user.type(orgInput, 'NewOrg'); await user.tab(); const slugInput = await screen.findByRole('textbox', { name: /library id/i }); await user.click(slugInput); await user.type(slugInput, 'test_library_slug'); fireEvent.click(await screen.findByRole('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":"NewOrg","slug":"test_library_slug"}', ); expect(mockNavigate).toHaveBeenCalledWith('/library/library-id'); }); }); test('show api error', async () => { const user = userEvent.setup(); axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock); axiosMock.onPost(getContentLibraryV2CreateApiUrl()).reply(400, { field: 'Error message', }); render(); const titleInput = await screen.findByRole('textbox', { name: /library name/i }); await user.click(titleInput); await user.type(titleInput, 'Test Library Name'); const orgInput = await screen.findByTestId('autosuggest-textbox-input'); await user.click(orgInput); await user.type(orgInput, 'org1'); await user.tab(); const slugInput = await screen.findByRole('textbox', { name: /library id/i }); await user.click(slugInput); await user.type(slugInput, 'test_library_slug'); fireEvent.click(await screen.findByRole('button', { name: /create/i })); await waitFor(async () => { 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(); const errorMessage = 'Request failed with status code 400{ "field": "Error message" }'; expect(await screen.findByRole('alert')).toHaveTextContent(errorMessage); }); }); test('cancel creating library navigates to libraries page', async () => { render(); fireEvent.click(await screen.findByRole('button', { name: /cancel/i })); await waitFor(() => { expect(mockNavigate).toHaveBeenCalledWith('/libraries'); }); }); });