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',