From 72c17d963e117ada0ca6317697dcdb9433d7856e Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Mon, 15 Jul 2024 17:21:30 -0400 Subject: [PATCH] fix: adhere to `hideCourseOriginalPrice` in upgrade/enroll confirmation modal (#1117) --- .../data/services/contentHighlights.test.js | 1 - .../enterpriseCustomerUser.factory.js | 1 + src/components/course/EnrollModal.jsx | 21 +++- .../course/tests/EnrollModal.test.jsx | 111 ++++++++++++++---- 4 files changed, 102 insertions(+), 32 deletions(-) diff --git a/src/components/app/data/services/contentHighlights.test.js b/src/components/app/data/services/contentHighlights.test.js index 9a74cf40fc..d6d53d18ad 100644 --- a/src/components/app/data/services/contentHighlights.test.js +++ b/src/components/app/data/services/contentHighlights.test.js @@ -77,7 +77,6 @@ describe('fetchContentHighlights', () => { { uuid: 'test-highlight-set-uuid-2' }, ], }; - console.log('mockUrl ', HIGHLIGHT_SETS_URL); axiosMock.onGet(HIGHLIGHT_SETS_URL).reply(200, mockResponse); const result = await fetchContentHighlights(mockEnterpriseId); expect(result).toEqual(mockResponse.results); diff --git a/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.js b/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.js index 321ee0e4b9..cab510dc53 100644 --- a/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.js +++ b/src/components/app/data/services/data/__factories__/enterpriseCustomerUser.factory.js @@ -24,6 +24,7 @@ Factory.define('enterpriseCustomer') .attr('name', faker.company.name()) .attr('contact_email', faker.internet.email()) .attr('hide_labor_market_data', false) + .attr('hide_course_original_price', false) .attr('enable_learner_portal', true) .attr('enable_data_sharing_consent', true) .attr('disable_expiry_messaging_for_learner_credit', false) diff --git a/src/components/course/EnrollModal.jsx b/src/components/course/EnrollModal.jsx index ae533adc69..68b4c4bc29 100644 --- a/src/components/course/EnrollModal.jsx +++ b/src/components/course/EnrollModal.jsx @@ -8,7 +8,12 @@ import { FormattedMessage, defineMessages, useIntl } from '@edx/frontend-platfor import { v4 as uuidv4 } from 'uuid'; import { ENTERPRISE_OFFER_TYPE } from '../enterprise-user-subsidy/enterprise-offers/data/constants'; -import { COUPON_CODE_SUBSIDY_TYPE, ENTERPRISE_OFFER_SUBSIDY_TYPE, LEARNER_CREDIT_SUBSIDY_TYPE } from '../app/data'; +import { + COUPON_CODE_SUBSIDY_TYPE, + ENTERPRISE_OFFER_SUBSIDY_TYPE, + LEARNER_CREDIT_SUBSIDY_TYPE, + useEnterpriseCustomer, +} from '../app/data'; export const messages = defineMessages({ enrollModalConfirmCta: { @@ -88,8 +93,9 @@ export const messages = defineMessages({ }, }); -export const createUseEnterpriseOfferText = (offerType, courseRunPrice) => { - if (offerType !== ENTERPRISE_OFFER_TYPE.ENROLLMENTS_LIMIT && courseRunPrice) { +export const createUseEnterpriseOfferText = ({ offerType, courseRunPrice, hideCourseOriginalPrice }) => { + const isOfferTypeEnrollmentsLimit = offerType === ENTERPRISE_OFFER_TYPE.ENROLLMENTS_LIMIT; + if (!isOfferTypeEnrollmentsLimit && courseRunPrice && !hideCourseOriginalPrice) { return messages.enterpriseOfferUsageWithPrice; } return messages.enterpriseOfferUsageWithoutPrice; @@ -156,6 +162,7 @@ export const MODAL_TEXTS = { }; const useModalTexts = ({ userSubsidyApplicableToCourse, couponCodesCount, courseRunPrice }) => { + const { data: enterpriseCustomer } = useEnterpriseCustomer(); const intl = useIntl(); const { HAS_COUPON_CODE, @@ -178,7 +185,11 @@ const useModalTexts = ({ userSubsidyApplicableToCourse, couponCodesCount, course paymentRequiredForCourse: false, buttonText: intl.formatMessage(HAS_ENTERPRISE_OFFER.button), enrollText: intl.formatMessage( - HAS_ENTERPRISE_OFFER.body(userSubsidyApplicableToCourse.offerType, courseRunPrice), + HAS_ENTERPRISE_OFFER.body({ + offerType: userSubsidyApplicableToCourse.offerType, + courseRunPrice, + hideCourseOriginalPrice: enterpriseCustomer.hideCourseOriginalPrice, + }), { courseRunPrice: `$${courseRunPrice}` }, ), titleText: intl.formatMessage(HAS_ENTERPRISE_OFFER.title), @@ -242,7 +253,7 @@ const EnrollModal = ({ // Check whether the modal should be rendered (i.e., do not show modal if user has no applicable subsidy) // as payment would be required for the learner to enroll in the course. - if (paymentRequiredForCourse) { + if (paymentRequiredForCourse || !userSubsidyApplicableToCourse) { return null; } diff --git a/src/components/course/tests/EnrollModal.test.jsx b/src/components/course/tests/EnrollModal.test.jsx index 258cb574a9..99f11706b2 100644 --- a/src/components/course/tests/EnrollModal.test.jsx +++ b/src/components/course/tests/EnrollModal.test.jsx @@ -5,10 +5,22 @@ import { screen, render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import EnrollModal, { MODAL_TEXTS, messages } from '../EnrollModal'; -import { COUPON_CODE_SUBSIDY_TYPE, ENTERPRISE_OFFER_SUBSIDY_TYPE, LEARNER_CREDIT_SUBSIDY_TYPE } from '../../app/data'; +import { + COUPON_CODE_SUBSIDY_TYPE, + ENTERPRISE_OFFER_SUBSIDY_TYPE, + LEARNER_CREDIT_SUBSIDY_TYPE, + useEnterpriseCustomer, +} from '../../app/data'; +import { enterpriseCustomerFactory } from '../../app/data/services/data/__factories__'; import { ENTERPRISE_OFFER_TYPE } from '../../enterprise-user-subsidy/enterprise-offers/data/constants'; +jest.mock('../../app/data', () => ({ + ...jest.requireActual('../../app/data'), + useEnterpriseCustomer: jest.fn(), +})); + jest.mock('../data/hooks', () => ({ + ...jest.requireActual('../data/hooks'), useTrackSearchConversionClickHandler: jest.fn(), useOptimizelyEnrollmentClickHandler: jest.fn(), })); @@ -19,24 +31,36 @@ const EnrollModalWrapper = (props) => ( ); +const baseProps = { + isModalOpen: true, + setIsModalOpen: jest.fn(), + enrollmentUrl: 'https://example.com/enroll', + courseRunPrice: 100, + userSubsidyApplicableToCourse: undefined, + couponCodesCount: 0, +}; + +const mockEnterpriseCustomer = enterpriseCustomerFactory(); +const mockEnterpriseCustomerWithoutPrice = enterpriseCustomerFactory({ + hide_course_original_price: true, +}); + describe('', () => { - const basicProps = { - isModalOpen: true, - setIsModalOpen: jest.fn(), - enrollmentUrl: 'https://example.com/enroll', - courseRunPrice: 100, - userSubsidyApplicableToCourse: undefined, - couponCodesCount: 0, - }; + beforeEach(() => { + jest.clearAllMocks(); + useEnterpriseCustomer.mockReturnValue({ + data: mockEnterpriseCustomer, + }); + }); it('does not render when user has no applicable subsidy', () => { - const { container } = render(); + const { container } = render(); expect(container).toBeEmptyDOMElement(); }); - it('displays the correct texts when user has a coupon code for the course', () => { + it('displays the correct texts when user has a coupon code for the course (%s)', async () => { const props = { - ...basicProps, + ...baseProps, userSubsidyApplicableToCourse: { subsidyType: COUPON_CODE_SUBSIDY_TYPE, }, @@ -46,14 +70,40 @@ describe('', () => { expect(screen.getByText(MODAL_TEXTS.HAS_COUPON_CODE.title.defaultMessage)).toBeInTheDocument(); expect(screen.getByText(MODAL_TEXTS.HAS_COUPON_CODE.body.defaultMessage.replace('{couponCodesCount}', props.couponCodesCount))).toBeInTheDocument(); expect(screen.getByText(MODAL_TEXTS.HAS_COUPON_CODE.button.defaultMessage)).toBeInTheDocument(); + + // Close modal + userEvent.click(screen.getByRole('button', { name: messages.modalCancelCta.defaultMessage })); + expect(baseProps.setIsModalOpen).toHaveBeenCalledTimes(1); + expect(baseProps.setIsModalOpen).toHaveBeenCalledWith(false); }); it.each([ - { offerType: ENTERPRISE_OFFER_TYPE.ENROLLMENTS_LIMIT }, - { offerType: ENTERPRISE_OFFER_TYPE.NO_LIMIT }, - ])('displays the correct texts when there is an enterprise offer (%s)', ({ offerType }) => { + { + offerType: ENTERPRISE_OFFER_TYPE.ENROLLMENTS_LIMIT, + hideCourseOriginalPrice: false, + courseRunPrice: 100, + }, + { + offerType: ENTERPRISE_OFFER_TYPE.NO_LIMIT, + hideCourseOriginalPrice: false, + courseRunPrice: 100, + }, + { + offerType: ENTERPRISE_OFFER_TYPE.NO_LIMIT, + hideCourseOriginalPrice: true, + courseRunPrice: 100, + }, + ])('displays the correct texts when there is an enterprise offer (%s)', async ({ + offerType, + hideCourseOriginalPrice, + courseRunPrice, + }) => { + useEnterpriseCustomer.mockReturnValue({ + data: hideCourseOriginalPrice ? mockEnterpriseCustomerWithoutPrice : mockEnterpriseCustomer, + }); const props = { - ...basicProps, + ...baseProps, + courseRunPrice, userSubsidyApplicableToCourse: { subsidyType: ENTERPRISE_OFFER_SUBSIDY_TYPE, offerType, @@ -61,19 +111,23 @@ describe('', () => { }; render(); expect(screen.getByText(MODAL_TEXTS.HAS_ENTERPRISE_OFFER.title.defaultMessage)).toBeInTheDocument(); - expect( - screen.getByText( - MODAL_TEXTS.HAS_ENTERPRISE_OFFER.body(offerType, props.courseRunPrice) - .defaultMessage - .replace('{courseRunPrice}', `$${props.courseRunPrice}`), - ), - ).toBeInTheDocument(); + const expectedBodyMessage = MODAL_TEXTS.HAS_ENTERPRISE_OFFER.body({ + offerType, + courseRunPrice: props.courseRunPrice, + hideCourseOriginalPrice, + }).defaultMessage.replace('{courseRunPrice}', `$${props.courseRunPrice}`); + expect(await screen.findByText(expectedBodyMessage)).toBeInTheDocument(); expect(screen.getByText(MODAL_TEXTS.HAS_ENTERPRISE_OFFER.button.defaultMessage)).toBeInTheDocument(); + + // Close modal + userEvent.click(screen.getByRole('button', { name: messages.modalCancelCta.defaultMessage })); + expect(baseProps.setIsModalOpen).toHaveBeenCalledTimes(1); + expect(baseProps.setIsModalOpen).toHaveBeenCalledWith(false); }); - it('displays the correct texts when there is learner credit available', () => { + it('displays the correct texts when there is learner credit available', async () => { const props = { - ...basicProps, + ...baseProps, userSubsidyApplicableToCourse: { subsidyType: LEARNER_CREDIT_SUBSIDY_TYPE, }, @@ -88,6 +142,11 @@ describe('', () => { // Assert confirm upgrade CTA is present expect(screen.getByRole('button', { name: messages.upgradeModalConfirmCta.defaultMessage })); + + // Close modal + userEvent.click(screen.getByRole('button', { name: messages.modalCancelCta.defaultMessage })); + expect(baseProps.setIsModalOpen).toHaveBeenCalledTimes(1); + expect(baseProps.setIsModalOpen).toHaveBeenCalledWith(false); }); it('calls onEnroll when enrollmentUrl is clicked', () => { @@ -95,7 +154,7 @@ describe('', () => { render(