@openedx/frontend-app-learner-dashboard 1.0.0-alpha.4 → 1.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/package.json +4 -5
  2. package/src/app.scss +2 -5
  3. package/src/components/Banner.test.jsx +21 -21
  4. package/src/containers/CourseCard/CourseCard.scss +4 -6
  5. package/src/containers/CourseCard/components/CourseCardActions/ActionButton/hooks.test.js +27 -0
  6. package/src/containers/CourseCard/components/CourseCardActions/ActionButton/index.test.jsx +17 -14
  7. package/src/containers/CourseCard/components/CourseCardActions/BeginCourseButton.test.jsx +37 -34
  8. package/src/containers/CourseCard/components/CourseCardActions/ResumeButton.test.jsx +28 -28
  9. package/src/containers/CourseCard/components/CourseCardActions/SelectSessionButton.test.jsx +26 -17
  10. package/src/containers/CourseCard/components/CourseCardActions/ViewCourseButton.test.jsx +29 -19
  11. package/src/containers/CourseCard/components/CourseCardActions/index.test.jsx +32 -34
  12. package/src/containers/CourseCard/components/CourseCardBanners/CertificateBanner.test.jsx +205 -190
  13. package/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.test.jsx +35 -62
  14. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/hooks.test.js +3 -3
  15. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/index.test.jsx +49 -79
  16. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/ApprovedContent.jsx +1 -2
  17. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/ApprovedContent.test.jsx +51 -34
  18. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/EligibleContent.test.jsx +36 -44
  19. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/MustRequestContent.jsx +1 -2
  20. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/MustRequestContent.test.jsx +74 -44
  21. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.jsx +1 -2
  22. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/PendingContent.test.jsx +40 -34
  23. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/RejectedContent.test.jsx +16 -26
  24. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/CreditContent.test.jsx +38 -28
  25. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/CreditRequestForm/hooks.test.js +6 -0
  26. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/CreditRequestForm/index.test.jsx +25 -24
  27. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/CreditRequestForm/ref.test.jsx +0 -3
  28. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/ProviderLink.test.jsx +15 -13
  29. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/hooks.test.js +3 -3
  30. package/src/containers/CourseCard/components/CourseCardBanners/EntitlementBanner.test.jsx +33 -24
  31. package/src/containers/CourseCard/components/CourseCardBanners/RelatedProgramsBanner/ProgramsList.test.jsx +13 -5
  32. package/src/containers/CourseCard/components/CourseCardBanners/RelatedProgramsBanner/index.test.jsx +34 -27
  33. package/src/containers/CourseCard/components/CourseCardBanners/index.test.jsx +44 -15
  34. package/src/containers/CourseCard/components/CourseCardDetails/hooks.test.js +19 -9
  35. package/src/containers/CourseCard/components/CourseCardDetails/index.scss +1 -5
  36. package/src/containers/CourseCard/components/CourseCardDetails/index.test.jsx +20 -8
  37. package/src/containers/CourseCard/components/CourseCardImage.test.jsx +48 -41
  38. package/src/containers/CourseCard/components/CourseCardMenu/SocialShareMenu.jsx +3 -4
  39. package/src/containers/CourseCard/components/CourseCardMenu/SocialShareMenu.test.jsx +62 -92
  40. package/src/containers/CourseCard/components/CourseCardMenu/hooks.js +8 -7
  41. package/src/containers/CourseCard/components/CourseCardMenu/hooks.test.js +8 -15
  42. package/src/containers/CourseCard/components/CourseCardMenu/index.jsx +2 -3
  43. package/src/containers/CourseCard/components/CourseCardMenu/index.test.jsx +78 -112
  44. package/src/containers/CourseCard/components/CourseCardTitle.test.jsx +51 -45
  45. package/src/containers/CourseCard/components/RelatedProgramsBadge/hooks.jsx +2 -2
  46. package/src/containers/CourseCard/components/RelatedProgramsBadge/hooks.test.js +18 -4
  47. package/src/containers/CourseCard/components/RelatedProgramsBadge/index.jsx +1 -1
  48. package/src/containers/CourseCard/components/RelatedProgramsBadge/index.test.jsx +17 -13
  49. package/src/containers/CourseCard/components/hooks.test.js +19 -8
  50. package/src/containers/CourseCard/hooks.test.js +12 -2
  51. package/src/containers/CourseCard/index.test.jsx +33 -12
  52. package/src/containers/CourseFilterControls/ActiveCourseFilters.test.jsx +19 -8
  53. package/src/containers/CourseFilterControls/CourseFilterControls.test.jsx +51 -36
  54. package/src/containers/CourseFilterControls/components/Checkbox.test.jsx +8 -5
  55. package/src/containers/CourseFilterControls/components/FilterForm.test.jsx +45 -20
  56. package/src/containers/CourseFilterControls/components/SortForm.test.jsx +19 -9
  57. package/src/containers/CourseFilterControls/hooks.test.js +25 -13
  58. package/src/containers/CoursesPanel/CourseList/index.test.jsx +39 -22
  59. package/src/containers/CoursesPanel/NoCoursesView/index.scss +5 -7
  60. package/src/containers/CoursesPanel/NoCoursesView/index.test.jsx +26 -6
  61. package/src/containers/CoursesPanel/hooks.test.js +4 -4
  62. package/src/containers/CoursesPanel/index.scss +5 -7
  63. package/src/containers/CoursesPanel/index.test.jsx +55 -21
  64. package/src/containers/Dashboard/DashboardLayout.test.jsx +43 -52
  65. package/src/containers/Dashboard/LoadingView.test.jsx +5 -10
  66. package/src/containers/Dashboard/hooks.test.js +21 -19
  67. package/src/containers/Dashboard/index.scss +8 -10
  68. package/src/containers/Dashboard/index.test.jsx +51 -92
  69. package/src/containers/EmailSettingsModal/hooks.test.js +3 -3
  70. package/src/containers/EmailSettingsModal/index.test.jsx +27 -10
  71. package/src/containers/RelatedProgramsModal/components/ProgramCard.test.jsx +31 -11
  72. package/src/containers/RelatedProgramsModal/index.test.jsx +27 -15
  73. package/src/containers/SelectSessionModal/constants.js +0 -1
  74. package/src/containers/SelectSessionModal/hooks.test.js +15 -5
  75. package/src/containers/SelectSessionModal/index.test.jsx +24 -11
  76. package/src/containers/UnenrollConfirmModal/components/ConfirmPane.test.jsx +24 -8
  77. package/src/containers/UnenrollConfirmModal/components/FinishedPane.test.jsx +39 -14
  78. package/src/containers/UnenrollConfirmModal/components/ReasonPane.test.jsx +23 -6
  79. package/src/containers/UnenrollConfirmModal/hooks/index.test.js +74 -26
  80. package/src/containers/UnenrollConfirmModal/hooks/reasons.test.js +4 -4
  81. package/src/containers/UnenrollConfirmModal/index.test.jsx +34 -17
  82. package/src/data/constants/app.js +0 -3
  83. package/src/data/constants/app.test.js +0 -12
  84. package/src/data/redux/app/selectors/courseCard.test.js +4 -4
  85. package/src/data/redux/app/selectors/currentList.test.js +5 -3
  86. package/src/data/redux/app/selectors/simpleSelectors.test.js +1 -1
  87. package/src/data/redux/requests/reducer.test.js +1 -1
  88. package/src/data/redux/requests/selectors.js +1 -2
  89. package/src/data/redux/requests/selectors.test.js +1 -29
  90. package/src/data/services/lms/api.test.js +6 -6
  91. package/src/data/services/lms/urls.test.js +1 -1
  92. package/src/data/services/segment/utils.test.js +1 -1
  93. package/src/data/store.test.js +2 -2
  94. package/src/hooks/api.test.js +59 -64
  95. package/src/hooks/utils.test.js +4 -0
  96. package/src/segment.js +1 -2
  97. package/src/setupTest.jsx +0 -206
  98. package/src/slots/WidgetSidebarSlot/index.test.jsx +21 -11
  99. package/src/test/app.test.jsx +65 -75
  100. package/src/test/inspector.js +0 -6
  101. package/src/test/messages.js +1 -1
  102. package/src/testUtils.js +1 -1
  103. package/src/tracking/trackers/course.test.js +4 -4
  104. package/src/tracking/trackers/credit.test.js +5 -5
  105. package/src/tracking/trackers/engagement.test.js +3 -3
  106. package/src/tracking/trackers/entitlements.test.js +3 -3
  107. package/src/tracking/trackers/filter.test.js +3 -3
  108. package/src/tracking/trackers/findCourses.test.js +3 -3
  109. package/src/tracking/trackers/socialShare.test.js +2 -2
  110. package/src/utils/StrictDict.test.js +4 -12
  111. package/src/widgets/LearnerDashboardHeader/ConfirmEmailBanner/messages.js +1 -1
  112. package/src/widgets/LearnerDashboardHeader/MasqueradeBar/index.scss +10 -12
  113. package/src/widgets/LearnerDashboardHeader/hooks.js +1 -1
  114. package/src/widgets/LookingForChallengeWidget/index.test.jsx +22 -8
  115. package/src/__snapshots__/App.test.jsx.snap +0 -83
  116. package/src/__snapshots__/index.test.jsx.snap +0 -43
  117. package/src/components/__snapshots__/Banner.test.jsx.snap +0 -31
  118. package/src/containers/CourseCard/__snapshots__/index.test.jsx.snap +0 -111
  119. package/src/containers/CourseCard/components/CourseCardActions/ActionButton/__snapshots__/index.test.jsx.snap +0 -14
  120. package/src/containers/CourseCard/components/CourseCardActions/__snapshots__/BeginCourseButton.test.jsx.snap +0 -39
  121. package/src/containers/CourseCard/components/CourseCardActions/__snapshots__/ResumeButton.test.jsx.snap +0 -39
  122. package/src/containers/CourseCard/components/CourseCardActions/__snapshots__/SelectSessionButton.test.jsx.snap +0 -19
  123. package/src/containers/CourseCard/components/CourseCardActions/__snapshots__/ViewCourseButton.test.jsx.snap +0 -39
  124. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/__snapshots__/index.test.jsx.snap +0 -58
  125. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/CreditRequestForm/__snapshots__/index.test.jsx.snap +0 -32
  126. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/__snapshots__/CreditContent.test.jsx.snap +0 -60
  127. package/src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/__snapshots__/ProviderLink.test.jsx.snap +0 -11
  128. package/src/containers/CourseCard/components/CourseCardBanners/RelatedProgramsBanner/__snapshots__/ProgramsList.test.jsx.snap +0 -28
  129. package/src/containers/CourseCard/components/CourseCardBanners/RelatedProgramsBanner/__snapshots__/index.test.jsx.snap +0 -29
  130. package/src/containers/CourseCard/components/CourseCardBanners/__snapshots__/CertificateBanner.test.jsx.snap +0 -205
  131. package/src/containers/CourseCard/components/CourseCardBanners/__snapshots__/CourseBanner.test.jsx.snap +0 -38
  132. package/src/containers/CourseCard/components/CourseCardBanners/__snapshots__/EntitlementBanner.test.jsx.snap +0 -53
  133. package/src/containers/CourseCard/components/CourseCardBanners/__snapshots__/index.test.jsx.snap +0 -41
  134. package/src/containers/CourseCard/components/CourseCardDetails/__snapshots__/index.test.jsx.snap +0 -56
  135. package/src/containers/CourseCard/components/CourseCardMenu/__snapshots__/index.test.jsx.snap +0 -81
  136. package/src/containers/CourseCard/components/RelatedProgramsBadge/__snapshots__/index.test.jsx.snap +0 -25
  137. package/src/containers/CourseCard/components/__snapshots__/CourseCardImage.test.jsx.snap +0 -72
  138. package/src/containers/CourseCard/components/__snapshots__/CourseCardTitle.test.jsx.snap +0 -33
  139. package/src/containers/CourseFilterControls/__snapshots__/ActiveCourseFilters.test.jsx.snap +0 -39
  140. package/src/containers/CourseFilterControls/__snapshots__/CourseFilterControls.test.jsx.snap +0 -169
  141. package/src/containers/CourseFilterControls/components/__snapshots__/Checkbox.test.jsx.snap +0 -46
  142. package/src/containers/CourseFilterControls/components/__snapshots__/FilterForm.test.jsx.snap +0 -41
  143. package/src/containers/CourseFilterControls/components/__snapshots__/SortForm.test.jsx.snap +0 -29
  144. package/src/containers/CoursesPanel/CourseList/__snapshots__/index.test.jsx.snap +0 -70
  145. package/src/containers/CoursesPanel/NoCoursesView/__snapshots__/index.test.jsx.snap +0 -29
  146. package/src/containers/CoursesPanel/__snapshots__/index.test.jsx.snap +0 -55
  147. package/src/containers/Dashboard/__snapshots__/DashboardLayout.test.jsx.snap +0 -197
  148. package/src/containers/Dashboard/__snapshots__/LoadingView.test.jsx.snap +0 -13
  149. package/src/containers/Dashboard/__snapshots__/index.test.jsx.snap +0 -69
  150. package/src/containers/EmailSettingsModal/__snapshots__/index.test.jsx.snap +0 -133
  151. package/src/containers/RelatedProgramsModal/__snapshots__/index.test.jsx.snap +0 -169
  152. package/src/containers/RelatedProgramsModal/components/__snapshots__/ProgramCard.test.jsx.snap +0 -60
  153. package/src/containers/SelectSessionModal/__snapshots__/index.test.jsx.snap +0 -176
  154. package/src/containers/UnenrollConfirmModal/__snapshots__/index.test.jsx.snap +0 -101
  155. package/src/containers/UnenrollConfirmModal/components/__snapshots__/ConfirmPane.test.jsx.snap +0 -22
  156. package/src/containers/UnenrollConfirmModal/components/__snapshots__/FinishedPane.test.jsx.snap +0 -38
  157. package/src/containers/UnenrollConfirmModal/components/__snapshots__/ReasonPane.test.jsx.snap +0 -183
  158. package/src/slots/WidgetSidebarSlot/__snapshots__/index.test.jsx.snap +0 -14
  159. package/src/widgets/LookingForChallengeWidget/__snapshots__/index.test.jsx.snap +0 -45
@@ -1,11 +1,12 @@
1
- import React from 'react';
2
- import { shallow } from '@edx/react-unit-test-utils';
1
+ import { render, screen } from '@testing-library/react';
2
+ import { IntlProvider } from '@openedx/frontend-base';
3
+ import { formatMessage } from '@src/testUtils';
3
4
 
4
- import { reduxHooks } from 'hooks';
5
+ import { reduxHooks } from '@src/hooks';
5
6
  import EntitlementBanner from './EntitlementBanner';
7
+ import messages from './messages';
6
8
 
7
- jest.mock('components/Banner', () => 'Banner');
8
- jest.mock('hooks', () => ({
9
+ jest.mock('@src/hooks', () => ({
9
10
  utilHooks: {
10
11
  useFormatDate: () => date => date,
11
12
  },
@@ -18,9 +19,7 @@ jest.mock('hooks', () => ({
18
19
  },
19
20
  }));
20
21
 
21
- const cardId = 'my-test-course-number';
22
-
23
- let el;
22
+ const cardId = 'test-card-id';
24
23
 
25
24
  const entitlementData = {
26
25
  isEntitlement: true,
@@ -31,33 +30,43 @@ const entitlementData = {
31
30
  };
32
31
  const platformData = { supportEmail: 'test-support-email' };
33
32
 
34
- const render = (overrides = {}) => {
33
+ const renderComponent = (overrides = {}) => {
35
34
  const { entitlement = {} } = overrides;
36
35
  reduxHooks.useCardEntitlementData.mockReturnValueOnce({ ...entitlementData, ...entitlement });
37
36
  reduxHooks.usePlatformSettingsData.mockReturnValueOnce(platformData);
38
- el = shallow(<EntitlementBanner cardId={cardId} />);
37
+ return render(<IntlProvider locale="en"><EntitlementBanner cardId={cardId} /></IntlProvider>);
39
38
  };
40
39
 
41
40
  describe('EntitlementBanner', () => {
42
- test('initializes data with course number from entitlement', () => {
43
- render();
41
+ it('initializes data with course number from entitlement', () => {
42
+ renderComponent();
44
43
  expect(reduxHooks.useCardEntitlementData).toHaveBeenCalledWith(cardId);
45
44
  expect(reduxHooks.useUpdateSelectSessionModalCallback).toHaveBeenCalledWith(cardId);
46
45
  });
47
- test('no display if not an entitlement', () => {
48
- render({ entitlement: { isEntitlement: false } });
49
- expect(el.isEmptyRender()).toEqual(true);
46
+ it('no display if not an entitlement', () => {
47
+ renderComponent({ entitlement: { isEntitlement: false } });
48
+ const banner = screen.queryByRole('alert');
49
+ expect(banner).toBeNull();
50
50
  });
51
- test('snapshot: no sessions available', () => {
52
- render({ entitlement: { isFulfilled: false, hasSessions: false } });
53
- expect(el.snapshot).toMatchSnapshot();
51
+ it('renders when no sessions available', () => {
52
+ renderComponent({ entitlement: { isFulfilled: false, hasSessions: false } });
53
+ const banner = screen.getByRole('alert');
54
+ expect(banner).toBeInTheDocument();
55
+ expect(banner).toHaveClass('alert-warning');
56
+ expect(banner.innerHTML).toContain(platformData.supportEmail);
54
57
  });
55
- test('snapshot: expiration warning', () => {
56
- render({ entitlement: { showExpirationWarning: true } });
57
- expect(el.snapshot).toMatchSnapshot();
58
+ it('renders when expiration warning', () => {
59
+ renderComponent({ entitlement: { showExpirationWarning: true } });
60
+ const banner = screen.getByRole('alert');
61
+ expect(banner).toBeInTheDocument();
62
+ expect(banner).toHaveClass('alert-info');
63
+ const button = screen.getByRole('button', { name: formatMessage(messages.selectSession) });
64
+ expect(button).toBeInTheDocument();
58
65
  });
59
- test('no display if sessions available and not displaying warning', () => {
60
- render();
61
- expect(el.isEmptyRender()).toEqual(true);
66
+ it('renders expired banner', () => {
67
+ renderComponent({ entitlement: { isExpired: true } });
68
+ const banner = screen.getByRole('alert');
69
+ expect(banner).toBeInTheDocument();
70
+ expect(banner.innerHTML).toContain(formatMessage(messages.entitlementExpired));
62
71
  });
63
72
  });
@@ -1,4 +1,4 @@
1
- import { shallow } from '@edx/react-unit-test-utils';
1
+ import { render, screen } from '@testing-library/react';
2
2
 
3
3
  import { ProgramsList } from './ProgramsList';
4
4
 
@@ -9,15 +9,23 @@ describe('ProgramsList', () => {
9
9
  title: 'Example Program 1',
10
10
  },
11
11
  {
12
- programUrl: 'http://example.com',
12
+ programUrl: 'http://example2.com',
13
13
  title: 'Example Program 2',
14
14
  },
15
15
  ];
16
16
 
17
17
  it('renders correctly', () => {
18
- const wrapper = shallow(<ProgramsList programs={programs} />);
19
- expect(wrapper.snapshot).toMatchSnapshot();
18
+ render(<ProgramsList programs={programs} />);
19
+ const list = screen.getByRole('list');
20
+ expect(list).toBeInTheDocument();
21
+ expect(list.children.length).toEqual(programs.length);
22
+ });
20
23
 
21
- expect(wrapper.instance.findByType('li').length).toEqual(programs.length);
24
+ it('add the links correctly', () => {
25
+ render(<ProgramsList programs={programs} />);
26
+ programs.forEach(program => {
27
+ const link = screen.getByRole('link', { name: program.title });
28
+ expect(link).toHaveAttribute('href', program.url);
29
+ });
22
30
  });
23
31
  });
@@ -1,42 +1,49 @@
1
- import { shallow } from '@edx/react-unit-test-utils';
1
+ import { render, screen } from '@testing-library/react';
2
+ import { IntlProvider } from '@openedx/frontend-base';
2
3
 
3
- import { reduxHooks } from '../../../../../hooks';
4
+ import { reduxHooks } from '@src/hooks';
4
5
  import RelatedProgramsBanner from '.';
5
6
 
6
- jest.mock('./ProgramsList', () => 'ProgramsList');
7
-
8
- jest.mock('hooks', () => ({
7
+ jest.mock('@src/hooks', () => ({
9
8
  reduxHooks: {
10
9
  useCardRelatedProgramsData: jest.fn(),
11
10
  },
12
11
  }));
13
12
 
14
13
  const cardId = 'test-card-id';
14
+ const programData = {
15
+ list: [
16
+ {
17
+ title: 'Program 1',
18
+ url: 'http://example.com/program1',
19
+ },
20
+ {
21
+ title: 'Program 2',
22
+ url: 'http://example.com/program2',
23
+ },
24
+ ],
25
+ length: 2,
26
+ };
15
27
 
16
28
  describe('RelatedProgramsBanner', () => {
17
- test('render empty', () => {
18
- reduxHooks.useCardRelatedProgramsData.mockReturnValue({
19
- length: 0,
20
- });
21
- const el = shallow(<RelatedProgramsBanner cardId={cardId} />);
22
- expect(el.isEmptyRender()).toEqual(true);
29
+ it('render empty', () => {
30
+ reduxHooks.useCardRelatedProgramsData.mockReturnValue({});
31
+ render(<IntlProvider locale="en"><RelatedProgramsBanner cardId={cardId} /></IntlProvider>);
32
+ const banner = screen.queryByRole('alert');
33
+ expect(banner).toBeNull();
34
+ });
35
+
36
+ it('render with programs', () => {
37
+ reduxHooks.useCardRelatedProgramsData.mockReturnValue(programData);
38
+ render(<IntlProvider locale="en"><RelatedProgramsBanner cardId={cardId} /></IntlProvider>);
39
+ const list = screen.getByRole('list');
40
+ expect(list.childElementCount).toBe(programData.list.length);
23
41
  });
24
42
 
25
- test('render with programs', () => {
26
- reduxHooks.useCardRelatedProgramsData.mockReturnValue({
27
- list: [
28
- {
29
- title: 'Program 1',
30
- url: 'http://example.com/program1',
31
- },
32
- {
33
- title: 'Program 2',
34
- url: 'http://example.com/program2',
35
- },
36
- ],
37
- length: 2,
38
- });
39
- const el = shallow(<RelatedProgramsBanner cardId={cardId} />);
40
- expect(el.snapshot).toMatchSnapshot();
43
+ it('render related programs title', () => {
44
+ reduxHooks.useCardRelatedProgramsData.mockReturnValue(programData);
45
+ render(<IntlProvider locale="en"><RelatedProgramsBanner cardId={cardId} /></IntlProvider>);
46
+ const title = screen.getByText('Related Programs:');
47
+ expect(title).toBeInTheDocument();
41
48
  });
42
49
  });
@@ -1,16 +1,25 @@
1
- import { shallow } from '@edx/react-unit-test-utils';
2
-
3
- import { reduxHooks } from 'hooks';
1
+ import { render, screen } from '@testing-library/react';
2
+ import { IntlProvider } from '@openedx/frontend-base';
3
+ import { MemoryRouter } from 'react-router-dom';
4
4
 
5
+ import { reduxHooks } from '@src/hooks';
5
6
  import CourseCardBanners from '.';
6
7
 
7
- jest.mock('./CourseBanner', () => 'CourseBanner');
8
- jest.mock('./CertificateBanner', () => 'CertificateBanner');
9
- jest.mock('./CreditBanner', () => 'CreditBanner');
10
- jest.mock('./EntitlementBanner', () => 'EntitlementBanner');
11
- jest.mock('./RelatedProgramsBanner', () => 'RelatedProgramsBanner');
8
+ jest.mock('./CourseBanner', () => jest.fn(() => <div>CourseBanner</div>));
9
+ jest.mock('./CertificateBanner', () => jest.fn(() => <div>CertificateBanner</div>));
10
+ jest.mock('./CreditBanner', () => jest.fn(() => <div>CreditBanner</div>));
11
+ jest.mock('./EntitlementBanner', () => jest.fn(() => <div>EntitlementBanner</div>));
12
+ jest.mock('./RelatedProgramsBanner', () => jest.fn(() => <div>RelatedProgramsBanner</div>));
13
+
14
+ const mockedComponents = [
15
+ 'CourseBanner',
16
+ 'CertificateBanner',
17
+ 'CreditBanner',
18
+ 'EntitlementBanner',
19
+ 'RelatedProgramsBanner',
20
+ ];
12
21
 
13
- jest.mock('hooks', () => ({
22
+ jest.mock('@src/hooks', () => ({
14
23
  reduxHooks: {
15
24
  useCardEnrollmentData: jest.fn(() => ({ isEnrolled: true })),
16
25
  },
@@ -20,13 +29,33 @@ describe('CourseCardBanners', () => {
20
29
  const props = {
21
30
  cardId: 'test-card-id',
22
31
  };
23
- test('renders default CourseCardBanners', () => {
24
- const wrapper = shallow(<CourseCardBanners {...props} />);
25
- expect(wrapper.snapshot).toMatchSnapshot();
32
+ it('renders default CourseCardBanners', () => {
33
+ reduxHooks.useCardEnrollmentData.mockReturnValueOnce({ isEnrolled: true });
34
+ render(
35
+ <MemoryRouter>
36
+ <IntlProvider locale="en">
37
+ <CourseCardBanners {...props} />
38
+ </IntlProvider>
39
+ </MemoryRouter>
40
+ );
41
+ mockedComponents.map((componentName) => {
42
+ const mockedComponent = screen.getByText(componentName);
43
+ return expect(mockedComponent).toBeInTheDocument();
44
+ });
26
45
  });
27
- test('render with isEnrolled false', () => {
46
+ it('render with isEnrolled false', () => {
28
47
  reduxHooks.useCardEnrollmentData.mockReturnValueOnce({ isEnrolled: false });
29
- const wrapper = shallow(<CourseCardBanners {...props} />);
30
- expect(wrapper.snapshot).toMatchSnapshot();
48
+ render(
49
+ <MemoryRouter>
50
+ <IntlProvider locale="en">
51
+ <CourseCardBanners {...props} />
52
+ </IntlProvider>
53
+ </MemoryRouter>
54
+ );
55
+ const mockedComponentsIfNotEnrolled = mockedComponents.slice(-2);
56
+ mockedComponentsIfNotEnrolled.map((componentName) => {
57
+ const mockedComponent = screen.getByText(componentName);
58
+ return expect(mockedComponent).toBeInTheDocument();
59
+ });
31
60
  });
32
61
  });
@@ -1,12 +1,11 @@
1
1
  import { useIntl } from '@openedx/frontend-base';
2
2
 
3
- import { keyStore } from 'utils';
4
- import { utilHooks, reduxHooks } from 'hooks';
5
-
3
+ import { keyStore } from '@src/utils';
4
+ import { utilHooks, reduxHooks } from '@src/hooks';
6
5
  import * as hooks from './hooks';
7
6
  import messages from './messages';
8
7
 
9
- jest.mock('hooks', () => ({
8
+ jest.mock('@src/hooks', () => ({
10
9
  utilHooks: {
11
10
  useFormatDate: jest.fn(),
12
11
  },
@@ -20,6 +19,16 @@ jest.mock('hooks', () => ({
20
19
  },
21
20
  }));
22
21
 
22
+ jest.mock('@openedx/frontend-base', () => {
23
+ const { formatMessage } = jest.requireActual('@src/testUtils');
24
+ return {
25
+ ...jest.requireActual('@openedx/frontend-base'),
26
+ useIntl: () => ({
27
+ formatMessage,
28
+ }),
29
+ };
30
+ });
31
+
23
32
  const cardId = 'my-test-card-id';
24
33
  const courseNumber = 'test-course-number';
25
34
  const useAccessMessage = 'test-access-message';
@@ -36,9 +45,8 @@ describe('CourseCardDetails hooks', () => {
36
45
  });
37
46
 
38
47
  describe('useCardDetailsData', () => {
39
- const providerData = {
40
- name: 'my-provider-name',
41
- };
48
+ const providerName = 'my-provider-name';
49
+ const providerData = {};
42
50
  const entitlementData = {
43
51
  isEntitlement: false,
44
52
  disableViewCourse: false,
@@ -68,8 +76,10 @@ describe('CourseCardDetails hooks', () => {
68
76
  expect(out.accessMessage).toEqual(mockAccessMessage({ cardId }));
69
77
  });
70
78
  it('forwards provider name if it exists, else formatted unknown provider name', () => {
71
- expect(out.providerName).toEqual(providerData.name);
72
- runHook({ provider: { name: '' } });
79
+ runHook({ provider: { name: providerName } });
80
+ expect(out.providerName).toEqual(providerName);
81
+
82
+ runHook({ provider: {} });
73
83
  expect(out.providerName).toEqual(formatMessage(messages.unknownProviderName));
74
84
  });
75
85
  it('forward changeOrLeaveSessionMessage', () => {
@@ -1,7 +1,3 @@
1
- @import "~@edx/brand/paragon/variables";
2
- @import "~@openedx/paragon/scss/core/core";
3
- @import "~@edx/brand/paragon/overrides";
4
-
5
1
  a.course-card-title {
6
- color: $black;
2
+ color: var(--pgn-color-black);
7
3
  }
@@ -1,5 +1,4 @@
1
- import React from 'react';
2
- import { render } from '@testing-library/react';
1
+ import { render, screen } from '@testing-library/react';
3
2
 
4
3
  import CourseCardDetails from '.';
5
4
 
@@ -48,23 +47,36 @@ describe('CourseCard Details component', () => {
48
47
  return separatorsCount;
49
48
  };
50
49
 
51
- test('has change session button on entitlement course', () => {
50
+ it('has change session button on entitlement course', () => {
52
51
  const wrapper = createWrapper();
53
- expect(wrapper.container).toMatchSnapshot();
52
+ const sessionButton = screen.getByRole('button', { name: defaultHooks.changeOrLeaveSessionMessage });
53
+ expect(sessionButton).toBeInTheDocument();
54
+
55
+ const accessMessage = screen.getByText((text) => text.includes(defaultHooks.accessMessage));
56
+ expect(accessMessage).toBeInTheDocument();
54
57
  // it has 3 separator, 4 column
55
58
  expect(fetchSeparators(wrapper)).toBe(3);
56
59
  });
57
60
 
58
- test('has change session button on entitlement course but no access message', () => {
61
+ it('has change session button on entitlement course but no access message', () => {
59
62
  const wrapper = createWrapper({ accessMessage: null });
60
- expect(wrapper.container).toMatchSnapshot();
63
+ const sessionButton = screen.getByRole('button', { name: defaultHooks.changeOrLeaveSessionMessage });
64
+ expect(sessionButton).toBeInTheDocument();
65
+
66
+ const accessMessage = screen.queryByText((text) => text.includes(defaultHooks.accessMessage));
67
+ expect(accessMessage).toBeNull();
68
+
61
69
  // it has 2 separator, 3 column
62
70
  expect(fetchSeparators(wrapper)).toBe(2);
63
71
  });
64
72
 
65
- test('does not have change session button on regular course', () => {
73
+ it('does not have change session button on regular course', () => {
66
74
  const wrapper = createWrapper({ isEntitlement: false });
67
- expect(wrapper.container).toMatchSnapshot();
75
+ const sessionButton = screen.queryByRole('button', { name: defaultHooks.changeOrLeaveSessionMessage });
76
+ expect(sessionButton).toBeNull();
77
+
78
+ const accessMessage = screen.getByText((text) => text.includes(defaultHooks.accessMessage));
79
+ expect(accessMessage).toBeInTheDocument();
68
80
  // it has 2 separator, 3 column
69
81
  expect(fetchSeparators(wrapper)).toBe(2);
70
82
  });
@@ -1,61 +1,68 @@
1
- import { shallow } from '@edx/react-unit-test-utils';
2
-
3
- import { reduxHooks } from 'hooks';
4
- import track from 'tracking';
1
+ import { render, screen } from '@testing-library/react';
2
+ import { IntlProvider } from '@openedx/frontend-base';
3
+ import { formatMessage } from '@src/testUtils';
4
+ import { reduxHooks } from '@src/hooks';
5
5
  import useActionDisabledState from './hooks';
6
- import CourseCardImage from './CourseCardImage';
7
-
8
- const homeUrl = 'home-url';
6
+ import { CourseCardImage } from './CourseCardImage';
7
+ import messages from '../messages';
9
8
 
10
- jest.mock('tracking', () => ({
11
- course: {
12
- courseImageClicked: jest.fn().mockName('segment.courseImageClicked'),
13
- },
14
- }));
9
+ const homeUrl = 'https://example.com';
10
+ const bannerImgSrc = 'banner-img-src.jpg';
15
11
 
16
- jest.mock('hooks', () => ({
12
+ jest.mock('@src/hooks', () => ({
17
13
  reduxHooks: {
18
- useCardCourseData: jest.fn(() => ({ bannerImgSrc: 'banner-img-src' })),
14
+ useCardCourseData: jest.fn(() => ({ bannerImgSrc })),
19
15
  useCardCourseRunData: jest.fn(() => ({ homeUrl })),
20
- useCardEnrollmentData: jest.fn(() => ({ isVerified: true })),
16
+ useCardEnrollmentData: jest.fn(),
21
17
  useTrackCourseEvent: jest.fn((eventName, cardId, url) => ({
22
18
  trackCourseEvent: { eventName, cardId, url },
23
19
  })),
24
20
  },
25
21
  }));
26
- jest.mock('./hooks', () => jest.fn(() => ({ disableCourseTitle: false })));
22
+
23
+ jest.mock('./hooks', () => jest.fn());
27
24
 
28
25
  describe('CourseCardImage', () => {
29
26
  const props = {
30
- cardId: 'cardId',
31
- orientation: 'orientation',
27
+ cardId: 'test-card-id',
28
+ orientation: 'horizontal',
32
29
  };
33
- beforeEach(() => {
34
- jest.clearAllMocks();
30
+
31
+ it('renders course image with correct attributes', () => {
32
+ useActionDisabledState.mockReturnValue({ disableCourseTitle: true });
33
+ reduxHooks.useCardEnrollmentData.mockReturnValue({ isVerified: true });
34
+ render(<IntlProvider locale="en"><CourseCardImage {...props} /></IntlProvider>);
35
+
36
+ const image = screen.getByRole('img', { name: formatMessage(messages.bannerAlt) });
37
+ expect(image).toBeInTheDocument();
38
+ expect(image.src).toContain(bannerImgSrc);
39
+ expect(image.parentElement).toHaveClass('horizontal');
35
40
  });
36
- describe('snapshot', () => {
37
- test('renders clickable link course Image', () => {
38
- const wrapper = shallow(<CourseCardImage {...props} />);
39
- expect(wrapper.snapshot).toMatchSnapshot();
40
- expect(wrapper.instance.type).toBe('a');
41
- expect(wrapper.instance.props.onClick).toEqual(
42
- reduxHooks.useTrackCourseEvent(
43
- track.course.courseImageClicked,
44
- props.cardId,
45
- homeUrl,
46
- ),
47
- );
48
- });
49
- test('renders disabled link', () => {
50
- useActionDisabledState.mockReturnValueOnce({ disableCourseTitle: true });
51
- const wrapper = shallow(<CourseCardImage {...props} />);
52
- expect(wrapper.snapshot).toMatchSnapshot();
53
- expect(wrapper.instance.type).toBe('div');
54
- });
41
+
42
+ it('isVerified, should render badge', () => {
43
+ useActionDisabledState.mockReturnValue({ disableCourseTitle: false });
44
+ reduxHooks.useCardEnrollmentData.mockReturnValue({ isVerified: true });
45
+ render(<IntlProvider locale="en"><CourseCardImage {...props} /></IntlProvider>);
46
+
47
+ const badge = screen.getByText(formatMessage(messages.verifiedBanner));
48
+ expect(badge).toBeInTheDocument();
49
+ const badgeImg = screen.getByRole('img', { name: formatMessage(messages.verifiedBannerRibbonAlt) });
50
+ expect(badgeImg).toBeInTheDocument();
51
+ });
52
+
53
+ it('renders link with correct href if disableCourseTitle is false', () => {
54
+ useActionDisabledState.mockReturnValue({ disableCourseTitle: false });
55
+ reduxHooks.useCardEnrollmentData.mockReturnValue({ isVerified: false });
56
+ render(<IntlProvider locale="en"><CourseCardImage {...props} /></IntlProvider>);
57
+
58
+ const link = screen.getByRole('link');
59
+ expect(link).toHaveAttribute('href', homeUrl);
55
60
  });
56
- describe('behavior', () => {
61
+ describe('hooks', () => {
57
62
  it('initializes', () => {
58
- shallow(<CourseCardImage {...props} />);
63
+ useActionDisabledState.mockReturnValue({ disableCourseTitle: false });
64
+ reduxHooks.useCardEnrollmentData.mockReturnValue({ isVerified: true });
65
+ render(<IntlProvider locale="en"><CourseCardImage {...props} /></IntlProvider>);
59
66
  expect(reduxHooks.useCardCourseData).toHaveBeenCalledWith(props.cardId);
60
67
  expect(reduxHooks.useCardCourseRunData).toHaveBeenCalledWith(
61
68
  props.cardId,
@@ -1,8 +1,7 @@
1
- import React from 'react';
1
+ import { useContext } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import * as ReactShare from 'react-share';
4
4
 
5
- import { StrictDict } from '@edx/react-unit-test-utils';
6
5
  import { useIntl } from '@openedx/frontend-base';
7
6
  import { Dropdown } from '@openedx/paragon';
8
7
 
@@ -12,9 +11,9 @@ import { reduxHooks } from '../../../../hooks';
12
11
 
13
12
  import messages from './messages';
14
13
 
15
- export const testIds = StrictDict({
14
+ export const testIds = {
16
15
  emailSettingsModalToggle: 'emailSettingsModalToggle',
17
- });
16
+ };
18
17
 
19
18
  export const SocialShareMenu = ({ cardId, emailSettings }) => {
20
19
  const { formatMessage } = useIntl();