@openedx/frontend-app-learner-dashboard 1.0.0-alpha.3 → 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,5 +1,4 @@
1
- import { shallow } from '@edx/react-unit-test-utils';
2
- import { Spinner } from '@openedx/paragon';
1
+ import { render, screen } from '@testing-library/react';
3
2
 
4
3
  import hooks from './hooks';
5
4
  import LoadingView from './LoadingView';
@@ -10,14 +9,10 @@ jest.mock('./hooks', () => ({
10
9
 
11
10
  const spinnerScreenReaderText = 'test-sr-text';
12
11
  describe('LoadingView', () => {
13
- beforeEach(() => {
14
- hooks.useDashboardMessages.mockReturnValueOnce({ spinnerScreenReaderText });
15
- });
16
- test('snapshot', () => {
17
- expect(shallow(<LoadingView />).snapshot).toMatchSnapshot();
18
- });
19
12
  it('renders spinner component with associated screen reader text', () => {
20
- const wrapper = shallow(<LoadingView />);
21
- expect(wrapper.instance.findByType(Spinner)[0].props.screenReaderText).toEqual(spinnerScreenReaderText);
13
+ hooks.useDashboardMessages.mockReturnValueOnce({ spinnerScreenReaderText });
14
+ render(<LoadingView />);
15
+ const loader = screen.getByRole('status');
16
+ expect(loader.children[0].innerHTML).toBe(spinnerScreenReaderText);
22
17
  });
23
18
  });
@@ -1,25 +1,37 @@
1
- import React from 'react';
2
-
3
1
  import { useIntl } from '@openedx/frontend-base';
4
2
  import { useWindowSize, breakpoints } from '@openedx/paragon';
3
+ import { apiHooks } from '@src/hooks';
4
+ import { MockUseState } from '@src/testUtils';
5
5
 
6
- import { apiHooks } from 'hooks';
7
- import { MockUseState } from 'testUtils';
8
-
9
- import appMessages from 'messages';
6
+ import appMessages from '@src/messages';
10
7
  import * as hooks from './hooks';
11
8
 
12
9
  jest.mock('@openedx/paragon', () => ({
10
+ ...jest.requireActual('@openedx/paragon'),
13
11
  useWindowSize: jest.fn(),
14
12
  breakpoints: {},
15
13
  }));
16
14
 
17
- jest.mock('hooks', () => ({
15
+ jest.mock('@openedx/frontend-base', () => {
16
+ const { formatMessage } = jest.requireActual('@src/testUtils');
17
+ return {
18
+ ...jest.requireActual('@openedx/frontend-base',),
19
+ useIntl: () => ({
20
+ formatMessage,
21
+ }),
22
+ };
23
+ });
24
+
25
+ jest.mock('@src/hooks', () => ({
18
26
  apiHooks: {
19
27
  useInitializeApp: jest.fn(),
20
28
  },
21
29
  }));
22
30
 
31
+ jest.mock('react', () => ({
32
+ ...jest.requireActual('react'),
33
+ useEffect: jest.fn((cb, prereqs) => ({ useEffect: { cb, prereqs } })),
34
+ }));
23
35
  const state = new MockUseState(hooks);
24
36
 
25
37
  const initializeApp = jest.fn();
@@ -63,24 +75,14 @@ describe('CourseCard hooks', () => {
63
75
  });
64
76
  });
65
77
  });
66
- describe('useInitializeDashboard', () => {
67
- it('dispatches initialize thunk action on component load', () => {
68
- hooks.useInitializeDashboard();
69
- const [cb, prereqs] = React.useEffect.mock.calls[0];
70
- expect(prereqs).toEqual([]);
71
- expect(initializeApp).not.toHaveBeenCalled();
72
- cb();
73
- expect(initializeApp).toHaveBeenCalledWith();
74
- });
75
- });
76
78
  describe('useDashboardMessages', () => {
77
79
  it('returns spinner screen reader text', () => {
78
- expect(hooks.useDashboardMessages()['learner-dash.loadingSR']).toEqual(
80
+ expect(hooks.useDashboardMessages().spinnerScreenReaderText).toEqual(
79
81
  formatMessage(appMessages['learner-dash.loadingSR']),
80
82
  );
81
83
  });
82
84
  it('returns page title', () => {
83
- expect(hooks.useDashboardMessages()['learner-dash.title']).toEqual(
85
+ expect(hooks.useDashboardMessages().pageTitle).toEqual(
84
86
  formatMessage(appMessages['learner-dash.title']),
85
87
  );
86
88
  });
@@ -1,29 +1,27 @@
1
- @import "@openedx/paragon/scss/core/core";
2
-
3
1
  .course-list-column {
4
- padding: 0 map-get($spacers, 4);
2
+ padding: 0 var(--pgn-spacing-spacer-4);
5
3
  }
6
4
 
7
5
  .sidebar-column {
8
- padding: 0 map-get($spacers, 3) 0 map-get($spacers, 1);
6
+ padding: 0 var(--pgn-spacing-spacer-3) 0 var(--pgn-spacing-spacer-1);
9
7
 
10
8
  &.not-collapsed {
11
- padding-top: map-get($spacers, 2);
9
+ padding-top: var(--pgn-spacing-spacer-2);
12
10
 
13
11
  & >:first-child {
14
- margin-top: map-get($spacers, 5\.5);
12
+ margin-top: var(--pgn-spacing-spacer-5-5);
15
13
  }
16
14
  }
17
15
  }
18
16
 
19
- @include media-breakpoint-down(lg) {
17
+ @media (--pgn-size-breakpoint-max-width-lg) {
20
18
  .sidebar-column {
21
19
  // grid are inheriting dir="ltr" from the body, so we need to override it
22
20
  [dir=ltr] & {
23
- padding: 0 map-get($spacers, 3);
21
+ padding: 0 var(--pgn-spacing-spacer-3);
24
22
  }
25
23
  [dir=rtl] & {
26
- padding: 0 map-get($spacers, 3);
24
+ padding: 0 var(--pgn-spacing-spacer-3);
27
25
  }
28
26
  }
29
- }
27
+ }
@@ -1,121 +1,80 @@
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
-
5
- import SelectSessionModal from 'containers/SelectSessionModal';
6
- import CoursesPanel from 'containers/CoursesPanel';
7
-
8
- import DashboardLayout from './DashboardLayout';
9
- import LoadingView from './LoadingView';
4
+ import { reduxHooks, apiHooks } from '@src/hooks';
10
5
  import hooks from './hooks';
11
- import Dashboard from '.';
6
+ import Dashboard from './';
12
7
 
13
- jest.mock('hooks', () => ({
8
+ jest.mock('@src/hooks', () => ({
14
9
  reduxHooks: {
15
10
  useHasCourses: jest.fn(),
16
11
  useShowSelectSessionModal: jest.fn(),
17
12
  useRequestIsPending: jest.fn(),
18
13
  },
14
+ apiHooks: {
15
+ useInitializeApp: jest.fn(),
16
+ },
19
17
  }));
20
18
 
21
- jest.mock('slots/DashboardModalSlot', () => 'DashboardModalSlot');
22
- jest.mock('containers/CoursesPanel', () => 'CoursesPanel');
23
- jest.mock('./LoadingView', () => 'LoadingView');
24
- jest.mock('./DashboardLayout', () => 'DashboardLayout');
25
-
26
19
  jest.mock('./hooks', () => ({
27
20
  useInitializeDashboard: jest.fn(),
28
21
  useDashboardMessages: jest.fn(),
29
22
  }));
30
23
 
24
+ jest.mock('../../slots/DashboardModalSlot', () => jest.fn(() => <div>DashboardModalSlot</div>));
25
+ jest.mock('@src/containers/CoursesPanel', () => jest.fn(() => <div>CoursesPanel</div>));
26
+ jest.mock('@src/containers/SelectSessionModal', () => jest.fn(() => <div>SelectSessionModal</div>));
27
+ jest.mock('./DashboardLayout', () => jest.fn(() => <div>DashboardLayout</div>));
28
+ jest.mock('./LoadingView', () => jest.fn(() => <div>LoadingView</div>));
29
+
31
30
  const pageTitle = 'test-page-title';
32
31
 
33
32
  describe('Dashboard', () => {
34
- beforeEach(() => {
33
+ const createWrapper = (props = {}) => {
34
+ const {
35
+ hasCourses = true,
36
+ initIsPending = true,
37
+ showSelectSessionModal = true,
38
+ } = props;
35
39
  hooks.useDashboardMessages.mockReturnValue({ pageTitle });
36
- });
37
- const createWrapper = ({
38
- hasCourses,
39
- initIsPending,
40
- showSelectSessionModal,
41
- }) => {
42
- reduxHooks.useHasCourses.mockReturnValueOnce(hasCourses);
43
- reduxHooks.useRequestIsPending.mockReturnValueOnce(initIsPending);
44
- reduxHooks.useShowSelectSessionModal.mockReturnValueOnce(showSelectSessionModal);
45
- return shallow(<Dashboard />);
40
+ apiHooks.useInitializeApp.mockReturnValue({ isPending: initIsPending });
41
+ reduxHooks.useHasCourses.mockReturnValue(hasCourses);
42
+ reduxHooks.useRequestIsPending.mockReturnValue(initIsPending);
43
+ reduxHooks.useShowSelectSessionModal.mockReturnValue(showSelectSessionModal);
44
+ return render(<IntlProvider locale="en"><Dashboard /></IntlProvider>);
46
45
  };
47
46
 
48
- let wrapper;
49
- describe('snapshots', () => {
50
- const testTitle = () => {
51
- test('page title is displayed in sr-only h1 tag', () => {
52
- const heading = wrapper.instance.findByType('h1')[0];
53
- expect(heading.props.className).toEqual('sr-only');
54
- expect(heading.children[0].el).toEqual(pageTitle);
55
- });
56
- };
57
- const testSnapshot = () => {
58
- test('snapshot', () => {
59
- expect(wrapper.snapshot).toMatchSnapshot();
60
- });
61
- };
62
- const testContent = (el) => {
63
- expect(wrapper.instance.findByTestId('dashboard-content')[0].children[0]).toMatchObject(shallow(el));
64
- };
65
-
66
- const renderString = (show) => (show ? 'renders' : 'does not render');
67
- const testView = ({
68
- props,
69
- content: [contentName, contentEl],
70
- showSelectSessionModal,
71
- }) => {
72
- beforeEach(() => { wrapper = createWrapper(props); });
73
- testTitle();
74
- testSnapshot();
75
- it(`renders ${contentName}`, () => {
76
- testContent(contentEl);
77
- });
78
- it(`${renderString(showSelectSessionModal)} select session modal`, () => {
79
- expect(wrapper.instance.findByType(SelectSessionModal).length).toEqual(showSelectSessionModal ? 1 : 0);
47
+ describe('render', () => {
48
+ it('page title is displayed in sr-only h1 tag', () => {
49
+ createWrapper();
50
+ const heading = screen.getByText(pageTitle);
51
+ expect(heading).toHaveClass('sr-only');
52
+ });
53
+ describe('initIsPending false', () => {
54
+ it('should render DashboardModalSlot', () => {
55
+ createWrapper({ initIsPending: false });
56
+ const dashboardModalSlot = screen.getByText('DashboardModalSlot');
57
+ expect(dashboardModalSlot).toBeInTheDocument();
80
58
  });
81
- };
82
- describe('courses still loading', () => {
83
- testView({
84
- props: {
85
- hasCourses: false,
86
- initIsPending: true,
87
- showSelectSessionModal: false,
88
- },
89
- content: ['LoadingView', <LoadingView />],
90
- showSelectSessionModal: false,
59
+ it('should render SelectSessionModal', () => {
60
+ createWrapper({ initIsPending: false });
61
+ const selectSessionModal = screen.getByText('SelectSessionModal');
62
+ expect(selectSessionModal).toBeInTheDocument();
91
63
  });
92
64
  });
93
-
94
- describe('courses loaded, show select session modal', () => {
95
- testView({
96
- props: {
97
- hasCourses: true,
98
- initIsPending: false,
99
- showSelectSessionModal: true,
100
- },
101
- content: ['LoadedView', (
102
- <DashboardLayout><CoursesPanel /></DashboardLayout>
103
- )],
104
- showSelectSessionModal: true,
65
+
66
+ describe('courses still loading', () => {
67
+ it('should render LoadingView', () => {
68
+ createWrapper({ initIsPending: true });
69
+ const loadingView = screen.getByText('LoadingView');
70
+ expect(loadingView).toBeInTheDocument();
105
71
  });
106
72
  });
107
-
108
- describe('there are no courses', () => {
109
- testView({
110
- props: {
111
- hasCourses: false,
112
- initIsPending: false,
113
- showSelectSessionModal: false,
114
- },
115
- content: ['Dashboard layout with no courses sidebar and content', (
116
- <DashboardLayout><CoursesPanel /></DashboardLayout>
117
- )],
118
- showSelectSessionModal: false,
73
+ describe('courses loaded', () => {
74
+ it('should show dashboard layout', () => {
75
+ createWrapper({ initIsPending: false });
76
+ const dashboardLayout = screen.getByText('DashboardLayout');
77
+ expect(dashboardLayout).toBeInTheDocument();
119
78
  });
120
79
  });
121
80
  });
@@ -1,9 +1,9 @@
1
- import { MockUseState } from 'testUtils';
2
- import { reduxHooks, apiHooks } from 'hooks';
1
+ import { MockUseState } from '@src/testUtils';
2
+ import { reduxHooks, apiHooks } from '@src/hooks';
3
3
 
4
4
  import * as hooks from './hooks';
5
5
 
6
- jest.mock('hooks', () => ({
6
+ jest.mock('@src/hooks', () => ({
7
7
  reduxHooks: {
8
8
  useCardEnrollmentData: jest.fn(),
9
9
  },
@@ -1,8 +1,9 @@
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
3
 
4
4
  import hooks from './hooks';
5
5
  import EmailSettingsModal from '.';
6
+ import messages from './messages';
6
7
 
7
8
  jest.mock('./hooks', () => ({
8
9
  __esModule: true,
@@ -28,7 +29,7 @@ describe('EmailSettingsModal', () => {
28
29
  describe('behavior', () => {
29
30
  beforeEach(() => {
30
31
  hooks.mockReturnValueOnce(hookProps);
31
- shallow(<EmailSettingsModal {...props} />);
32
+ render(<IntlProvider locale="en"><EmailSettingsModal {...props} /></IntlProvider>);
32
33
  });
33
34
  it('calls hook w/ closeModal and cardId from props', () => {
34
35
  expect(hooks).toHaveBeenCalledWith({
@@ -38,20 +39,36 @@ describe('EmailSettingsModal', () => {
38
39
  });
39
40
  });
40
41
  describe('render', () => {
41
- test('snapshot: emails disabled, show: false', () => {
42
- hooks.mockReturnValueOnce(hookProps);
43
- expect(shallow(<EmailSettingsModal {...props} show={false} />).snapshot).toMatchSnapshot();
42
+ it('emails disabled, show: false', () => {
43
+ hooks.mockReturnValue(hookProps);
44
+ render(<IntlProvider locale="en"><EmailSettingsModal {...props} show={false} /></IntlProvider>);
45
+ const modal = screen.queryByRole('dialog');
46
+ expect(modal).toBeNull();
44
47
  });
45
- test('snapshot: emails disabled, show: true', () => {
48
+ it('emails disabled, show: true', () => {
46
49
  hooks.mockReturnValueOnce(hookProps);
47
- expect(shallow(<EmailSettingsModal {...props} />).snapshot).toMatchSnapshot();
50
+ render(<IntlProvider locale="en"><EmailSettingsModal {...props} /></IntlProvider>);
51
+ const modal = screen.getByRole('dialog');
52
+ const heading = screen.getByText(messages.header.defaultMessage);
53
+ const emailsMsg = screen.getByText(messages.emailsOff.defaultMessage);
54
+ expect(modal).toBeInTheDocument();
55
+ expect(heading).toBeInTheDocument();
56
+ expect(emailsMsg).toBeInTheDocument();
48
57
  });
49
- test('snapshot: emails enabled, show: true', () => {
58
+ it('emails enabled, show: true', () => {
50
59
  hooks.mockReturnValueOnce({
51
60
  ...hookProps,
52
61
  isOptedOut: false,
53
62
  });
54
- expect(shallow(<EmailSettingsModal {...props} />).snapshot).toMatchSnapshot();
63
+ render(<IntlProvider locale="en"><EmailSettingsModal {...props} /></IntlProvider>);
64
+ const emailsMsg = screen.getByText(messages.emailsOn.defaultMessage);
65
+ const description = screen.getByText(messages.description.defaultMessage);
66
+ const buttonNeverMind = screen.getByRole('button', { name: messages.nevermind.defaultMessage });
67
+ const buttonSave = screen.getByRole('button', { name: messages.save.defaultMessage });
68
+ expect(emailsMsg).toBeInTheDocument();
69
+ expect(description).toBeInTheDocument();
70
+ expect(buttonNeverMind).toBeInTheDocument();
71
+ expect(buttonSave).toBeInTheDocument();
55
72
  });
56
73
  });
57
74
  });
@@ -1,23 +1,43 @@
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
3
 
4
4
  import ProgramCard from './ProgramCard';
5
5
 
6
6
  const props = {
7
7
  data: {
8
8
  numberOfCourses: 2,
9
- bannerImgSrc: 'props.data.bannerImgSrc',
10
- logoImgSrc: 'props.data.logoImgSrc',
11
- title: 'props.data.title',
12
- provider: 'props.data.provider',
13
- programType: 'props.data.programType',
14
- programUrl: 'props.data.programUrl',
15
- programTypeUrl: 'props.data.programTypeUrl',
9
+ bannerImgSrc: 'test bannerImgSrc',
10
+ logoImgSrc: 'test logoImgSrc',
11
+ title: 'test title',
12
+ provider: 'test provider',
13
+ programType: 'test programType',
14
+ programUrl: 'test programUrl',
15
+ programTypeUrl: 'test programTypeUrl',
16
16
  },
17
17
  };
18
18
 
19
19
  describe('RelatedProgramsModal ProgramCard', () => {
20
- test('snapshot', () => {
21
- expect(shallow(<ProgramCard {...props} />).snapshot).toMatchSnapshot();
20
+ describe('renders', () => {
21
+ beforeEach(() => render(<IntlProvider locale="en"><ProgramCard {...props} /></IntlProvider>));
22
+ it('bannerImg and logo', () => {
23
+ const logo = screen.getByRole('img', { name: `${props.data.provider} logo` });
24
+ const bannerImg = screen.getByRole('img', { name: /bannerAlt/i });
25
+ expect(logo).toBeInTheDocument();
26
+ expect(bannerImg).toBeInTheDocument();
27
+ });
28
+ it('title and subtitle', () => {
29
+ const title = screen.getByText(props.data.title);
30
+ const subtitle = screen.getByText(props.data.provider);
31
+ expect(title).toBeInTheDocument();
32
+ expect(subtitle).toBeInTheDocument();
33
+ });
34
+ it('badge', () => {
35
+ const badge = screen.getByText(props.data.programType);
36
+ expect(badge).toBeInTheDocument();
37
+ });
38
+ it('courses number', () => {
39
+ const coursesNumber = screen.getByText(`${props.data.numberOfCourses} Courses`);
40
+ expect(coursesNumber).toBeInTheDocument();
41
+ });
22
42
  });
23
43
  });
@@ -1,20 +1,21 @@
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
3
 
4
- import { reduxHooks } from 'hooks';
4
+ import { reduxHooks } from '@src/hooks';
5
5
  import RelatedProgramsModal from '.';
6
+ import messages from './messages';
6
7
 
7
- jest.mock('./components/ProgramCard', () => 'ProgramCard');
8
- jest.mock('hooks', () => ({
8
+ jest.mock('./components/ProgramCard', () => jest.fn(() => <div>ProgramCard</div>));
9
+ jest.mock('@src/hooks', () => ({
9
10
  reduxHooks: {
10
11
  useCardCourseData: jest.fn(),
11
12
  useCardRelatedProgramsData: jest.fn(),
12
13
  },
13
14
  }));
14
15
 
15
- const cardId = 'test-course-number';
16
+ const cardId = 'test-card-id';
16
17
  const courseData = {
17
- courseTitle: 'hookProps.courseTitle',
18
+ courseName: 'test course',
18
19
  };
19
20
  const programData = {
20
21
  list: [
@@ -45,16 +46,27 @@ describe('RelatedProgramsModal', () => {
45
46
  reduxHooks.useCardRelatedProgramsData.mockReturnValueOnce(programData);
46
47
  });
47
48
  it('initializes hooks with cardId', () => {
48
- shallow(<RelatedProgramsModal {...props} />);
49
+ render(<IntlProvider locale="en"><RelatedProgramsModal {...props} /></IntlProvider>);
49
50
  expect(reduxHooks.useCardCourseData).toHaveBeenCalledWith(cardId);
50
51
  expect(reduxHooks.useCardRelatedProgramsData).toHaveBeenCalledWith(cardId);
51
52
  });
52
- test('snapshot: open', () => {
53
- expect(shallow(<RelatedProgramsModal {...props} />).snapshot).toMatchSnapshot();
54
- });
55
- test('snapshot: closed', () => {
56
- expect(
57
- shallow(<RelatedProgramsModal {...props} isOpen={false} />).snapshot,
58
- ).toMatchSnapshot();
53
+ describe('renders', () => {
54
+ beforeEach(() => render(<IntlProvider locale="en"><RelatedProgramsModal {...props} /></IntlProvider>));
55
+ it('display header', () => {
56
+ const header = screen.getByRole('heading', { name: messages.header.defaultMessage });
57
+ expect(header).toBeInTheDocument();
58
+ });
59
+ it('displays course name', () => {
60
+ const courseName = screen.getByText(courseData.courseName);
61
+ expect(courseName).toBeInTheDocument();
62
+ });
63
+ it('displays description', () => {
64
+ const description = screen.getByText((text) => text.includes('Are you looking to expand your knowledge?'));
65
+ expect(description).toBeInTheDocument();
66
+ });
67
+ it('displays program cards', () => {
68
+ const programCards = screen.getAllByText('ProgramCard');
69
+ expect(programCards.length).toEqual(programData.list.length);
70
+ });
59
71
  });
60
72
  });
@@ -1,2 +1 @@
1
- /* eslint-disable import/prefer-default-export */
2
1
  export const LEAVE_OPTION = 'leave';
@@ -1,21 +1,31 @@
1
1
  import { useIntl } from '@openedx/frontend-base';
2
- import track from 'tracking';
2
+ import track from '@src/tracking';
3
3
 
4
- import { MockUseState } from 'testUtils';
5
- import { reduxHooks, apiHooks } from 'hooks';
4
+ import { MockUseState } from '@src/testUtils';
5
+ import { reduxHooks, apiHooks } from '@src/hooks';
6
6
 
7
7
  import { LEAVE_OPTION } from './constants';
8
8
  import messages from './messages';
9
9
  import * as hooks from './hooks';
10
10
 
11
- jest.mock('tracking', () => ({
11
+ jest.mock('@openedx/frontend-base', () => {
12
+ const { formatMessage } = jest.requireActual('@src/testUtils');
13
+ return {
14
+ ...jest.requireActual('@openedx/frontend-base'),
15
+ useIntl: () => ({
16
+ formatMessage,
17
+ }),
18
+ };
19
+ });
20
+
21
+ jest.mock('@src/tracking', () => ({
12
22
  entitlements: {
13
23
  newSession: jest.fn(),
14
24
  switchSession: jest.fn(),
15
25
  leaveSession: jest.fn(),
16
26
  },
17
27
  }));
18
- jest.mock('hooks', () => ({
28
+ jest.mock('../../hooks', () => ({
19
29
  reduxHooks: {
20
30
  useCardCourseData: jest.fn(),
21
31
  useCardCourseRunData: jest.fn(),
@@ -1,8 +1,9 @@
1
- import React from 'react';
2
- import { shallow } from '@edx/react-unit-test-utils';
3
-
1
+ import { render, screen } from '@testing-library/react';
2
+ import { formatMessage } from '@src/testUtils';
3
+ import { IntlProvider } from '@openedx/frontend-base';
4
4
  import hooks from './hooks';
5
5
  import SelectSessionModal from '.';
6
+ import messages from './messages';
6
7
 
7
8
  jest.mock('./hooks', () => ({
8
9
  __esModule: true,
@@ -25,29 +26,41 @@ const availableSessions = [
25
26
  ];
26
27
 
27
28
  describe('SelectSessionModal', () => {
28
- describe('snapshot', () => {
29
- test('empty modal with leave option ', () => {
29
+ describe('renders', () => {
30
+ it('empty modal with leave option ', () => {
30
31
  hooks.mockReturnValueOnce({
31
32
  ...hookReturn,
32
33
  });
33
- expect(shallow(<SelectSessionModal />).snapshot).toMatchSnapshot();
34
+ render(<IntlProvider locale="en"><SelectSessionModal /></IntlProvider>);
35
+ const sessionOption = screen.queryByDisplayValue(availableSessions[0].courseId);
36
+ expect(sessionOption).toBeNull();
37
+ const leaveOption = screen.getByRole('radio', { name: formatMessage(messages.leaveSessionOption) });
38
+ expect(leaveOption).toBeInTheDocument();
34
39
  });
35
40
 
36
- test('modal with leave option ', () => {
41
+ it('modal with leave option ', () => {
37
42
  hooks.mockReturnValueOnce({
38
43
  ...hookReturn,
39
- availableSessions: [...availableSessions],
44
+ availableSessions,
40
45
  });
41
- expect(shallow(<SelectSessionModal />).snapshot).toMatchSnapshot();
46
+ render(<IntlProvider locale="en"><SelectSessionModal /></IntlProvider>);
47
+ const sessionOption = screen.getByDisplayValue(availableSessions[0].courseId);
48
+ expect(sessionOption).toBeInTheDocument();
49
+ const leaveOption = screen.getByRole('radio', { name: formatMessage(messages.leaveSessionOption) });
50
+ expect(leaveOption).toBeInTheDocument();
42
51
  });
43
52
 
44
- test('modal without leave option ', () => {
53
+ it('modal without leave option ', () => {
45
54
  hooks.mockReturnValueOnce({
46
55
  ...hookReturn,
47
56
  availableSessions,
48
57
  showLeaveOption: false,
49
58
  });
50
- expect(shallow(<SelectSessionModal />).snapshot).toMatchSnapshot();
59
+ render(<IntlProvider locale="en"><SelectSessionModal /></IntlProvider>);
60
+ const sessionOption = screen.getByDisplayValue(availableSessions[0].courseId);
61
+ expect(sessionOption).toBeInTheDocument();
62
+ const leaveOption = screen.queryByRole('radio', { name: formatMessage(messages.leaveSessionOption) });
63
+ expect(leaveOption).toBeNull();
51
64
  });
52
65
  });
53
66
  });
@@ -1,14 +1,30 @@
1
- import React from 'react';
2
- import { shallow } from '@edx/react-unit-test-utils';
1
+ import { render, screen } from '@testing-library/react';
2
+ import { formatMessage } from '@src/testUtils';
3
+ import { IntlProvider } from '@openedx/frontend-base';
3
4
 
4
5
  import { ConfirmPane } from './ConfirmPane';
6
+ import messages from './messages';
7
+
8
+ const props = {
9
+ handleClose: jest.fn().mockName('props.handleClose'),
10
+ handleConfirm: jest.fn().mockName('props.handleConfirm'),
11
+ };
5
12
 
6
13
  describe('UnenrollConfirmModal ConfirmPane', () => {
7
- test('snapshot', () => {
8
- const props = {
9
- handleClose: jest.fn().mockName('props.handleClose'),
10
- handleConfirm: jest.fn().mockName('props.handleConfirm'),
11
- };
12
- expect(shallow(<ConfirmPane {...props} />).snapshot).toMatchSnapshot();
14
+ beforeEach(() => {
15
+ jest.clearAllMocks();
16
+ render(<IntlProvider locale="en"><ConfirmPane {...props} /></IntlProvider>);
17
+ });
18
+ it('renders title', () => {
19
+ const header = screen.getByText(formatMessage(messages.confirmHeader));
20
+ expect(header).toBeInTheDocument();
21
+ });
22
+ it('renders cancel button', () => {
23
+ const cancelButton = screen.getByRole('button', { name: formatMessage(messages.confirmCancel) });
24
+ expect(cancelButton).toBeInTheDocument();
25
+ });
26
+ it('renders unenroll button', () => {
27
+ const unenrollButton = screen.getByRole('button', { name: formatMessage(messages.confirmUnenroll) });
28
+ expect(unenrollButton).toBeInTheDocument();
13
29
  });
14
30
  });