Skip to content

Commit

Permalink
fix: adhere to hideCourseOriginalPrice in upgrade/enroll confirmati…
Browse files Browse the repository at this point in the history
…on modal (#1117)
  • Loading branch information
adamstankiewicz authored Jul 15, 2024
1 parent 00a9728 commit 72c17d9
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 32 deletions.
1 change: 0 additions & 1 deletion src/components/app/data/services/contentHighlights.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
21 changes: 16 additions & 5 deletions src/components/course/EnrollModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -156,6 +162,7 @@ export const MODAL_TEXTS = {
};

const useModalTexts = ({ userSubsidyApplicableToCourse, couponCodesCount, courseRunPrice }) => {
const { data: enterpriseCustomer } = useEnterpriseCustomer();
const intl = useIntl();
const {
HAS_COUPON_CODE,
Expand All @@ -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),
Expand Down Expand Up @@ -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;
}

Expand Down
111 changes: 85 additions & 26 deletions src/components/course/tests/EnrollModal.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}));
Expand All @@ -19,24 +31,36 @@ const EnrollModalWrapper = (props) => (
</IntlProvider>
);

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('<EnrollModal />', () => {
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(<EnrollModalWrapper {...basicProps} />);
const { container } = render(<EnrollModalWrapper {...baseProps} />);
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,
},
Expand All @@ -46,34 +70,64 @@ describe('<EnrollModal />', () => {
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,
},
};
render(<EnrollModalWrapper {...props} />);
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,
},
Expand All @@ -88,14 +142,19 @@ describe('<EnrollModal />', () => {

// 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', () => {
const mockHandleEnroll = jest.fn();

render(
<EnrollModalWrapper
{...basicProps}
{...baseProps}
onEnroll={mockHandleEnroll}
userSubsidyApplicableToCourse={{
subsidyType: COUPON_CODE_SUBSIDY_TYPE,
Expand Down

0 comments on commit 72c17d9

Please sign in to comment.