TNL-7185: Stop using dangerouslySetInnerHTML in alerts (#306)

Render offer and access-expiration alerts ourselves from newly
passed in backend data, rather than from provided HTML blobs.
This commit is contained in:
Michael Terry
2020-12-14 16:09:49 -05:00
committed by GitHub
parent 3d41c56a0a
commit e89aef78b5
15 changed files with 309 additions and 57 deletions

View File

@@ -35,16 +35,17 @@ function Course({
].filter(element => element != null).map(element => element.title);
const {
accessExpiration,
canShowUpgradeSock,
celebrations,
courseExpiredMessage,
offerHtml,
offer,
userTimezone,
verifiedMode,
} = course;
// Below the tabs, above the breadcrumbs alerts (appearing in the order listed here)
const offerAlert = useOfferAlert(offerHtml, 'course');
const accessExpirationAlert = useAccessExpirationAlert(courseExpiredMessage, 'course');
const offerAlert = useOfferAlert(offer, userTimezone, 'course');
const accessExpirationAlert = useAccessExpirationAlert(accessExpiration, userTimezone, 'course');
const dispatch = useDispatch();
const celebrateFirstSection = celebrations && celebrations.firstSection;

View File

@@ -85,23 +85,27 @@ describe('Course', () => {
});
it('displays offer and expiration alert', async () => {
const offerText = 'test-offer';
const offerId = `${offerText}-id`;
const offerHtml = `<div data-testid="${offerId}">${offerText}</div>`;
const expirationText = 'test-expiration';
const expirationId = `${expirationText}-id`;
const expirationHtml = `<div data-testid="${expirationId}">${expirationText}</div>`;
const courseMetadata = Factory.build('courseMetadata', {
offer_html: offerHtml,
course_expired_message: expirationHtml,
access_expiration: {
expiration_date: '2080-01-01T12:00:00Z',
masquerading_expired_course: false,
upgrade_deadline: null,
upgrade_url: null,
},
offer: {
code: 'EDXWELCOME',
expiration_date: '2070-01-01T12:00:00Z',
original_price: '$100',
discounted_price: '$85',
percentage: 15,
upgrade_url: 'https://example.com/upgrade',
},
});
const testStore = await initializeTestStore({ courseMetadata, excludeFetchSequence: true }, false);
render(<Course {...mockData} courseId={courseMetadata.id} />, { store: testStore });
expect(await screen.findByTestId(offerId)).toHaveTextContent(offerText);
expect(screen.getByTestId(expirationId)).toHaveTextContent(expirationText);
await screen.findByText('EDXWELCOME');
await screen.findByText('Audit Access Expires');
});
it('passes handlers to the sequence', async () => {

View File

@@ -218,6 +218,8 @@ function CourseCelebration({ intl }) {
} else {
footnote = <DashboardFootnote variant={visitEvent} />;
}
} else {
visitEvent = 'celebration_audit_no_upgrade';
}
break;
default:

View File

@@ -110,14 +110,13 @@ function normalizeTabUrls(id, tabs) {
function normalizeMetadata(metadata) {
return {
accessExpiration: camelCaseObject(metadata.access_expiration),
canShowUpgradeSock: metadata.can_show_upgrade_sock,
contentTypeGatingEnabled: metadata.content_type_gating_enabled,
// TODO: TNL-7185: return course expired _date_, instead of _message_
courseExpiredMessage: metadata.course_expired_message,
id: metadata.id,
title: metadata.name,
number: metadata.number,
offerHtml: metadata.offer_html,
offer: camelCaseObject(metadata.offer),
org: metadata.org,
enrollmentStart: metadata.enrollment_start,
enrollmentEnd: metadata.enrollment_end,
@@ -131,6 +130,7 @@ function normalizeMetadata(metadata) {
license: metadata.license,
verifiedMode: camelCaseObject(metadata.verified_mode),
tabs: normalizeTabUrls(metadata.id, camelCaseObject(metadata.tabs)),
userTimezone: metadata.user_timezone,
showCalculator: metadata.show_calculator,
notes: camelCaseObject(metadata.notes),
marketingUrl: metadata.marketing_url,