diff --git a/src/generic/processing-notification/ProcessingNotification.test.jsx b/src/generic/processing-notification/ProcessingNotification.test.jsx index 97f57429bf..d2bbdbeaca 100644 --- a/src/generic/processing-notification/ProcessingNotification.test.jsx +++ b/src/generic/processing-notification/ProcessingNotification.test.jsx @@ -1,13 +1,11 @@ -import { capitalize } from 'lodash'; import userEvent from '@testing-library/user-event'; import { initializeMocks, render, screen } from '../../testUtils'; -import { NOTIFICATION_MESSAGES } from '../../constants'; import ProcessingNotification from '.'; const mockUndo = jest.fn(); const props = { - title: NOTIFICATION_MESSAGES.saving, + title: 'ThIs IS a Test. OK?', isShow: true, action: { label: 'Undo', @@ -22,16 +20,16 @@ describe('', () => { it('renders successfully', () => { render( {}} />); - expect(screen.getByText(capitalize(props.title))).toBeInTheDocument(); + expect(screen.getByText(props.title)).toBeInTheDocument(); expect(screen.getByText('Undo')).toBeInTheDocument(); expect(screen.getByRole('alert').querySelector('.processing-notification-hide-close-button')).not.toBeInTheDocument(); userEvent.click(screen.getByText('Undo')); - expect(mockUndo).toBeCalled(); + expect(mockUndo).toHaveBeenCalled(); }); it('add hide-close-button class if no close action is passed', () => { render(); - expect(screen.getByText(capitalize(props.title))).toBeInTheDocument(); + expect(screen.getByText(props.title)).toBeInTheDocument(); expect(screen.getByRole('alert').querySelector('.processing-notification-hide-close-button')).toBeInTheDocument(); }); }); diff --git a/src/generic/processing-notification/index.jsx b/src/generic/processing-notification/index.jsx index b31150a957..42dc95711f 100644 --- a/src/generic/processing-notification/index.jsx +++ b/src/generic/processing-notification/index.jsx @@ -3,7 +3,6 @@ import { Icon, Toast, } from '@openedx/paragon'; import { Settings as IconSettings } from '@openedx/paragon/icons'; -import { capitalize } from 'lodash'; import classNames from 'classnames'; const ProcessingNotification = ({ @@ -18,7 +17,7 @@ const ProcessingNotification = ({ > - {capitalize(title)} + {title} ); diff --git a/src/generic/toast-context/index.test.tsx b/src/generic/toast-context/index.test.tsx index f7e0a2e4b0..11294b0699 100644 --- a/src/generic/toast-context/index.test.tsx +++ b/src/generic/toast-context/index.test.tsx @@ -13,7 +13,7 @@ const TestComponentToShow = () => { const { showToast } = React.useContext(ToastContext); React.useEffect(() => { - showToast('This is the toast!'); + showToast('This is the Toast!'); }, [showToast]); return
Content
; @@ -23,7 +23,7 @@ const TestComponentToClose = () => { const { showToast, closeToast } = React.useContext(ToastContext); React.useEffect(() => { - showToast('This is the toast!'); + showToast('This is the Toast!'); closeToast(); }, [showToast]); @@ -59,19 +59,19 @@ describe('', () => { it('should show toast', async () => { render(); - expect(await screen.findByText('This is the toast!')).toBeInTheDocument(); + expect(await screen.findByText('This is the Toast!')).toBeInTheDocument(); }); it('should close toast after 5000ms', async () => { render(); - expect(await screen.findByText('This is the toast!')).toBeInTheDocument(); + expect(await screen.findByText('This is the Toast!')).toBeInTheDocument(); jest.advanceTimersByTime(6000); - expect(screen.queryByText('This is the toast!')).not.toBeInTheDocument(); + expect(screen.queryByText('This is the Toast!')).not.toBeInTheDocument(); }); it('should close toast', async () => { render(); expect(await screen.findByText('Content')).toBeInTheDocument(); - expect(screen.queryByText('This is the toast!')).not.toBeInTheDocument(); + expect(screen.queryByText('This is the Toast!')).not.toBeInTheDocument(); }); }); diff --git a/src/library-authoring/library-team/LibraryTeam.test.tsx b/src/library-authoring/library-team/LibraryTeam.test.tsx index 2ab5ec52ab..bdd424fc08 100644 --- a/src/library-authoring/library-team/LibraryTeam.test.tsx +++ b/src/library-authoring/library-team/LibraryTeam.test.tsx @@ -15,6 +15,7 @@ import { getLibraryTeamMemberApiUrl, } from '../data/api'; import { LibraryProvider } from '../common/context'; +import { ToastProvider } from '../../generic/toast-context'; import LibraryTeam from './LibraryTeam'; mockContentLibrary.applyMock(); @@ -28,9 +29,11 @@ describe('', () => { const { libraryId } = mockContentLibrary; const renderLibraryTeam = async () => { render( - - - , + + + + + , ); await waitFor(() => { @@ -176,6 +179,56 @@ describe('', () => { `{"library_id":"${libraryId}","email":"another@user.tld","access_level":"read"}`, ); }); + + expect(await screen.findByText('Team Member added')).toBeInTheDocument(); + }); + + it('shows error when user do not exist', async () => { + const url = getLibraryTeamApiUrl(libraryId); + const axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + axiosMock.onPost(url).reply(400, { email: 'Error' }); + + await renderLibraryTeam(); + + const addButton = screen.getByRole('button', { name: 'New team member' }); + userEvent.click(addButton); + const emailInput = screen.getByRole('textbox', { name: 'User\'s email address' }); + userEvent.click(emailInput); + userEvent.type(emailInput, 'another@user.tld'); + + const saveButton = screen.getByRole('button', { name: /add member/i }); + userEvent.click(saveButton); + + await waitFor(() => { + expect(axiosMock.history.post.length).toEqual(1); + }); + + expect(await screen.findByText( + 'Error adding Team Member. Please verify that the email is correct and belongs to a registered user.', + )).toBeInTheDocument(); + }); + + it('shows error', async () => { + const url = getLibraryTeamApiUrl(libraryId); + const axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + axiosMock.onPost(url).reply(400, {}); + + await renderLibraryTeam(); + + const addButton = screen.getByRole('button', { name: 'New team member' }); + userEvent.click(addButton); + const emailInput = screen.getByRole('textbox', { name: 'User\'s email address' }); + userEvent.click(emailInput); + userEvent.type(emailInput, 'another@user.tld'); + + const saveButton = screen.getByRole('button', { name: /add member/i }); + userEvent.click(saveButton); + + await waitFor(() => { + expect(axiosMock.history.post.length).toEqual(1); + }); + + expect(await screen.findByText('Error adding Team Member')).toBeInTheDocument(); }); it('allows library team member roles to be changed', async () => { diff --git a/src/library-authoring/library-team/LibraryTeam.tsx b/src/library-authoring/library-team/LibraryTeam.tsx index b41be5acf2..8bf4d2e31c 100644 --- a/src/library-authoring/library-team/LibraryTeam.tsx +++ b/src/library-authoring/library-team/LibraryTeam.tsx @@ -65,8 +65,13 @@ const LibraryTeam: React.FC> = () => { accessLevel: LibraryRole.Reader.toString() as LibraryAccessLevel, }).then(() => { showToast(intl.formatMessage(messages.addMemberSuccess)); - }).catch(() => { - showToast(intl.formatMessage(messages.addMemberError)); + }).catch((addMemberError) => { + const errorData = typeof addMemberError === 'object' ? addMemberError.response?.data : undefined; + if (errorData && 'email' in errorData) { + showToast(intl.formatMessage(messages.addMemberEmailError)); + } else { + showToast(intl.formatMessage(messages.addMemberError)); + } }); closeAddLibraryTeamMember(); }, diff --git a/src/library-authoring/library-team/messages.ts b/src/library-authoring/library-team/messages.ts index 6bf6a8c363..d56d606153 100644 --- a/src/library-authoring/library-team/messages.ts +++ b/src/library-authoring/library-team/messages.ts @@ -124,6 +124,11 @@ const messages = defineMessages({ defaultMessage: 'Error adding Team Member', description: 'Message shown when an error occurs while adding a Library Team member', }, + addMemberEmailError: { + id: 'course-authoring.library-authoring.library-team.add-member-email-error', + defaultMessage: 'Error adding Team Member. Please verify that the email is correct and belongs to a registered user.', + description: 'Message shown when an error occurs with email while adding a Library Team member.', + }, deleteMemberSuccess: { id: 'course-authoring.library-authoring.library-team.delete-member-success', defaultMessage: 'Team Member deleted',