diff --git a/src/features/Classes/EnrollStudent/__test__/index.test.jsx b/src/features/Classes/EnrollStudent/__test__/index.test.jsx index bca7cfc7..4c42cb31 100644 --- a/src/features/Classes/EnrollStudent/__test__/index.test.jsx +++ b/src/features/Classes/EnrollStudent/__test__/index.test.jsx @@ -5,6 +5,8 @@ import '@testing-library/jest-dom/extend-expect'; import EnrollStudent from 'features/Classes/EnrollStudent'; +import * as api from 'features/Students/data/api'; + jest.mock('react-router-dom', () => ({ useParams: jest.fn(() => ({ courseName: 'Demo course', className: 'demo class' })), useLocation: jest.fn().mockReturnValue({ search: '?classId=demo class' }), @@ -39,6 +41,14 @@ describe('EnrollStudent', () => { { preloadedState: {} }, ); + const handleEnrollmentsMock = jest.spyOn(api, 'handleEnrollments').mockResolvedValue({ + data: { + results: [{ + tags: 'success', + }], + }, + }); + const emailInput = getByPlaceholderText('Enter email of the student to enroll'); fireEvent.change(emailInput, { target: { value: 'test@example.com' } }); @@ -48,5 +58,37 @@ describe('EnrollStudent', () => { await waitFor(() => { expect(getByText('Email invite has been sent successfully')).toBeInTheDocument(); }); + + expect(handleEnrollmentsMock).toHaveBeenCalledTimes(1); + handleEnrollmentsMock.mockRestore(); + }); + + test('Should handle form submission and show error toast', async () => { + const onCloseMock = jest.fn(); + + const handleEnrollmentsMock = jest.spyOn(api, 'handleEnrollments').mockResolvedValue({ + data: { + results: [{ tags: 'error', message: 'Enrollment limit reached' }], + }, + }); + + const { getByPlaceholderText, getByText } = renderWithProviders( + , + { preloadedState: {} }, + ); + + const emailInput = getByPlaceholderText('Enter email of the student to enroll'); + fireEvent.change(emailInput, { target: { value: 'test@example.com' } }); + + const submitButton = getByText('Send invite'); + fireEvent.click(submitButton); + + await waitFor(() => { + expect(getByText('Enrollment limit reached')).toBeInTheDocument(); + }); + + expect(handleEnrollmentsMock).toHaveBeenCalledTimes(1); + + handleEnrollmentsMock.mockRestore(); }); }); diff --git a/src/features/Classes/EnrollStudent/index.jsx b/src/features/Classes/EnrollStudent/index.jsx index 36bd99c7..468321d7 100644 --- a/src/features/Classes/EnrollStudent/index.jsx +++ b/src/features/Classes/EnrollStudent/index.jsx @@ -21,14 +21,13 @@ import { initialPage } from 'features/constants'; import 'features/Classes/EnrollStudent/index.scss'; -const successToastMessage = 'Email invite has been sent successfully'; - const EnrollStudent = ({ isOpen, onClose, queryClassId }) => { const dispatch = useDispatch(); const { courseName, className } = useParams(); const [showToast, setShowToast] = useState(false); const [isLoading, setLoading] = useState(false); + const [toastMessage, setToastMessage] = useState(''); const institution = useSelector((state) => state.main.selectedInstitution); const courseNameDecoded = decodeURIComponent(courseName); const classNameDecoded = decodeURIComponent(className); @@ -47,7 +46,21 @@ const EnrollStudent = ({ isOpen, onClose, queryClassId }) => { try { setLoading(true); - await handleEnrollments(formData, queryClassId); + const response = await handleEnrollments(formData, queryClassId); + + /** + * This is because the service that checks the enrollment status is a different + * endpoint, and that endpoint always returns a status 200, so the error cannot be + * caught with a .catch. + */ + if (response?.data?.results[0]?.tags === 'error') { + setToastMessage(response?.data?.results[0]?.message); + setShowToast(true); + + return onClose(); + } + + setToastMessage('Email invite has been sent successfully'); const params = { course_name: courseNameDecoded, @@ -59,10 +72,11 @@ const EnrollStudent = ({ isOpen, onClose, queryClassId }) => { // Get the classes info updated with the new number of students enrolled. dispatch(fetchAllClassesData(institution.id, courseNameDecoded)); + setShowToast(true); - onClose(); + return onClose(); } catch (error) { - logError(error); + return logError(error); } finally { setLoading(false); } @@ -71,7 +85,7 @@ const EnrollStudent = ({ isOpen, onClose, queryClassId }) => { return ( <> setShowToast(false)} show={showToast}> - {successToastMessage} + {toastMessage} { describe('handleEnrollments', () => { test('should call getAuthenticatedHttpClient with the correct parameters', () => { const httpClientMock = { - post: jest.fn(), + post: jest.fn().mockResolvedValue({}), + get: jest.fn().mockResolvedValue({}), }; const courseId = 'course123'; const data = new FormData(); diff --git a/src/features/Students/data/api.js b/src/features/Students/data/api.js index a425a1cc..c03cd071 100644 --- a/src/features/Students/data/api.js +++ b/src/features/Students/data/api.js @@ -21,7 +21,9 @@ function handleEnrollments(data, courseId) { return getAuthenticatedHttpClient().post( `${INSTRUCTOR_API_URL.replace(courseIdSearchPattern, courseId)}/students_update_enrollment`, data, - ); + ).then(() => getAuthenticatedHttpClient().get( + `${getConfig().LMS_BASE_URL}/pearson_course_operation/api/messages/get-messages/`, + )); } function getStudentsMetrics(institutionId, days) {