diff --git a/src/components/bulk-email-tool/BulkEmailTool.jsx b/src/components/bulk-email-tool/BulkEmailTool.jsx index 481623f..b908f65 100644 --- a/src/components/bulk-email-tool/BulkEmailTool.jsx +++ b/src/components/bulk-email-tool/BulkEmailTool.jsx @@ -1,19 +1,18 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useRef } from 'react'; import classnames from 'classnames'; import { useParams } from 'react-router-dom'; -import { Spinner } from '@edx/paragon'; + import { ErrorPage } from '@edx/frontend-platform/react'; import BulkEmailTaskManager from './bulk-email-task-manager/BulkEmailTaskManager'; -import Navigationtabs from '../navigation-tabs/NavigationTabs'; -import { getCohorts, getCourseHomeCourseMetadata } from './data/api'; +import NavigationTabs from '../navigation-tabs/NavigationTabs'; import useMobileResponsive from '../../utils/useMobileResponsive'; import BulkEmailForm from './bulk-email-form'; +import { CourseMetadataContext } from '../page-container/PageContainer'; export default function BulkEmailTool() { const { courseId } = useParams(); - const [courseMetadata, setCourseMetadata] = useState(); const isMobile = useMobileResponsive(); const textEditorRef = useRef(); @@ -23,58 +22,23 @@ export default function BulkEmailTool() { } }; - useEffect(() => { - async function fetchTabData() { - let metadataResponse; - let cohortsResponse; - try { - metadataResponse = await getCourseHomeCourseMetadata(courseId); - cohortsResponse = await getCohorts(courseId); - } catch (e) { - setCourseMetadata({ - isStaff: false, - tabs: [], - cohorts: [], - }); - return; - } - const { tabs, is_staff: isStaff } = metadataResponse; - const { cohorts } = cohortsResponse; - setCourseMetadata({ - isStaff, - tabs: [...tabs], - cohorts: cohorts.map(({ name }) => name), - }); - } - fetchTabData(); - }, []); - - if (courseMetadata) { - return courseMetadata.isStaff ? ( -
- -
-
- -
-
- + return ( + + {(courseMetadata) => (courseMetadata.isStaff ? ( +
+ +
+
+ +
+
+ +
-
- ) : ( - - ); - } - return ( -
- -
+ ) : ( + + ))} + ); } diff --git a/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx b/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx index 79a9451..0aa920b 100644 --- a/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx +++ b/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx @@ -115,6 +115,13 @@ export default function BulkEmailForm(props) { }} />
+

+ +

({ getInstructorTasks: jest.fn(() => ({ tasks: {} })), getEmailTaskHistory: jest.fn(() => ({ tasks: {} })), })); -jest.mock('../data/api', () => ({ - __esModule: true, - getCourseHomeCourseMetadata: jest.fn(() => {}), - getCohorts: jest.fn(() => {}), -})); jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useParams: jest.fn(() => ({ @@ -29,20 +24,59 @@ jest.mock('react-router-dom', () => ({ describe('BulkEmailTool', () => { beforeEach(() => jest.resetModules()); afterEach(cleanup); - test('BulkEmailTool renders properly when given course metadata', async () => { - const courseMetadata = Factory.build('courseMetadata'); - const cohorts = { cohorts: [Factory.build('cohort'), Factory.build('cohort')] }; - getCourseHomeCourseMetadata.mockImplementation(() => courseMetadata); - getCohorts.mockImplementation(() => cohorts); - render(); + + /** + * Utility function to munge course data in the form the components expect. + * + */ + function buildCourseMetadata(cohortData, courseData) { + const { + org, number, title, tabs, is_staff: isStaff, + } = courseData; + const { cohorts } = cohortData; + + return { + org, + number, + title, + isStaff, + tabs: [...tabs], + cohorts: cohorts.map(({ name }) => name), + }; + } + + /** + * Function that wraps component under test in a context provider. This allows us to make the data needed for testing + * availble to the component under test. + */ + function renderBulkEmailTool(courseMetadata) { + return render( + + + , + ); + } + + test('BulkEmailTool renders properly when given course metadata through context', async () => { + const cohorts = { cohorts: [] }; + const courseInfo = Factory.build('courseMetadata'); + const courseMetadata = buildCourseMetadata(cohorts, courseInfo); + renderBulkEmailTool(courseMetadata); + // verify all tab data expected is displayed within our component expect(await screen.findByText('Course')).toBeTruthy(); + expect(await screen.findByText('Discussion')).toBeTruthy(); + expect(await screen.findByText('Wiki')).toBeTruthy(); + expect(await screen.findByText('Progress')).toBeTruthy(); + expect(await screen.findByText('Instructor')).toBeTruthy(); + expect(await screen.findByText('Dates')).toBeTruthy(); }); + test('BulkEmailTool renders error page on no staff user', async () => { - const courseMetadata = Factory.build('courseMetadata', { is_staff: false }); - const cohorts = { cohorts: [Factory.build('cohort'), Factory.build('cohort')] }; - getCourseHomeCourseMetadata.mockImplementation(() => courseMetadata); - getCohorts.mockImplementation(() => cohorts); - render(); + const cohorts = { cohorts: [] }; + const courseInfo = Factory.build('courseMetadata', { is_staff: false }); + const courseMetadata = buildCourseMetadata(cohorts, courseInfo); + renderBulkEmailTool(courseMetadata); + // verify error page is displayed for user without staff permissions expect( await screen.findByText('An unexpected error occurred. Please click the button below to refresh the page.'), ).toBeTruthy(); diff --git a/src/components/page-container/PageContainer.jsx b/src/components/page-container/PageContainer.jsx new file mode 100644 index 0000000..bd471ae --- /dev/null +++ b/src/components/page-container/PageContainer.jsx @@ -0,0 +1,87 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { useParams } from 'react-router-dom'; + +import { LearningHeader as Header } from '@edx/frontend-component-header'; +import Footer from '@edx/frontend-component-footer'; +import { Spinner } from '@edx/paragon'; + +import { getCohorts, getCourseHomeCourseMetadata } from './data/api'; + +export const CourseMetadataContext = React.createContext(); + +export default function PageContainer(props) { + const { children } = props; + const { courseId } = useParams(); + + const [courseMetadata, setCourseMetadata] = useState(); + + useEffect(() => { + async function fetchCourseMetadata() { + let metadataResponse; + let cohortsResponse; + + try { + metadataResponse = await getCourseHomeCourseMetadata(courseId); + cohortsResponse = await getCohorts(courseId); + } catch (e) { + setCourseMetadata({ + org: '', + number: '', + title: '', + isStaff: false, + tabs: [], + cohorts: [], + }); + return; + } + + const { + org, number, title, tabs, is_staff: isStaff, + } = metadataResponse; + const { cohorts } = cohortsResponse; + + setCourseMetadata({ + org, + number, + title, + isStaff, + tabs: [...tabs], + cohorts: cohorts.map(({ name }) => name), + }); + } + fetchCourseMetadata(); + }, []); + + if (courseMetadata) { + return ( + + <> +
+ {children} +