@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,21 +1,46 @@
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 { FinishedPane } from './FinishedPane';
6
+ import messages from './messages';
7
+
8
+ const props = {
9
+ gaveReason: true,
10
+ handleClose: jest.fn().mockName('props.handleClose'),
11
+ };
5
12
 
6
13
  describe('UnenrollConfirmModal FinishedPane', () => {
7
- test('snapshot: gave reason', () => {
8
- const props = {
9
- gaveReason: true,
10
- handleClose: jest.fn().mockName('props.handleClose'),
11
- };
12
- expect(shallow(<FinishedPane {...props} />).snapshot).toMatchSnapshot();
14
+ describe('gave reason', () => {
15
+ beforeEach(() => {
16
+ jest.clearAllMocks();
17
+ render(<IntlProvider locale="en"><FinishedPane {...props} /></IntlProvider>);
18
+ });
19
+ it('renders heading', () => {
20
+ const heading = screen.getByText(formatMessage(messages.finishHeading));
21
+ expect(heading).toBeInTheDocument();
22
+ });
23
+ it('renders return button', () => {
24
+ const returnButton = screen.getByRole('button', { name: formatMessage(messages.finishReturn) });
25
+ expect(returnButton).toBeInTheDocument();
26
+ });
27
+ it('Gave reason, display thanks message', () => {
28
+ const thanksMsg = screen.getByText((text) => text.includes('Thank you'));
29
+ expect(thanksMsg).toBeInTheDocument();
30
+ expect(thanksMsg.innerHTML).toContain(formatMessage(messages.finishThanksText));
31
+ });
13
32
  });
14
- test('snapshot: did not give reason', () => {
15
- const props = {
16
- gaveReason: false,
17
- handleClose: jest.fn().mockName('props.handleClose'),
18
- };
19
- expect(shallow(<FinishedPane {...props} />).snapshot).toMatchSnapshot();
33
+ describe('Did not give reason', () => {
34
+ it('Does not display thanks message', () => {
35
+ const customProps = {
36
+ gaveReason: false,
37
+ handleClose: jest.fn().mockName('props.handleClose'),
38
+ };
39
+ render(<IntlProvider locale="en"><FinishedPane {...customProps} /></IntlProvider>);
40
+ const thanksMsg = screen.queryByText((text) => text.includes('Thank you'));
41
+ expect(thanksMsg).toBeNull();
42
+ const finishMsg = screen.getByText(formatMessage(messages.finishText));
43
+ expect(finishMsg).toBeInTheDocument();
44
+ });
20
45
  });
21
46
  });
@@ -1,7 +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 { formatMessage } from '@src/testUtils';
3
+ import { IntlProvider } from '@openedx/frontend-base';
3
4
 
4
5
  import { ReasonPane } from './ReasonPane';
6
+ import messages from './messages';
5
7
 
6
8
  describe('UnenrollConfirmModal ReasonPane', () => {
7
9
  const props = {
@@ -17,10 +19,25 @@ describe('UnenrollConfirmModal ReasonPane', () => {
17
19
  hasReason: true,
18
20
  },
19
21
  };
20
- test('snapshot', () => {
21
- expect(shallow(<ReasonPane {...props} />).snapshot).toMatchSnapshot();
22
+ it('render heading', () => {
23
+ render(<IntlProvider locale="en"><ReasonPane {...props} /></IntlProvider>);
24
+ const heading = screen.getByText(formatMessage(messages.reasonHeading));
25
+ expect(heading).toBeInTheDocument();
22
26
  });
23
- test('snapshot: no reason provided', () => {
24
- expect(shallow(<ReasonPane {...props} hasReason={false} />).snapshot).toMatchSnapshot();
27
+ it('render options', () => {
28
+ render(<IntlProvider locale="en"><ReasonPane {...props} /></IntlProvider>);
29
+ const radioButtons = screen.getAllByRole('radio');
30
+ expect(radioButtons).toBeDefined();
31
+ expect(radioButtons.length).toBe(10);
32
+ });
33
+ it('render skip button', () => {
34
+ render(<IntlProvider locale="en"><ReasonPane {...props} hasReason={false} /></IntlProvider>);
35
+ const skipButton = screen.getByRole('button', { name: formatMessage(messages.reasonSkip) });
36
+ expect(skipButton).toBeInTheDocument();
37
+ });
38
+ it('render submit button', () => {
39
+ render(<IntlProvider locale="en"><ReasonPane {...props} hasReason={false} /></IntlProvider>);
40
+ const submitButton = screen.getByRole('button', { name: formatMessage(messages.reasonSubmit) });
41
+ expect(submitButton).toBeInTheDocument();
25
42
  });
26
43
  });
@@ -1,28 +1,40 @@
1
- import { apiHooks } from 'hooks';
2
- import { MockUseState } from 'testUtils';
3
-
1
+ import React from 'react';
2
+ import { apiHooks } from '@src/hooks';
3
+ import { MockUseState } from '@src/testUtils';
4
4
  import * as reasons from './reasons';
5
5
  import * as hooks from '.';
6
+ import { renderHook } from '@testing-library/react';
7
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
6
8
 
7
9
  jest.mock('./reasons', () => ({
8
10
  useUnenrollReasons: jest.fn(),
9
11
  }));
10
-
11
- jest.mock('hooks', () => ({
12
+ jest.mock('../../../hooks', () => ({
12
13
  apiHooks: {
13
14
  useInitializeApp: jest.fn(),
14
15
  },
15
16
  }));
17
+ jest.mock('@tanstack/react-query', () => ({
18
+ useQueryClient: () => ({
19
+ invalidateQueries: jest.fn(),
20
+ }),
21
+ QueryClient: jest.fn().mockImplementation(() => ({
22
+ invalidateQueries: jest.fn(),
23
+ })),
24
+ QueryClientProvider: ({ children }) => children,
25
+ }));
16
26
 
17
27
  const state = new MockUseState(hooks);
18
28
  const testValue = 'test-value';
19
29
  const initializeApp = jest.fn();
20
30
  apiHooks.useInitializeApp.mockReturnValue(initializeApp);
31
+
21
32
  let out;
22
33
 
23
34
  const mockReason = {
24
35
  handleClear: jest.fn(),
25
36
  isSubmitted: false,
37
+ isSkipped: false,
26
38
  submittedReason: 'test-submitted-reason',
27
39
  };
28
40
 
@@ -34,8 +46,15 @@ describe('UnenrollConfirmModal hooks', () => {
34
46
  });
35
47
  const closeModal = jest.fn();
36
48
  const cardId = 'test-card-id';
37
-
38
- const createUseUnenrollData = () => hooks.useUnenrollData({ closeModal, cardId });
49
+ const createUseUnenrollData = () => {
50
+ const queryClient = new QueryClient();
51
+ const { result } = renderHook(() => hooks.useUnenrollData({ closeModal, cardId }), {
52
+ wrapper: ({ children }) => (
53
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
54
+ ),
55
+ });
56
+ return result.current;
57
+ };
39
58
 
40
59
  describe('state fields', () => {
41
60
  state.testGetter(state.keys.confirmed);
@@ -68,34 +87,63 @@ describe('UnenrollConfirmModal hooks', () => {
68
87
  });
69
88
  });
70
89
  describe('closeAndRefresh', () => {
90
+ beforeEach(() => {
91
+ apiHooks.useInitializeApp.mockClear();
92
+ });
71
93
  it('calls closeModal, sets isConfirmed to false, and calls reason.handleClear', () => {
72
94
  out.closeAndRefresh();
73
95
  expect(closeModal).toHaveBeenCalled();
74
96
  expect(state.setState.confirmed).toHaveBeenCalledWith(false);
75
97
  expect(mockReason.handleClear).toHaveBeenCalled();
76
98
  });
77
- it('calls initializeApp api method', () => {
99
+ it('calls refreshList and close', () => {
100
+ const refreshList = jest.fn();
101
+ const close = jest.fn();
102
+
103
+ jest.spyOn(hooks, 'useUnenrollData').mockReturnValue({
104
+ closeAndRefresh: () => {
105
+ refreshList();
106
+ close();
107
+ },
108
+ refreshList,
109
+ close,
110
+ });
111
+
112
+ out = hooks.useUnenrollData({ closeModal, cardId });
78
113
  out.closeAndRefresh();
79
- expect(initializeApp).toHaveBeenCalled();
114
+ expect(refreshList).toHaveBeenCalled();
115
+ expect(close).toHaveBeenCalled();
80
116
  });
81
117
  });
82
- describe('modalState', () => {
83
- it('returns modalStates.finished if confirmed and submitted', () => {
84
- state.mockVal(state.keys.confirmed, true);
85
- reasons.useUnenrollReasons.mockReturnValueOnce({ ...mockReason, isSubmitted: true });
86
- out = createUseUnenrollData();
87
- expect(out.modalState).toEqual(hooks.modalStates.finished);
88
- });
89
- it('returns modalStates.reason if confirmed and not submitted', () => {
90
- state.mockVal(state.keys.confirmed, true);
91
- out = createUseUnenrollData();
92
- expect(out.modalState).toEqual(hooks.modalStates.reason);
93
- });
94
- it('returns modalStates.confirm if not confirmed', () => {
95
- state.mockVal(state.keys.confirmed, false);
96
- out = createUseUnenrollData();
97
- expect(out.modalState).toEqual(hooks.modalStates.confirm);
98
- });
118
+ });
119
+
120
+ describe('modalState', () => {
121
+ // Helper function to compute modalState based on the same logic as the actual hook
122
+ const getModalState = (isConfirmed, reason) => {
123
+ if (isConfirmed) {
124
+ return (reason.isSubmitted || reason.isSkipped) ? 'finished' : 'reason';
125
+ }
126
+ return 'confirm';
127
+ };
128
+
129
+ test('should return finished when confirmed and submitted', () => {
130
+ const result = getModalState(true, { isSubmitted: true, isSkipped: false });
131
+ expect(result).toEqual('finished');
132
+ });
133
+
134
+ test('should return finished when confirmed and skipped', () => {
135
+ const result = getModalState(true, { isSubmitted: false, isSkipped: true });
136
+ expect(result).toEqual('finished');
137
+ });
138
+
139
+ test('should return reason when confirmed but not submitted or skipped', () => {
140
+ const result = getModalState(true, { isSubmitted: false, isSkipped: false });
141
+ expect(result).toEqual('reason');
142
+ });
143
+
144
+ test('should return confirm when not confirmed', () => {
145
+ const result = getModalState(false, { isSubmitted: false, isSkipped: false });
146
+ expect(result).toEqual('confirm');
99
147
  });
100
148
  });
101
149
  });
@@ -1,14 +1,14 @@
1
- import { MockUseState } from 'testUtils';
2
- import track from 'tracking';
1
+ import { MockUseState } from '@src/testUtils';
2
+ import track from '@src/tracking';
3
3
  import {
4
4
  apiHooks,
5
5
  reduxHooks,
6
6
  utilHooks,
7
- } from 'hooks';
7
+ } from '@src/hooks';
8
8
 
9
9
  import * as hooks from './reasons';
10
10
 
11
- jest.mock('hooks', () => ({
11
+ jest.mock('@src/hooks', () => ({
12
12
  apiHooks: {
13
13
  useUnenrollFromCourse: jest.fn((...args) => ({ unenrollFromCourse: args })),
14
14
  },
@@ -1,13 +1,11 @@
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
3
 
4
+ import { IntlProvider } from '@openedx/frontend-base';
4
5
  import { UnenrollConfirmModal } from '.';
5
6
 
6
7
  import * as hooks from './hooks';
7
-
8
- jest.mock('./components/ConfirmPane', () => 'ConfirmPane');
9
- jest.mock('./components/ReasonPane', () => 'ReasonPane');
10
- jest.mock('./components/FinishedPane', () => 'FinishedPane');
8
+ import messages from './components/messages';
11
9
 
12
10
  jest.mock('./hooks', () => ({
13
11
  __esModule: true,
@@ -33,29 +31,48 @@ describe('UnenrollConfirmModal component', () => {
33
31
  show: true,
34
32
  cardId,
35
33
  };
36
- test('hooks called with closeModal and cardId', () => {
34
+ it('hooks called with closeModal and cardId', () => {
37
35
  hooks.useUnenrollData.mockReturnValueOnce(hookProps);
38
- shallow(<UnenrollConfirmModal {...props} />);
36
+ render(<IntlProvider><UnenrollConfirmModal {...props} /></IntlProvider>);
39
37
  expect(hooks.useUnenrollData).toHaveBeenCalledWith({ closeModal, cardId });
40
38
  });
41
- test('snapshot: modalStates.confirm', () => {
39
+ it('modalStates.confirm display correct component and to have class shadow', () => {
42
40
  hooks.useUnenrollData.mockReturnValueOnce(hookProps);
43
- expect(shallow(<UnenrollConfirmModal {...props} />).snapshot).toMatchSnapshot();
41
+ render(<IntlProvider><UnenrollConfirmModal {...props} /></IntlProvider>);
42
+ const confirmHeader = screen.getByText(formatMessage(messages.confirmHeader));
43
+ expect(confirmHeader).toBeInTheDocument();
44
+ const dialogContainer = screen.getByRole('dialog').firstElementChild;
45
+ expect(dialogContainer).toHaveClass('shadow');
44
46
  });
45
- test('snapshot: modalStates.finished, reason given', () => {
47
+ it('modalStates.finished, reason given, display correct component', () => {
46
48
  hooks.useUnenrollData.mockReturnValueOnce({ ...hookProps, modalState: hooks.modalStates.finished });
47
- expect(shallow(<UnenrollConfirmModal {...props} />).snapshot).toMatchSnapshot();
49
+ render(<IntlProvider><UnenrollConfirmModal {...props} /></IntlProvider>);
50
+ const finishHeading = screen.getByText(formatMessage(messages.finishHeading));
51
+ expect(finishHeading).toBeInTheDocument();
52
+ const thanksMsg = screen.getByText((text) => text.includes('Thank you'));
53
+ expect(thanksMsg).toBeInTheDocument();
54
+ expect(thanksMsg.innerHTML).toContain(formatMessage(messages.finishThanksText));
48
55
  });
49
- test('snapshot: modalStates.finished, reason skipped', () => {
56
+ it('modalStates.finished, reason skipped', () => {
50
57
  hooks.useUnenrollData.mockReturnValueOnce({
51
58
  ...hookProps,
52
59
  modalState: hooks.modalStates.finished,
53
- isSkipped: true,
60
+ reason: { isSkipped: true },
54
61
  });
55
- expect(shallow(<UnenrollConfirmModal {...props} />).snapshot).toMatchSnapshot();
62
+ render(<IntlProvider><UnenrollConfirmModal {...props} /></IntlProvider>);
63
+ const finishHeading = screen.getByText(formatMessage(messages.finishHeading));
64
+ expect(finishHeading).toBeInTheDocument();
65
+ const thanksMsg = screen.queryByText((text) => text.includes('Thank you'));
66
+ expect(thanksMsg).toBeNull();
67
+ const finishMsg = screen.getByText(formatMessage(messages.finishText));
68
+ expect(finishMsg).toBeInTheDocument();
56
69
  });
57
- test('snapshot: modalStates.reason, should be fullscreen with no shadow', () => {
70
+ it('modalStates.reason, should display correct component with no shadow', () => {
58
71
  hooks.useUnenrollData.mockReturnValueOnce({ ...hookProps, modalState: hooks.modalStates.reason });
59
- expect(shallow(<UnenrollConfirmModal {...props} />).snapshot).toMatchSnapshot();
72
+ render(<IntlProvider><UnenrollConfirmModal {...props} /></IntlProvider>);
73
+ const reasonHeading = screen.getByText(formatMessage(messages.reasonHeading));
74
+ expect(reasonHeading).toBeInTheDocument();
75
+ const dialogContainer = screen.getByRole('dialog').firstElementChild;
76
+ expect(dialogContainer).not.toHaveClass('shadow');
60
77
  });
61
78
  });
@@ -1,7 +1,4 @@
1
- import { getSiteConfig } from '@openedx/frontend-base';
2
1
  import { StrictDict } from '../../utils';
3
-
4
- export const routePath = `${getSiteConfig().publicPath}:courseId`;
5
2
  export const locationId = window.location.pathname.slice(1);
6
3
 
7
4
  export const SortKeys = StrictDict({
@@ -1,20 +1,8 @@
1
- import * as base from '@openedx/frontend-base';
2
1
  import * as constants from './app';
3
2
 
4
3
  jest.unmock('./app');
5
4
 
6
- jest.mock('@openedx/frontend-base', () => {
7
- const PUBLIC_PATH = 'test-public-path';
8
- return {
9
- getSiteConfig: () => ({ PUBLIC_PATH }),
10
- PUBLIC_PATH,
11
- };
12
- });
13
-
14
5
  describe('app constants', () => {
15
- test('route path draws from public path and adds courseId', () => {
16
- expect(constants.routePath).toEqual(`${base.PUBLIC_PATH}:courseId`);
17
- });
18
6
  test('locationId returns trimmed pathname', () => {
19
7
  const old = window.location;
20
8
  window.location = { pathName: '/somePath.jpg' };
@@ -1,11 +1,11 @@
1
- import { keyStore } from 'utils';
2
- import { baseAppUrl } from 'data/services/lms/urls';
3
- import { EXECUTIVE_EDUCATION_COURSE_MODES } from 'data/constants/course';
1
+ import { keyStore } from '@src/utils';
2
+ import { baseAppUrl } from '@src/data/services/lms/urls';
3
+ import { EXECUTIVE_EDUCATION_COURSE_MODES } from '@src/data/constants/course';
4
4
 
5
5
  import simpleSelectors from './simpleSelectors';
6
6
  import * as module from './courseCard';
7
7
 
8
- jest.mock('data/services/lms/urls', () => ({
8
+ jest.mock('@src/data/services/lms/urls', () => ({
9
9
  baseAppUrl: url => ({ baseAppUrl: url }),
10
10
  }));
11
11
 
@@ -1,5 +1,5 @@
1
- import { keyStore } from 'utils';
2
- import { FilterKeys, SortKeys } from 'data/constants/app';
1
+ import { keyStore } from '@src/utils';
2
+ import { FilterKeys, SortKeys } from '@src/data/constants/app';
3
3
  import simpleSelectors from './simpleSelectors';
4
4
  import * as module from './currentList';
5
5
 
@@ -104,7 +104,9 @@ describe('courseList selector module', () => {
104
104
  filterSpy.mockReturnValue(({ val }) => val > 0);
105
105
  sortSpy.mockReturnValue((v1, v2) => {
106
106
  const [a, b] = [v1, v2].map(({ val }) => val);
107
- if (a === b) { return 0; }
107
+ if (a === b) {
108
+ return 0;
109
+ }
108
110
  return (a > b) ? 1 : -1;
109
111
  });
110
112
  const testCourses = {
@@ -1,4 +1,4 @@
1
- import { keyStore } from 'utils';
1
+ import { keyStore } from '@src/utils';
2
2
  import * as module from './simpleSelectors';
3
3
 
4
4
  const {
@@ -1,4 +1,4 @@
1
- import { RequestStates } from 'data/constants/requests';
1
+ import { RequestStates } from '@src/data/constants/requests';
2
2
  import { initialState, actions, reducer } from './reducer';
3
3
 
4
4
  const testingState = {
@@ -1,6 +1,5 @@
1
1
  import { StrictDict } from '../../../utils';
2
- import { RequestStates, RequestKeys } from '../../../data/constants/requests';
3
- // import * as module from './selectors';
2
+ import { RequestStates } from '../../../data/constants/requests';
4
3
 
5
4
  export const requestStatus = (state, { requestKey }) => state.requests[requestKey];
6
5
 
@@ -1,4 +1,4 @@
1
- import { RequestStates, RequestKeys } from 'data/constants/requests';
1
+ import { RequestStates } from '@src/data/constants/requests';
2
2
 
3
3
  import selectors from './selectors';
4
4
 
@@ -79,32 +79,4 @@ describe('requests selectors unit tests', () => {
79
79
  test('data reurns the request data', () => {
80
80
  expect(select(selectors.data, { data: testValue })).toEqual(testValue);
81
81
  });
82
- test('masquerade returns the masquerade data', () => {
83
- const mockResponse = (response) => ({
84
- requests: {
85
- [RequestKeys.masquerade]: response,
86
- },
87
- });
88
- expect(selectors.masquerade(mockResponse(completedRequest))).toEqual({
89
- isMasquerading: true,
90
- isMasqueradingFailed: false,
91
- isMasqueradingPending: false,
92
- masqueradeErrorStatus: undefined,
93
- });
94
- expect(selectors.masquerade(mockResponse(pendingRequest))).toEqual({
95
- isMasquerading: false,
96
- isMasqueradingFailed: false,
97
- isMasqueradingPending: true,
98
- masqueradeErrorStatus: undefined,
99
- });
100
- expect(selectors.masquerade(mockResponse({
101
- ...failedRequest,
102
- error: testErrorValue,
103
- }))).toEqual({
104
- isMasquerading: false,
105
- isMasqueradingFailed: true,
106
- isMasqueradingPending: false,
107
- masqueradeErrorStatus: testErrorValue.response.status,
108
- });
109
- });
110
82
  });
@@ -1,6 +1,6 @@
1
- import { mockLocation } from 'testUtils';
2
- import { keyStore } from 'utils';
3
- import eventNames from 'tracking/constants';
1
+ import { mockLocation } from '@src/testUtils';
2
+ import { keyStore } from '@src/utils';
3
+ import { eventNames } from '@src/tracking/constants';
4
4
  import * as api from './api';
5
5
  import * as utils from './utils';
6
6
  import urls from './urls';
@@ -32,9 +32,9 @@ describe('lms api methods', () => {
32
32
  beforeEach(() => {
33
33
  jest.clearAllMocks();
34
34
  });
35
- test('keys identical to module', () => {
36
- /* eslint-disable-next-line global-require */
37
- const { default: defaultApi, ...rest } = require('./api');
35
+ test('keys identical to module', async () => {
36
+ const mod = await import('./api');
37
+ const { default: defaultApi, ...rest } = mod;
38
38
  expect(Object.keys(rest).sort()).toMatchObject(Object.keys(defaultApi).sort());
39
39
  });
40
40
  describe('initializeList', () => {
@@ -1,5 +1,5 @@
1
1
  import { getAppConfig, getSiteConfig } from '@openedx/frontend-base';
2
- import { appId } from '../../../constants';
2
+ import { appId } from '@src/constants';
3
3
  import * as urls from './urls';
4
4
 
5
5
  describe('urls', () => {
@@ -1,6 +1,6 @@
1
1
  import { sendTrackEvent } from '@openedx/frontend-base';
2
2
 
3
- import { appName } from 'tracking/constants';
3
+ import { appName } from '@src/tracking/constants';
4
4
 
5
5
  import { createEventTracker, createLinkTracker, LINK_TIMEOUT } from './utils';
6
6
 
@@ -5,11 +5,11 @@ import {
5
5
  } from '@redux-devtools/extension';
6
6
  import { createLogger } from 'redux-logger';
7
7
 
8
- import rootReducer from 'data/redux';
8
+ import rootReducer from './redux';
9
9
 
10
10
  import exportedStore, { createStore } from './store';
11
11
 
12
- jest.mock('data/redux', () => ({
12
+ jest.mock('./redux', () => ({
13
13
  __esModule: true,
14
14
  default: 'REDUCER',
15
15
  actions: 'ACTIONS',