fix: stop user from unenroll after earned the certificate

This commit is contained in:
Leangseu Kim
2023-06-05 16:53:41 -04:00
committed by leangseu-edx
parent e43a49b431
commit a479b7ead6
4 changed files with 173 additions and 51 deletions

View File

@@ -1,5 +1,64 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CourseCardMenu disable and stop rendering buttons snapshot when no dropdown items exist 1`] = `
<Fragment>
<Dropdown>
<Dropdown.Toggle
alt="Course actions dropdown"
as="IconButton"
iconAs="Icon"
id="course-actions-dropdown-test-card-id"
src={[MockFunction icons.MoreVert]}
variant="primary"
/>
<Dropdown.Menu>
<Dropdown.Item
data-testid="unenrollModalToggle"
disabled={false}
onClick={[MockFunction unenrollShow]}
>
Unenroll
</Dropdown.Item>
<Dropdown.Item
data-testid="emailSettingsModalToggle"
disabled={false}
onClick={[MockFunction emailSettingShow]}
>
Email settings
</Dropdown.Item>
<FacebookShareButton
className="pgn__dropdown-item dropdown-item"
onClick={[MockFunction facebookShareClick]}
resetButtonStyle={false}
title="I'm taking test-course-name online with facebook-social-brand. Check it out!"
url="facebook-share-url"
>
Share to Facebook
</FacebookShareButton>
<TwitterShareButton
className="pgn__dropdown-item dropdown-item"
onClick={[MockFunction twitterShareClick]}
resetButtonStyle={false}
title="I'm taking test-course-name online with twitter-social-brand. Check it out!"
url="twitter-share-url"
>
Share to Twitter
</TwitterShareButton>
</Dropdown.Menu>
</Dropdown>
<UnenrollConfirmModal
cardId="test-card-id"
closeModal={[MockFunction unenrollHide]}
show={false}
/>
<EmailSettingsModal
cardId="test-card-id"
closeModal={[MockFunction emailSettingHide]}
show={false}
/>
</Fragment>
`;
exports[`CourseCardMenu enrolled, share enabled, email setting enable snapshot 1`] = `
<Fragment>
<Dropdown>
@@ -117,24 +176,3 @@ exports[`CourseCardMenu masquerading snapshot 1`] = `
/>
</Fragment>
`;
exports[`CourseCardMenu not enrolled, share disabled, email setting disabled snapshot 1`] = `
<Fragment>
<Dropdown>
<Dropdown.Toggle
alt="Course actions dropdown"
as="IconButton"
iconAs="Icon"
id="course-actions-dropdown-test-card-id"
src={[MockFunction icons.MoreVert]}
variant="primary"
/>
<Dropdown.Menu />
</Dropdown>
<UnenrollConfirmModal
cardId="test-card-id"
closeModal={[MockFunction unenrollHide]}
show={false}
/>
</Fragment>
`;

View File

@@ -25,6 +25,7 @@ export const CourseCardMenu = ({ cardId }) => {
const { isEnrolled, isEmailEnabled } = reduxHooks.useCardEnrollmentData(cardId);
const { twitter, facebook } = reduxHooks.useCardSocialSettingsData(cardId);
const { isMasquerading } = reduxHooks.useMasqueradeData();
const { isEarned } = reduxHooks.useCardCertificateData(cardId);
const handleTwitterShare = reduxHooks.useTrackCourseEvent(
track.socialShare,
cardId,
@@ -40,6 +41,13 @@ export const CourseCardMenu = ({ cardId }) => {
const unenrollModal = useUnenrollData();
const handleToggleDropdown = useHandleToggleDropdown(cardId);
const showUnenrollItem = isEnrolled && !isEarned;
const showDropdown = showUnenrollItem || isEmailEnabled || facebook.isEnabled || twitter.isEnabled;
if (!showDropdown) {
return null;
}
return (
<>
<Dropdown onToggle={handleToggleDropdown}>
@@ -52,7 +60,7 @@ export const CourseCardMenu = ({ cardId }) => {
alt={formatMessage(messages.dropdownAlt)}
/>
<Dropdown.Menu>
{isEnrolled && (
{showUnenrollItem && (
<Dropdown.Item
disabled={isMasquerading}
onClick={unenrollModal.show}

View File

@@ -14,6 +14,7 @@ jest.mock('hooks', () => ({
useCardEnrollmentData: jest.fn(),
useCardSocialSettingsData: jest.fn(),
useMasqueradeData: jest.fn(),
useCardCertificateData: jest.fn(),
useTrackCourseEvent: (_, __, site) => jest.fn().mockName(`${site}ShareClick`),
},
}));
@@ -53,17 +54,43 @@ let wrapper;
let el;
describe('CourseCardMenu', () => {
beforeEach(() => {
useEmailSettings.mockReturnValue(defaultEmailSettingsModal);
useUnenrollData.mockReturnValue(defaultUnenrollModal);
reduxHooks.useCardSocialSettingsData.mockReturnValue(defaultSocialShare);
reduxHooks.useCardCourseData.mockReturnValue({ courseName });
reduxHooks.useCardEnrollmentData.mockReturnValue({ isEnrolled: true, isEmailEnabled: true });
reduxHooks.useMasqueradeData.mockReturnValue({ isMasquerading: false });
});
const mockCourseCardMenu = ({
isEnrolled,
isEmailEnabled,
isMasquerading,
facebook,
twitter,
isEarned,
}) => {
useEmailSettings.mockReturnValueOnce(defaultEmailSettingsModal);
useUnenrollData.mockReturnValueOnce(defaultUnenrollModal);
reduxHooks.useCardCourseData.mockReturnValueOnce({ courseName });
reduxHooks.useCardSocialSettingsData.mockReturnValueOnce({
facebook: {
...defaultSocialShare.facebook,
...facebook,
},
twitter: {
...defaultSocialShare.twitter,
...twitter,
},
});
reduxHooks.useCardEnrollmentData.mockReturnValueOnce({
isEnrolled,
isEmailEnabled,
});
reduxHooks.useMasqueradeData.mockReturnValueOnce({ isMasquerading });
reduxHooks.useCardCertificateData.mockReturnValueOnce({ isEarned });
return shallow(<CourseCardMenu {...props} />);
};
describe('enrolled, share enabled, email setting enable', () => {
beforeEach(() => {
wrapper = shallow(<CourseCardMenu {...props} />);
wrapper = mockCourseCardMenu({
isEnrolled: true,
isEmailEnabled: true,
isMasquerading: false,
isEarned: false,
});
});
test('snapshot', () => {
expect(wrapper).toMatchSnapshot();
@@ -89,36 +116,84 @@ describe('CourseCardMenu', () => {
expect(el.props().disabled).toEqual(false);
});
});
describe('not enrolled, share disabled, email setting disabled', () => {
beforeEach(() => {
reduxHooks.useCardSocialSettingsData.mockReturnValueOnce({
...defaultSocialShare,
twitter: { ...defaultSocialShare.twitter, isEnabled: false },
facebook: { ...defaultSocialShare.facebook, isEnabled: false },
describe('disable and stop rendering buttons', () => {
it('does not render unenroll dropdown item when certificate is already earned', () => {
wrapper = mockCourseCardMenu({
isEnrolled: true,
isEmailEnabled: true,
isMasquerading: false,
isEarned: true,
});
reduxHooks.useCardEnrollmentData.mockReturnValueOnce({ isEnrolled: false, isEmailEnabled: false });
wrapper = shallow(<CourseCardMenu {...props} />);
});
test('snapshot', () => {
expect(wrapper).toMatchSnapshot();
});
it('does not renders share buttons', () => {
expect(wrapper.find('FacebookShareButton').length).toEqual(0);
expect(wrapper.find('TwitterShareButton').length).toEqual(0);
});
it('does not render unenroll modal toggle', () => {
el = wrapper.find({ 'data-testid': 'unenrollModalToggle' });
expect(el.length).toEqual(0);
});
it('does not render email settings modal toggle', () => {
it('does not render unenroll dropdown item when course is not enrolled', () => {
wrapper = mockCourseCardMenu({
isEnrolled: false,
isEmailEnabled: true,
isMasquerading: false,
isEarned: false,
});
el = wrapper.find({ 'data-testid': 'unenrollModalToggle' });
expect(el.length).toEqual(0);
});
it('does not render email settings modal toggle when email is not enabled', () => {
wrapper = mockCourseCardMenu({
isEnrolled: true,
isEmailEnabled: false,
isMasquerading: false,
isEarned: false,
});
el = wrapper.find({ 'data-testid': 'emailSettingsModalToggle' });
expect(el.length).toEqual(0);
});
it('does not render facebook share button when facebook is not enabled', () => {
wrapper = mockCourseCardMenu({
isEnrolled: true,
isEmailEnabled: true,
facebook: {
...defaultSocialShare.facebook,
isEnabled: false,
},
isMasquerading: false,
isEarned: false,
});
el = wrapper.find('FacebookShareButton');
expect(el.length).toEqual(0);
});
it('does not render twitter share button when twitter is not enabled', () => {
wrapper = mockCourseCardMenu({
isEnrolled: true,
isEmailEnabled: true,
twitter: {
...defaultSocialShare.twitter,
isEnabled: false,
},
isMasquerading: false,
isEarned: false,
});
el = wrapper.find('TwitterShareButton');
expect(el.length).toEqual(0);
});
it('snapshot when no dropdown items exist', () => {
wrapper = mockCourseCardMenu({
isEnrolled: true,
isEmailEnabled: true,
isMasquerading: false,
isEarned: false,
});
expect(wrapper).toMatchSnapshot();
expect(wrapper).toEqual({});
});
});
describe('masquerading', () => {
beforeEach(() => {
reduxHooks.useMasqueradeData.mockReturnValue({ isMasquerading: true });
wrapper = shallow(<CourseCardMenu {...props} />);
wrapper = mockCourseCardMenu({
isEnrolled: true,
isEmailEnabled: true,
isMasquerading: true,
isEarned: false,
});
});
test('snapshot', () => {
expect(wrapper).toMatchSnapshot();

View File

@@ -24,6 +24,7 @@ export const courseCard = StrictDict({
isDownloadable: certificate.isDownloadable,
isEarnedButUnavailable: certificate.isEarned && !isAvailable,
isRestricted: certificate.isRestricted,
isEarned: certificate.isEarned,
};
},
),