fix: update components for new api fields
This commit is contained in:
@@ -11,56 +11,67 @@ export const useCardActionData = ({ cardId }) => {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
canUpgrade,
|
||||
coursewareAccess,
|
||||
hasStarted,
|
||||
isAudit,
|
||||
isAuditAccessExpired,
|
||||
isVerified,
|
||||
} = appHooks.useCardEnrollmentData(cardId);
|
||||
const { isPending, isArchived } = appHooks.useCardCourseRunData(cardId);
|
||||
const { isArchived } = appHooks.useCardCourseRunData(cardId);
|
||||
const {
|
||||
isEntitlement,
|
||||
canViewCourse,
|
||||
isFulfilled,
|
||||
isExpired,
|
||||
canChange,
|
||||
hasSessions,
|
||||
isEntitlement,
|
||||
isExpired,
|
||||
isFulfilled,
|
||||
} = appHooks.useCardEntitlementData(cardId);
|
||||
const openSessionModal = appHooks.useUpdateSelectSessionModalCallback(dispatch, cardId);
|
||||
|
||||
const hasAccess = coursewareAccess.isStaff || !(
|
||||
coursewareAccess.hasUnmetPrereqs
|
||||
|| coursewareAccess.isTooEarly
|
||||
|| isArchived);
|
||||
|
||||
const selectSessionButton = {
|
||||
children: formatMessage(messages.selectSession),
|
||||
onClick: openSessionModal,
|
||||
disabled: !hasAccess || (!canChange || !hasSessions),
|
||||
};
|
||||
|
||||
const viewCourseButton = {
|
||||
children: formatMessage(messages.viewCourse),
|
||||
disabled: !hasAccess || (isEntitlement && isExpired),
|
||||
};
|
||||
|
||||
const beginCourseButton = {
|
||||
children: formatMessage(messages.beginCourse),
|
||||
disabled: !hasAccess,
|
||||
};
|
||||
|
||||
const resumeButton = {
|
||||
children: formatMessage(messages.resume),
|
||||
disabled: isAudit && isAuditAccessExpired,
|
||||
};
|
||||
|
||||
const upgradeButton = {
|
||||
iconBefore: Locked,
|
||||
variant: 'outline-primary',
|
||||
children: formatMessage(messages.upgrade),
|
||||
disabled: !canUpgrade,
|
||||
};
|
||||
|
||||
let primary;
|
||||
let secondary = null;
|
||||
if (isEntitlement) {
|
||||
if (!isFulfilled) {
|
||||
primary = {
|
||||
children: formatMessage(messages.selectSession),
|
||||
disabled: !(canChange && hasSessions),
|
||||
onClick: openSessionModal,
|
||||
};
|
||||
} else {
|
||||
primary = {
|
||||
children: formatMessage(messages.viewCourse),
|
||||
disabled: !canViewCourse || isExpired,
|
||||
};
|
||||
}
|
||||
primary = isFulfilled ? selectSessionButton : viewCourseButton;
|
||||
} else if (!hasStarted) {
|
||||
primary = beginCourseButton;
|
||||
} else if (isArchived) {
|
||||
primary = viewCourseButton;
|
||||
} else {
|
||||
if (!isVerified) {
|
||||
secondary = {
|
||||
iconBefore: Locked,
|
||||
variant: 'outline-primary',
|
||||
disabled: !canUpgrade,
|
||||
children: formatMessage(messages.upgrade),
|
||||
};
|
||||
}
|
||||
if (isPending) {
|
||||
primary = { children: formatMessage(messages.beginCourse) };
|
||||
} else if (!isArchived) {
|
||||
primary = {
|
||||
children: formatMessage(messages.resume),
|
||||
disabled: isAudit && isAuditAccessExpired,
|
||||
};
|
||||
} else {
|
||||
primary = { children: formatMessage(messages.viewCourse) };
|
||||
}
|
||||
primary = resumeButton;
|
||||
}
|
||||
|
||||
const secondary = (isEntitlement || !isVerified) ? null : upgradeButton;
|
||||
return { primary, secondary };
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export const CertificateBanner = ({ cardId }) => {
|
||||
const { isPassing } = appHooks.useCardGradeData(cardId);
|
||||
const { minPassingGrade, progressUrl } = appHooks.useCardCourseRunData(cardId);
|
||||
const { supportEmail, billingEmail } = appHooks.usePlatformSettingsData();
|
||||
const { formatMessage } = useIntl();
|
||||
const { formatMessage, formatDate } = useIntl();
|
||||
|
||||
const emailLink = address => address && <MailtoLink to={address}>{address}</MailtoLink>;
|
||||
|
||||
@@ -76,7 +76,7 @@ export const CertificateBanner = ({ cardId }) => {
|
||||
<Banner>
|
||||
{formatMessage(
|
||||
messages.gradeAndCertReadyAfter,
|
||||
{ availableDate: certificate.availableDate },
|
||||
{ availableDate: formatDate(certificate.availableDate) },
|
||||
)}
|
||||
</Banner>
|
||||
);
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { Hyperlink } from '@edx/paragon';
|
||||
|
||||
import { hooks as appHooks } from 'data/redux';
|
||||
import { CourseBanner } from './CourseBanner';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
jest.mock('components/Banner', () => 'Banner');
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseData: jest.fn(),
|
||||
useCardCourseRunData: jest.fn(),
|
||||
useCardEnrollmentData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const cardId = 'my-test-course-number';
|
||||
|
||||
let el;
|
||||
|
||||
const enrollmentData = {
|
||||
isVerified: false,
|
||||
canUpgrade: false,
|
||||
isAuditAccessExpired: false,
|
||||
};
|
||||
const courseRunData = {
|
||||
isActive: false,
|
||||
};
|
||||
const courseData = {
|
||||
website: 'test-course-website',
|
||||
};
|
||||
|
||||
const render = (overrides = {}) => {
|
||||
const {
|
||||
course = {},
|
||||
courseRun = {},
|
||||
enrollment = {},
|
||||
} = overrides;
|
||||
appHooks.useCardCourseData.mockReturnValueOnce({
|
||||
...courseData,
|
||||
...course,
|
||||
});
|
||||
appHooks.useCardCourseRunData.mockReturnValueOnce({
|
||||
...courseRunData,
|
||||
...courseRun,
|
||||
});
|
||||
appHooks.useCardEnrollmentData.mockReturnValueOnce({
|
||||
...enrollmentData,
|
||||
...enrollment,
|
||||
});
|
||||
el = shallow(<CourseBanner cardId={cardId} />);
|
||||
};
|
||||
|
||||
describe('CourseBanner', () => {
|
||||
it('initializes data with course number from enrollment, course and course run data', () => {
|
||||
render();
|
||||
expect(appHooks.useCardCourseData).toHaveBeenCalledWith(cardId);
|
||||
expect(appHooks.useCardCourseRunData).toHaveBeenCalledWith(cardId);
|
||||
expect(appHooks.useCardEnrollmentData).toHaveBeenCalledWith(cardId);
|
||||
});
|
||||
test('no display if learner is verified', () => {
|
||||
render({ enrollment: { isVerified: true } });
|
||||
expect(el.isEmptyRender()).toEqual(true);
|
||||
});
|
||||
describe('audit access expired, can upgrade', () => {
|
||||
beforeEach(() => {
|
||||
render({ enrollment: { 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({ enrollment: { 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({ courseRun: { isActive: 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.website);
|
||||
});
|
||||
});
|
||||
test('no display if audit access not expired and (course is not active or can upgrade)', () => {
|
||||
render();
|
||||
expect(el.html()).toEqual('');
|
||||
render({ enrollment: { canUpgrade: true }, courseRun: { isActive: true } });
|
||||
expect(el.html()).toEqual('');
|
||||
});
|
||||
});
|
||||
@@ -17,7 +17,7 @@ export const CourseBanner = ({ cardId }) => {
|
||||
} = appHooks.useCardEnrollmentData(cardId);
|
||||
const courseRun = appHooks.useCardCourseRunData(cardId);
|
||||
const course = appHooks.useCardCourseData(cardId);
|
||||
const { formatMessage } = useIntl();
|
||||
const { formatMessage, formatDate } = useIntl();
|
||||
|
||||
const { hasUnmetPrerequisites, isStaff, isTooEarly } = coursewareAccess;
|
||||
|
||||
@@ -56,7 +56,7 @@ export const CourseBanner = ({ cardId }) => {
|
||||
{isTooEarly && (
|
||||
<Banner>
|
||||
{formatMessage(messages.courseHasNotStarted, {
|
||||
startDate: courseRun.startDate,
|
||||
startDate: formatDate(courseRun.startDate),
|
||||
})}
|
||||
</Banner>
|
||||
)}
|
||||
@@ -71,4 +71,4 @@ CourseBanner.propTypes = {
|
||||
cardId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CourseBanner;
|
||||
export default CourseBanner;
|
||||
@@ -1,39 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CourseBanner audit access expired, can upgrade snapshot: (auditAccessExpired, upgradeToAccess) 1`] = `
|
||||
<Fragment>
|
||||
<Banner>
|
||||
Your audit access to this course has expired.
|
||||
|
||||
Upgrade now to access your course again.
|
||||
</Banner>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CourseBanner audit access expired, cannot upgrade snapshot: (auditAccessExpired, findAnotherCourse hyperlink) 1`] = `
|
||||
<Fragment>
|
||||
<Banner>
|
||||
Your audit access to this course has expired.
|
||||
|
||||
<Hyperlink
|
||||
destination=""
|
||||
>
|
||||
Find another course
|
||||
</Hyperlink>
|
||||
</Banner>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CourseBanner course run active and cannot upgrade snapshot: (upgradseDeadlinePassed, exploreCourseDetails hyperlink) 1`] = `
|
||||
<Fragment>
|
||||
<Banner>
|
||||
Your upgrade deadline for this course has passed. To upgrade, enroll in a session that is farther in the future.
|
||||
|
||||
<Hyperlink
|
||||
destination="test-course-website"
|
||||
>
|
||||
Explore course details.
|
||||
</Hyperlink>
|
||||
</Banner>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
exports[`EntitlementBanner snapshot: expiration warning 1`] = `
|
||||
<Banner>
|
||||
<formatMessageFunction
|
||||
<format-message-function
|
||||
message={
|
||||
Object {
|
||||
"defaultMessage": "You must {selectSessionButton} by {changeDeadline} to access the course.",
|
||||
@@ -31,7 +31,7 @@ exports[`EntitlementBanner snapshot: no sessions available 1`] = `
|
||||
<Banner
|
||||
variant="warning"
|
||||
>
|
||||
<formatMessageFunction
|
||||
<format-message-function
|
||||
message={
|
||||
Object {
|
||||
"defaultMessage": "There are no sessions available at the moment. The course team will create new sessions soon. If no sessions appear, please contact {emailLink} for information.",
|
||||
|
||||
@@ -16,16 +16,16 @@ import CourseCardDetails from './CourseCardDetails';
|
||||
|
||||
export const CourseCardContent = ({ cardId, orientation }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { title, bannerUrl } = appHooks.useCardCourseData(cardId);
|
||||
const { courseName, bannerImgSrc } = appHooks.useCardCourseData(cardId);
|
||||
return (
|
||||
<>
|
||||
<Card.ImageCap
|
||||
src={bannerUrl}
|
||||
src={bannerImgSrc}
|
||||
srcAlt={formatMessage(messages.bannerAlt)}
|
||||
/>
|
||||
<Card.Body>
|
||||
<Card.Header
|
||||
title={<span data-testid="CourseCardTitle">{title}</span>}
|
||||
title={<span data-testid="CourseCardTitle">{courseName}</span>}
|
||||
actions={<CourseCardMenu cardId={cardId} />}
|
||||
/>
|
||||
<Card.Section className="pt-0">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { hooks as appHooks } from 'data/redux';
|
||||
|
||||
import * as module from './hooks';
|
||||
import * as hooks from './hooks';
|
||||
import messages from './messages';
|
||||
|
||||
export const useAccessMessage = ({ cardId }) => {
|
||||
@@ -9,7 +9,8 @@ export const useAccessMessage = ({ cardId }) => {
|
||||
const enrollment = appHooks.useCardEnrollmentData(cardId);
|
||||
const courseRun = appHooks.useCardCourseRunData(cardId);
|
||||
if (!courseRun.isStarted) {
|
||||
return formatMessage(messages.courseStarts, { startDate: courseRun.startDate });
|
||||
const startDate = formatDate(courseRun.startDate);
|
||||
return formatMessage(messages.courseStarts, { startDate });
|
||||
}
|
||||
if (enrollment.isEnrolled) {
|
||||
if (enrollment.isAudit) {
|
||||
@@ -45,7 +46,7 @@ export const useCardDetailsData = ({ dispatch, cardId }) => {
|
||||
|
||||
return {
|
||||
providerName: providerName || formatMessage(messages.unknownProviderName),
|
||||
accessMessage: module.useAccessMessage({ cardId }),
|
||||
accessMessage: hooks.useAccessMessage({ cardId }),
|
||||
isEntitlement,
|
||||
isFulfilled,
|
||||
canChange,
|
||||
|
||||
@@ -9,13 +9,13 @@ export const useIsCollapsed = () => {
|
||||
|
||||
export const useCardData = ({ cardId }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { title, bannerUrl } = appHooks.useCardCourseData(cardId);
|
||||
const { title, bannerImgSrc } = appHooks.useCardCourseData(cardId);
|
||||
const { isEnrolled } = appHooks.useCardEnrollmentData(cardId);
|
||||
|
||||
return {
|
||||
isEnrolled,
|
||||
title,
|
||||
bannerUrl,
|
||||
bannerImgSrc,
|
||||
formatMessage,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('CourseCard hooks', () => {
|
||||
describe('useCardData', () => {
|
||||
const courseData = {
|
||||
title: 'fake-title',
|
||||
bannerUrl: 'my-banner-url',
|
||||
bannerImgSrc: 'my-banner-url',
|
||||
};
|
||||
const runHook = ({ course = {} }) => {
|
||||
appHooks.useCardCourseData.mockReturnValueOnce({
|
||||
@@ -42,7 +42,7 @@ describe('CourseCard hooks', () => {
|
||||
it('passes course title and banner URL form course data', () => {
|
||||
expect(appHooks.useCardCourseData).toHaveBeenCalledWith(cardId);
|
||||
expect(out.title).toEqual(courseData.title);
|
||||
expect(out.bannerUrl).toEqual(courseData.bannerUrl);
|
||||
expect(out.bannerImgSrc).toEqual(courseData.bannerImgSrc);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,8 +17,6 @@ exports[`SuggestedCourses snapshot has 3 suggested courses 1`] = `
|
||||
key="Suggested course 1"
|
||||
>
|
||||
<Card.ImageCap
|
||||
logoAlt="Course institute logo"
|
||||
logoSrc="https://prod-discovery.edx-cdn.org/organization/certificate_logos/b9dc96da-b3fc-45a6-b6b7-b8e12eb79335-ac60112330e3.png"
|
||||
src="https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg"
|
||||
srcAlt="Course image banner"
|
||||
/>
|
||||
@@ -38,8 +36,6 @@ exports[`SuggestedCourses snapshot has 3 suggested courses 1`] = `
|
||||
key="Suggested course 2"
|
||||
>
|
||||
<Card.ImageCap
|
||||
logoAlt="Course institute logo"
|
||||
logoSrc="https://prod-discovery.edx-cdn.org/organization/certificate_logos/b9dc96da-b3fc-45a6-b6b7-b8e12eb79335-ac60112330e3.png"
|
||||
src="https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg"
|
||||
srcAlt="Course image banner"
|
||||
/>
|
||||
@@ -59,8 +55,6 @@ exports[`SuggestedCourses snapshot has 3 suggested courses 1`] = `
|
||||
key="Suggested course 3"
|
||||
>
|
||||
<Card.ImageCap
|
||||
logoAlt="Course institute logo"
|
||||
logoSrc="https://prod-discovery.edx-cdn.org/organization/certificate_logos/b9dc96da-b3fc-45a6-b6b7-b8e12eb79335-ac60112330e3.png"
|
||||
src="https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg"
|
||||
srcAlt="Course image banner"
|
||||
/>
|
||||
|
||||
@@ -15,14 +15,12 @@ export const SuggestedCourses = () => {
|
||||
<h3 className="text-center">{formatMessage(messages.header)}</h3>
|
||||
<div className="d-flex">
|
||||
{suggestedCourses.map((course) => (
|
||||
<Card key={course.title} className="m-3">
|
||||
<Card key={course.courseName} className="m-3">
|
||||
<Card.ImageCap
|
||||
src={course.bannerUrl}
|
||||
src={course.bannerImgSrc}
|
||||
srcAlt={formatMessage(messages.courseImageAlt)}
|
||||
logoSrc={course.logoUrl}
|
||||
logoAlt={formatMessage(messages.institueLogoAlt)}
|
||||
/>
|
||||
<Card.Header title={course.title} />
|
||||
<Card.Header title={course.courseName} />
|
||||
<Card.Footer>
|
||||
<Button as="a">{formatMessage(messages.viewCourseButton)}</Button>
|
||||
</Card.Footer>
|
||||
|
||||
@@ -12,21 +12,18 @@ jest.mock('data/redux', () => ({
|
||||
|
||||
const suggestedCourses = [
|
||||
{
|
||||
bannerUrl: 'https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg',
|
||||
logoUrl: 'https://prod-discovery.edx-cdn.org/organization/certificate_logos/b9dc96da-b3fc-45a6-b6b7-b8e12eb79335-ac60112330e3.png',
|
||||
title: 'Suggested course 1',
|
||||
bannerImgSrc: 'https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg',
|
||||
courseName: 'Suggested course 1',
|
||||
courseUrl: 'www.edx/suggested-course',
|
||||
},
|
||||
{
|
||||
bannerUrl: 'https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg',
|
||||
logoUrl: 'https://prod-discovery.edx-cdn.org/organization/certificate_logos/b9dc96da-b3fc-45a6-b6b7-b8e12eb79335-ac60112330e3.png',
|
||||
title: 'Suggested course 2',
|
||||
bannerImgSrc: 'https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg',
|
||||
courseName: 'Suggested course 2',
|
||||
courseUrl: 'www.edx/suggested-course',
|
||||
},
|
||||
{
|
||||
bannerUrl: 'https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg',
|
||||
logoUrl: 'https://prod-discovery.edx-cdn.org/organization/certificate_logos/b9dc96da-b3fc-45a6-b6b7-b8e12eb79335-ac60112330e3.png',
|
||||
title: 'Suggested course 3',
|
||||
bannerImgSrc: 'https://prod-discovery.edx-cdn.org/media/programs/banner_images/9a310b98-8f27-439e-be85-12d6460245c9-f2efca129273.small.jpg',
|
||||
courseName: 'Suggested course 3',
|
||||
courseUrl: 'www.edx/suggested-course',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -16,11 +16,6 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Course image banner',
|
||||
description: 'alt for course image',
|
||||
},
|
||||
institueLogoAlt: {
|
||||
id: 'leanerDashboard.emptyCourse.suggestedCourses.institueLogoAlt',
|
||||
defaultMessage: 'Course institute logo',
|
||||
description: 'alt for institute logo',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
@@ -7,7 +7,7 @@ exports[`ConfirmEmailBanner snapshot Show on unverified 1`] = `
|
||||
onDismiss={[MockFunction closePageBanner]}
|
||||
show={[MockFunction showPageBanner]}
|
||||
>
|
||||
<formatMessageFunction
|
||||
<format-message-function
|
||||
message={
|
||||
Object {
|
||||
"defaultMessage": "Remember to confirm your email so that you can keep learning on edX! {confirmNowButton}.",
|
||||
|
||||
@@ -20,9 +20,7 @@ exports[`RelatedProgramsModal snapshot: closed 1`] = `
|
||||
<ModalDialog.Header
|
||||
as="h4"
|
||||
className="programs-header p-0"
|
||||
>
|
||||
hookProps.courseTitle
|
||||
</ModalDialog.Header>
|
||||
/>
|
||||
<ModalDialog.Body
|
||||
className="pl-0 overflow-hidden"
|
||||
>
|
||||
@@ -105,9 +103,7 @@ exports[`RelatedProgramsModal snapshot: open 1`] = `
|
||||
<ModalDialog.Header
|
||||
as="h4"
|
||||
className="programs-header p-0"
|
||||
>
|
||||
hookProps.courseTitle
|
||||
</ModalDialog.Header>
|
||||
/>
|
||||
<ModalDialog.Body
|
||||
className="pl-0 overflow-hidden"
|
||||
>
|
||||
|
||||
@@ -28,9 +28,9 @@ export const ProgramCard = ({ data }) => {
|
||||
>
|
||||
<Card.ImageCap
|
||||
className="program-card-banner"
|
||||
src={data.bannerUrl}
|
||||
src={data.bannerImgSrc}
|
||||
srcAlt={formatMessage(messages.bannerAlt)}
|
||||
logoSrc={data.logoUrl}
|
||||
logoSrc={data.logoImgSrc}
|
||||
logoAlt={formatMessage(messages.logoAlt)}
|
||||
/>
|
||||
<Card.Header
|
||||
@@ -50,8 +50,8 @@ export const ProgramCard = ({ data }) => {
|
||||
};
|
||||
ProgramCard.propTypes = {
|
||||
data: PropTypes.shape({
|
||||
bannerUrl: PropTypes.string,
|
||||
logoUrl: PropTypes.string,
|
||||
bannerImgSrc: PropTypes.string,
|
||||
logoImgSrc: PropTypes.string,
|
||||
numberOfCourses: PropTypes.number,
|
||||
programType: PropTypes.string,
|
||||
programUrl: PropTypes.string,
|
||||
|
||||
@@ -6,8 +6,8 @@ import ProgramCard from './ProgramCard';
|
||||
const props = {
|
||||
data: {
|
||||
numberOfCourses: 2,
|
||||
bannerUrl: 'props.data.bannerUrl',
|
||||
logoUrl: 'props.data.logoUrl',
|
||||
bannerImgSrc: 'props.data.bannerImgSrc',
|
||||
logoImgSrc: 'props.data.logoImgSrc',
|
||||
title: 'props.data.title',
|
||||
provider: 'props.data.provider',
|
||||
programType: 'props.data.programType',
|
||||
|
||||
@@ -13,9 +13,9 @@ exports[`RelatedProgramsModal ProgramCard snapshot 1`] = `
|
||||
<Card.ImageCap
|
||||
className="program-card-banner"
|
||||
logoAlt="Provider logo"
|
||||
logoSrc="props.data.logoUrl"
|
||||
src="props.data.bannerUrl"
|
||||
srcAlt="Programm banner"
|
||||
logoSrc="props.data.logoImgSrc"
|
||||
src="props.data.bannerImgSrc"
|
||||
srcAlt="Program banner"
|
||||
/>
|
||||
<Card.Header
|
||||
subtitle={
|
||||
|
||||
@@ -16,7 +16,7 @@ export const messages = {
|
||||
},
|
||||
bannerAlt: {
|
||||
id: 'learnerDashboard.programCard.bannerAlt',
|
||||
defaultMessage: 'Programm banner',
|
||||
defaultMessage: 'Program banner',
|
||||
description: 'Program banner logo alt-text',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { hooks as appHooks } from 'data/redux';
|
||||
|
||||
import * as hooks from './hooks';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseData: jest.fn(),
|
||||
useCardRelatedProgramsData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const cardId = 'test-course-number';
|
||||
|
||||
const courseTitle = 'test-course-title';
|
||||
const relatedPrograms = ['some', 'programs'];
|
||||
|
||||
describe('RelatedProgramsModal hooks', () => {
|
||||
it('forwards course title and related programs list by course number', () => {
|
||||
appHooks.useCardCourseData.mockReturnValue({ title: courseTitle });
|
||||
appHooks.useCardRelatedProgramsData.mockReturnValue({ list: relatedPrograms });
|
||||
const out = hooks.useProgramData({ cardId });
|
||||
expect(appHooks.useCardCourseData).toHaveBeenCalledWith(cardId);
|
||||
expect(appHooks.useCardRelatedProgramsData).toHaveBeenCalledWith(cardId);
|
||||
expect(out).toEqual({ courseTitle, relatedPrograms });
|
||||
});
|
||||
});
|
||||
@@ -7,9 +7,9 @@ import {
|
||||
Container, Row, Col, ModalDialog,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import ProgramCard from './components/ProgramCard';
|
||||
import messages from './messages';
|
||||
import { useProgramData } from './hooks';
|
||||
import './index.scss';
|
||||
|
||||
export const RelatedProgramsModal = ({
|
||||
@@ -18,7 +18,8 @@ export const RelatedProgramsModal = ({
|
||||
cardId,
|
||||
}) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { courseTitle, relatedPrograms } = useProgramData({ cardId });
|
||||
const { courseName } = hooks.useCardCourseData(cardId);
|
||||
const relatedPrograms = hooks.useCardRelatedProgramsData(cardId).list;
|
||||
return (
|
||||
<ModalDialog
|
||||
title={formatMessage(messages.header)}
|
||||
@@ -34,7 +35,7 @@ export const RelatedProgramsModal = ({
|
||||
{formatMessage(messages.header)}
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Header as="h4" className="programs-header p-0">
|
||||
{courseTitle}
|
||||
{courseName}
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body className="pl-0 overflow-hidden">
|
||||
<p>{formatMessage(messages.description)}</p>
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { useProgramData } from './hooks';
|
||||
import { hooks } from 'data/redux';
|
||||
import RelatedProgramsModal from '.';
|
||||
|
||||
jest.mock('./components/ProgramCard', () => 'ProgramCard');
|
||||
jest.mock('./hooks', () => ({
|
||||
useProgramData: jest.fn(),
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseData: jest.fn(),
|
||||
useCardRelatedProgramsData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const cardId = 'test-course-number';
|
||||
const hookProps = {
|
||||
const courseData = {
|
||||
courseTitle: 'hookProps.courseTitle',
|
||||
relatedPrograms: [
|
||||
};
|
||||
const programData = {
|
||||
list: [
|
||||
{
|
||||
programUrl: 'program-1-url',
|
||||
programData: { dataFor: 'program1' },
|
||||
@@ -36,7 +41,13 @@ const props = {
|
||||
|
||||
describe('RelatedProgramsModal', () => {
|
||||
beforeEach(() => {
|
||||
useProgramData.mockReturnValueOnce(hookProps);
|
||||
hooks.useCardCourseData.mockReturnValueOnce(courseData);
|
||||
hooks.useCardRelatedProgramsData.mockReturnValueOnce(programData);
|
||||
});
|
||||
it('initializes hooks with cardId', () => {
|
||||
shallow(<RelatedProgramsModal {...props} />);
|
||||
expect(hooks.useCardCourseData).toHaveBeenCalledWith(cardId);
|
||||
expect(hooks.useCardRelatedProgramsData).toHaveBeenCalledWith(cardId);
|
||||
});
|
||||
test('snapshot: open', () => {
|
||||
expect(shallow(<RelatedProgramsModal {...props} />)).toMatchSnapshot();
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import thunk from 'redux-thunk';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { useIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import api from 'data/services/lms/api';
|
||||
import fakeData from 'data/services/lms/fakeData/courses';
|
||||
@@ -34,6 +34,14 @@ jest.unmock('react');
|
||||
jest.unmock('react-redux');
|
||||
jest.unmock('hooks');
|
||||
|
||||
jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
...jest.requireActual('@edx/frontend-platform/i18n'),
|
||||
useIntl: () => ({
|
||||
formatMessage: jest.requireActual('testUtils').formatMessage,
|
||||
formatDate: (date) => `Date-${date}`,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@edx/frontend-platform/auth', () => ({
|
||||
getAuthenticatedHttpClient: jest.fn(),
|
||||
getLoginRedirectUrl: jest.fn(),
|
||||
@@ -128,9 +136,10 @@ describe('ESG app integration tests', () => {
|
||||
});
|
||||
|
||||
test('course cards', async () => {
|
||||
const { formatDate } = useIntl();
|
||||
resolveFns.init.success();
|
||||
await waitForRequestStatus(RequestKeys.initialize, RequestStates.completed);
|
||||
await inspector.findByText(fakeData.courseRunData[0].course.title);
|
||||
await inspector.findByText(fakeData.courseRunData[0].course.courseName);
|
||||
const cards = inspector.get.courseCards;
|
||||
|
||||
let cardId;
|
||||
@@ -149,14 +158,14 @@ describe('ESG app integration tests', () => {
|
||||
|
||||
inspector.verifyText(
|
||||
inspector.get.card.header(card),
|
||||
courseData.course.title,
|
||||
courseData.course.courseName,
|
||||
);
|
||||
cardDetails = inspector.get.card.details(card);
|
||||
[
|
||||
courseData.provider.name,
|
||||
courseData.courseProvider.name,
|
||||
courseData.course.courseNumber,
|
||||
appMessages.withValues.CourseCardDetails.courseStarts({
|
||||
startDate: courseData.courseRun.startDate,
|
||||
startDate: formatDate(new Date(courseData.courseRun.startDate)),
|
||||
}),
|
||||
].forEach(value => inspector.verifyTextIncludes(cardDetails, value));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user