From be44f04a245f874120dbaef4fefff1d908acdbe3 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Tue, 19 Jul 2022 15:08:51 -0400 Subject: [PATCH] chore: course banner logic and tests --- .../components/Banners/CourseBanner.jsx | 29 +++--- .../components/Banners/CourseBanner.test.jsx | 89 +++++++++++++++++++ .../__snapshots__/CourseBanner.test.jsx.snap | 33 +++++++ .../CourseCard/components/Banners/hooks.js | 20 +++++ .../CourseCard/components/Banners/messages.js | 31 +++++++ 5 files changed, 186 insertions(+), 16 deletions(-) create mode 100644 src/containers/CourseCard/components/Banners/CourseBanner.test.jsx create mode 100644 src/containers/CourseCard/components/Banners/__snapshots__/CourseBanner.test.jsx.snap create mode 100644 src/containers/CourseCard/components/Banners/hooks.js create mode 100644 src/containers/CourseCard/components/Banners/messages.js diff --git a/src/containers/CourseCard/components/Banners/CourseBanner.jsx b/src/containers/CourseCard/components/Banners/CourseBanner.jsx index b713a5c..8e54804 100644 --- a/src/containers/CourseCard/components/Banners/CourseBanner.jsx +++ b/src/containers/CourseCard/components/Banners/CourseBanner.jsx @@ -3,21 +3,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Hyperlink } from '@edx/paragon'; -import { useCardValues } from 'hooks'; -import { selectors } from 'data/redux'; - import Banner from 'components/Banner'; - -const { cardData } = selectors; +import { useCourseBannerData } from './hooks'; +import messages from './messages'; export const CourseBanner = ({ courseNumber }) => { - const courseData = useCardValues(courseNumber, { - isVerified: cardData.isVerified, - isCourseRunActive: cardData.isCourseRunActive, - canUpgrade: cardData.canUpgrade, - isAuditAccessExpired: cardData.isAuditAccessExpired, - courseWebsite: cardData.courseWebsite, - }); + const { courseData, formatMessage } = useCourseBannerData({ courseNumber }); if (courseData.isVerified) { return null; } @@ -25,22 +16,28 @@ export const CourseBanner = ({ courseNumber }) => { if (courseData.canUpgrade) { return ( - Your audit access to this course has expired. Upgrade now to access your course again. + {formatMessage(messages.auditAccessExpired)} + {' '} + {formatMessage(messages.upgradeToAccess)} ); } return ( - Your audit access to this course has expired. Find another course + {formatMessage(messages.auditAccessExpired)} + {' '} + {formatMessage(messages.findAnotherCourse)} ); } if (courseData.isCourseRunActive && !courseData.canUpgrade) { return ( - Your upgrade deadline for this course has passed. To upgrade, enroll in a session that is farther in the future. + {formatMessage(messages.upgradeDeadlinePassed)} {' '} - Explore course details. + + {formatMessage(messages.exploreCourseDetails)} + ); } diff --git a/src/containers/CourseCard/components/Banners/CourseBanner.test.jsx b/src/containers/CourseCard/components/Banners/CourseBanner.test.jsx new file mode 100644 index 0000000..f35e7da --- /dev/null +++ b/src/containers/CourseCard/components/Banners/CourseBanner.test.jsx @@ -0,0 +1,89 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { Hyperlink } from '@edx/paragon'; + +import { formatMessage } from 'testUtils'; +import { CourseBanner } from './CourseBanner'; + +import * as hooks from './hooks'; +import messages from './messages'; + +jest.mock('components/Banner', () => 'Banner'); + +jest.mock('./hooks', () => ({ + useCourseBannerData: jest.fn(), +})); + +const courseNumber = 'my-test-course-number'; + +const courseData = { + isVerified: false, + isCourseRunActive: false, + canUpgrade: false, + isAuditAccessExpired: false, + courseWebsite: 'test-course-website', +}; + +let el; + +const render = (overrides) => { + hooks.useCourseBannerData.mockReturnValueOnce({ + courseData: { + ...courseData, + ...overrides, + }, + formatMessage, + }); + el = shallow(); +}; + +describe('CourseBanner', () => { + test('no display if learner is verified', () => { + render({ isVerified: true }); + expect(el.isEmptyRender()).toEqual(true); + }); + describe('audit access expired, can upgrade', () => { + beforeEach(() => { + render({ isAuditAccessExpired: true, canUpgrade: true }); + }); + test('snapshot: (auditAccessExpired, upgradeToAccess)', () => { + expect(el).toMatchSnapshot(); + }); + test('messages: (auditAccessExpired, upgradeToAccess)', () => { + expect(el.text()).toContain(messages.auditAccessExpired.defaultMessage); + expect(el.text()).toContain(messages.upgradeToAccess.defaultMessage); + }); + }); + describe('audit access expired, cannot upgrade', () => { + beforeEach(() => { + render({ isAuditAccessExpired: true }); + }); + test('snapshot: (auditAccessExpired, findAnotherCourse hyperlink)', () => { + expect(el).toMatchSnapshot(); + }); + test('messages: (auditAccessExpired, upgradeToAccess)', () => { + expect(el.text()).toContain(messages.auditAccessExpired.defaultMessage); + expect(el.find(Hyperlink).text()).toEqual(messages.findAnotherCourse.defaultMessage); + }); + }); + describe('course run active and cannot upgrade', () => { + beforeEach(() => { + render({ isCourseRunActive: true }); + }); + test('snapshot: (upgradseDeadlinePassed, exploreCourseDetails hyperlink)', () => { + expect(el).toMatchSnapshot(); + }); + test('messages: (upgradseDeadlinePassed, exploreCourseDetails hyperlink)', () => { + expect(el.text()).toContain(messages.upgradeDeadlinePassed.defaultMessage); + const link = el.find(Hyperlink); + expect(link.text()).toEqual(messages.exploreCourseDetails.defaultMessage); + expect(link.props().destination).toEqual(courseData.courseWebsite); + }); + }); + test('no display if audit access not expired and (course is not active or can upgrade)', () => { + render(); + expect(el.isEmptyRender()).toEqual(true); + render({ isCourseRunActive: true, canUpgrade: true }); + expect(el.isEmptyRender()).toEqual(true); + }); +}); diff --git a/src/containers/CourseCard/components/Banners/__snapshots__/CourseBanner.test.jsx.snap b/src/containers/CourseCard/components/Banners/__snapshots__/CourseBanner.test.jsx.snap new file mode 100644 index 0000000..5c3160a --- /dev/null +++ b/src/containers/CourseCard/components/Banners/__snapshots__/CourseBanner.test.jsx.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CourseBanner audit access expired, can upgrade snapshot: (auditAccessExpired, upgradeToAccess) 1`] = ` + + Your audit access to this course has expired. + + Upgrade now to access your course again. + +`; + +exports[`CourseBanner audit access expired, cannot upgrade snapshot: (auditAccessExpired, findAnotherCourse hyperlink) 1`] = ` + + Your audit access to this course has expired. + + + Find another course + + +`; + +exports[`CourseBanner course run active and cannot upgrade snapshot: (upgradseDeadlinePassed, exploreCourseDetails hyperlink) 1`] = ` + + Your upgrade deadline for this course has passed. To upgrade, enroll in a session that is farther in the future. + + + Explore course details. + + +`; diff --git a/src/containers/CourseCard/components/Banners/hooks.js b/src/containers/CourseCard/components/Banners/hooks.js new file mode 100644 index 0000000..413bc76 --- /dev/null +++ b/src/containers/CourseCard/components/Banners/hooks.js @@ -0,0 +1,20 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; +import { useCardValues } from 'hooks'; +import { selectors } from 'data/redux'; + +const { cardData } = selectors; + +export const useCourseBannerData = ({ courseNumber }) => ({ + courseData: useCardValues(courseNumber, { + isVerified: cardData.isVerified, + isCourseRunActive: cardData.isCourseRunActive, + canUpgrade: cardData.canUpgrade, + isAuditAccessExpired: cardData.isAuditAccessExpired, + courseWebsite: cardData.courseWebsite, + }), + formatMessage: useIntl().formatMessage, +}); + +export default { + useCourseBannerData, +}; diff --git a/src/containers/CourseCard/components/Banners/messages.js b/src/containers/CourseCard/components/Banners/messages.js new file mode 100644 index 0000000..ac7a1d3 --- /dev/null +++ b/src/containers/CourseCard/components/Banners/messages.js @@ -0,0 +1,31 @@ +import { StrictDict } from 'utils'; + +export const messages = StrictDict({ + auditAccessExpired: { + id: 'learner-dash.courseCard.banners.auditAccessExpired', + description: 'Audit access expiration banner message', + defaultMessage: 'Your audit access to this course has expired.', + }, + upgradeToAccess: { + id: 'learner-dash.courseCard.banners.upgradeToAccess', + description: 'Upgrade prompt for audit-expired learners that can still upgrade', + defaultMessage: 'Upgrade now to access your course again.', + }, + findAnotherCourse: { + id: 'learner-dash.courseCard.banners.findAnotherCourse', + description: 'Action prompt taking learners to course exploration', + defaultMessage: 'Find another course', + }, + upgradeDeadlinePassed: { + id: 'learner-dash.courseCard.banners.upgradeDeadlinePassed', + description: 'Audit upgrade deadline passed banner message', + defaultMessage: 'Your upgrade deadline for this course has passed. To upgrade, enroll in a session that is farther in the future.', + }, + exploreCourseDetails: { + id: 'learner-dash.courseCard.banners.exploreCourseDetails', + description: 'Action prompt taking learners to course details page', + defaultMessage: 'Explore course details.', + }, +}); + +export default messages;