@@ -139,7 +137,7 @@ const CourseTeam = () => {
isOpen={isInfoModalOpen}
close={closeInfoModal}
currentEmail={currentEmail}
- errorMessage={errorMessage}
+ errorMessage={errorMessage ?? ''}
courseName={courseName}
modalType={modalType}
onDeleteSubmit={handleDeleteUserSubmit}
@@ -161,9 +159,9 @@ const CourseTeam = () => {
{}}
/>
>
diff --git a/src/course-team/add-user-form/AddUserForm.test.jsx b/src/course-team/add-user-form/AddUserForm.test.jsx
deleted file mode 100644
index d3716b14c..000000000
--- a/src/course-team/add-user-form/AddUserForm.test.jsx
+++ /dev/null
@@ -1,128 +0,0 @@
-import React from 'react';
-import {
- render,
- fireEvent,
- act,
- waitFor,
-} from '@testing-library/react';
-import { IntlProvider } from '@edx/frontend-platform/i18n';
-import { AppProvider } from '@edx/frontend-platform/react';
-import { initializeMockApp } from '@edx/frontend-platform';
-import MockAdapter from 'axios-mock-adapter';
-import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
-
-import { EXAMPLE_USER_EMAIL } from '../constants';
-import initializeStore from '../../store';
-import { USER_ROLES } from '../../constants';
-import { updateCourseTeamUserApiUrl } from '../data/api';
-import { createCourseTeamQuery } from '../data/thunk';
-import { executeThunk } from '../../utils';
-import AddUserForm from './AddUserForm';
-import messages from './messages';
-
-let axiosMock;
-let store;
-const mockPathname = '/foo-bar';
-const courseId = '123';
-
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useLocation: () => ({
- pathname: mockPathname,
- }),
-}));
-
-const onSubmitMock = jest.fn();
-const onCancelMock = jest.fn();
-
-const RootWrapper = () => (
-
-
-
-
-
-);
-
-describe('
', () => {
- beforeEach(() => {
- initializeMockApp({
- authenticatedUser: {
- userId: 3,
- username: 'abc123',
- administrator: true,
- roles: [],
- },
- });
-
- store = initializeStore();
- axiosMock = new MockAdapter(getAuthenticatedHttpClient());
- });
-
- it('render AddUserForm component correctly', () => {
- const { getByText, getByPlaceholderText } = render(
);
-
- expect(getByText(messages.formTitle.defaultMessage)).toBeInTheDocument();
- expect(getByText(messages.formLabel.defaultMessage)).toBeInTheDocument();
- expect(getByPlaceholderText(messages.formPlaceholder.defaultMessage
- .replace('{email}', EXAMPLE_USER_EMAIL))).toBeInTheDocument();
- expect(getByText(messages.cancelButton.defaultMessage)).toBeInTheDocument();
- expect(getByText(messages.addUserButton.defaultMessage)).toBeInTheDocument();
- });
-
- it('calls onSubmit when the "Add User" button is clicked with a valid email', async () => {
- const { getByPlaceholderText, getByRole } = render(
);
-
- const emailInput = getByPlaceholderText(messages.formPlaceholder.defaultMessage.replace('{email}', EXAMPLE_USER_EMAIL));
- const addUserButton = getByRole('button', { name: messages.addUserButton.defaultMessage });
-
- fireEvent.change(emailInput, { target: { value: EXAMPLE_USER_EMAIL } });
-
- await act(async () => {
- fireEvent.click(addUserButton);
- });
-
- await waitFor(() => {
- expect(onSubmitMock).toHaveBeenCalledTimes(1);
- expect(onSubmitMock).toHaveBeenCalledWith(
- { email: EXAMPLE_USER_EMAIL },
- expect.objectContaining({ submitForm: expect.any(Function) }),
- );
- });
-
- axiosMock
- .onPost(updateCourseTeamUserApiUrl(courseId, EXAMPLE_USER_EMAIL), { role: USER_ROLES.staff })
- .reply(200, { role: USER_ROLES.staff });
-
- await executeThunk(createCourseTeamQuery(courseId, EXAMPLE_USER_EMAIL), store.dispatch);
- });
-
- it('calls onCancel when the "Cancel" button is clicked', () => {
- const { getByText } = render(
);
-
- const cancelButton = getByText(messages.cancelButton.defaultMessage);
- fireEvent.click(cancelButton);
- expect(onCancelMock).toHaveBeenCalledTimes(1);
- });
-
- it('"Add User" button is disabled when the email input field is empty', () => {
- const { getByText } = render(
);
-
- const addUserButton = getByText(messages.addUserButton.defaultMessage);
- expect(addUserButton).toBeDisabled();
- });
-
- it('"Add User" button is not disabled when the email input field is not empty', () => {
- const { getByPlaceholderText, getByText } = render(
);
-
- const emailInput = getByPlaceholderText(
- messages.formPlaceholder.defaultMessage.replace('{email}', EXAMPLE_USER_EMAIL),
- );
- const addUserButton = getByText(messages.addUserButton.defaultMessage);
-
- fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
- expect(addUserButton).not.toBeDisabled();
- });
-});
diff --git a/src/course-team/add-user-form/AddUserForm.test.tsx b/src/course-team/add-user-form/AddUserForm.test.tsx
new file mode 100644
index 000000000..57207c4d2
--- /dev/null
+++ b/src/course-team/add-user-form/AddUserForm.test.tsx
@@ -0,0 +1,96 @@
+import userEvent from '@testing-library/user-event';
+import {
+ render,
+ screen,
+ fireEvent,
+ waitFor,
+ initializeMocks,
+} from '@src/testUtils';
+
+import { EXAMPLE_USER_EMAIL } from '../constants';
+import AddUserForm from './AddUserForm';
+import messages from './messages';
+
+const mockPathname = '/foo-bar';
+
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useLocation: () => ({
+ pathname: mockPathname,
+ }),
+}));
+
+const onSubmitMock = jest.fn();
+const onCancelMock = jest.fn();
+
+const renderComponent = () => render(
+
,
+);
+
+describe('
', () => {
+ beforeEach(() => {
+ initializeMocks();
+ });
+
+ it('render AddUserForm component correctly', () => {
+ renderComponent();
+
+ expect(screen.getByText(messages.formTitle.defaultMessage)).toBeInTheDocument();
+ expect(screen.getByText(messages.formLabel.defaultMessage)).toBeInTheDocument();
+ expect(screen.getByPlaceholderText(messages.formPlaceholder.defaultMessage
+ .replace('{email}', EXAMPLE_USER_EMAIL))).toBeInTheDocument();
+ expect(screen.getByText(messages.cancelButton.defaultMessage)).toBeInTheDocument();
+ expect(screen.getByText(messages.addUserButton.defaultMessage)).toBeInTheDocument();
+ });
+
+ it('calls onSubmit when the "Add User" button is clicked with a valid email', async () => {
+ const user = userEvent.setup();
+ renderComponent();
+
+ const emailInput = screen.getByPlaceholderText(messages.formPlaceholder.defaultMessage.replace('{email}', EXAMPLE_USER_EMAIL));
+ const addUserButton = screen.getByRole('button', { name: messages.addUserButton.defaultMessage });
+
+ fireEvent.change(emailInput, { target: { value: EXAMPLE_USER_EMAIL } });
+
+ await user.click(addUserButton);
+
+ await waitFor(() => {
+ expect(onSubmitMock).toHaveBeenCalledTimes(1);
+ });
+ expect(onSubmitMock).toHaveBeenCalledWith(
+ { email: EXAMPLE_USER_EMAIL },
+ expect.objectContaining({ submitForm: expect.any(Function) }),
+ );
+ });
+
+ it('calls onCancel when the "Cancel" button is clicked', async () => {
+ const user = userEvent.setup();
+ renderComponent();
+
+ const cancelButton = screen.getByText(messages.cancelButton.defaultMessage);
+ await user.click(cancelButton);
+ expect(onCancelMock).toHaveBeenCalledTimes(1);
+ });
+
+ it('"Add User" button is disabled when the email input field is empty', () => {
+ renderComponent();
+
+ const addUserButton = screen.getByText(messages.addUserButton.defaultMessage);
+ expect(addUserButton).toBeDisabled();
+ });
+
+ it('"Add User" button is not disabled when the email input field is not empty', () => {
+ renderComponent();
+
+ const emailInput = screen.getByPlaceholderText(
+ messages.formPlaceholder.defaultMessage.replace('{email}', EXAMPLE_USER_EMAIL),
+ );
+ const addUserButton = screen.getByText(messages.addUserButton.defaultMessage);
+
+ fireEvent.change(emailInput, { target: { value: 'user@example.com' } });
+ expect(addUserButton).not.toBeDisabled();
+ });
+});
diff --git a/src/course-team/constants.ts b/src/course-team/constants.ts
index 542ea5534..42ab37368 100644
--- a/src/course-team/constants.ts
+++ b/src/course-team/constants.ts
@@ -4,6 +4,8 @@ export const MODAL_TYPES = {
warning: 'warning',
} as const;
+export type ModalType = typeof MODAL_TYPES[keyof typeof MODAL_TYPES];
+
export const BADGE_STATES = {
admin: 'primary-700',
staff: 'gray-500',
diff --git a/src/course-team/data/api.js b/src/course-team/data/api.js
deleted file mode 100644
index 321671600..000000000
--- a/src/course-team/data/api.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import { camelCaseObject, getConfig } from '@edx/frontend-platform';
-import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
-
-import { USER_ROLES } from '../../constants';
-
-const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
-export const getCourseTeamApiUrl = (courseId) => `${getApiBaseUrl()}/api/contentstore/v1/course_team/${courseId}`;
-export const updateCourseTeamUserApiUrl = (courseId, email) => `${getApiBaseUrl()}/course_team/${courseId}/${email}`;
-
-/**
- * Get course team.
- * @param {string} courseId
- * @returns {Promise