richie-education 2.25.0-b2.dev148 → 2.25.0-b2.dev152
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.
- package/js/contexts/JoanieApiContext/index.spec.tsx +1 -1
- package/js/contexts/SessionContext/JoanieSessionProvider.spec.tsx +44 -37
- package/js/contexts/SessionContext/index.spec.tsx +42 -21
- package/js/contexts/SessionContext/no-authentication.spec.tsx +3 -2
- package/js/hooks/useCourseSearchParams/index.spec.tsx +0 -1
- package/js/hooks/useUnionResource/index.spec.tsx +11 -9
- package/js/utils/test/render.tsx +5 -1
- package/js/utils/test/wrappers/BaseAppWrapper.tsx +5 -8
- package/js/utils/test/wrappers/BaseJoanieAppWrapper.tsx +4 -7
- package/js/utils/test/wrappers/IntlWrapper.tsx +4 -2
- package/js/utils/test/wrappers/PresentationalAppWrapper.tsx +1 -1
- package/js/utils/test/wrappers/ReactQueryAppWrapper.tsx +16 -0
- package/js/widgets/Dashboard/components/DashboardAvatar/index.spec.tsx +8 -5
- package/js/widgets/Dashboard/components/DashboardBox/index.spec.tsx +3 -1
- package/js/widgets/Dashboard/components/DashboardItem/Certificate/index.spec.tsx +19 -39
- package/js/widgets/Dashboard/components/DashboardItem/CertificateStatus/index.spec.tsx +14 -12
- package/js/widgets/Dashboard/components/DashboardItem/Contract/index.spec.tsx +5 -43
- package/js/widgets/Dashboard/components/DashboardItem/CourseEnrolling/index.spec.tsx +16 -15
- package/js/widgets/Dashboard/components/DashboardItem/Enrollment/DashboardItemEnrollment.spec.tsx +8 -18
- package/js/widgets/Dashboard/components/DashboardItem/Enrollment/ProductCertificateFooter/index.spec.tsx +19 -51
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrder.spec.tsx +40 -70
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.spec.tsx +31 -32
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateLearnerMessage/index.spec.tsx +19 -31
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderStateTeacherMessage/index.spec.tsx +26 -37
- package/js/widgets/Dashboard/components/DashboardItem/index.spec.tsx +28 -23
- package/js/widgets/Dashboard/components/DashboardLayoutRoute/index.spec.tsx +53 -51
- package/js/widgets/Dashboard/components/DashboardSidebar/components/ContractNavLink/index.spec.tsx +24 -49
- package/js/widgets/Dashboard/components/DashboardSidebar/components/MenuNavLink/index.spec.tsx +5 -14
- package/js/widgets/Dashboard/components/ProtectedOutlet/AuthenticatedOutlet.spec.tsx +62 -54
- package/js/widgets/Dashboard/components/ProtectedOutlet/ProtectedOutlet.spec.tsx +67 -42
- package/js/widgets/Dashboard/components/RouterButton/index.spec.tsx +12 -14
- package/js/widgets/Dashboard/components/TeacherDashboardOrganizationSidebar/index.spec.tsx +14 -39
- package/js/widgets/Dashboard/hooks/useDashboardRouter/index.spec.tsx +2 -4
- package/js/widgets/Dashboard/hooks/useEnroll/index.spec.tsx +7 -28
- package/js/widgets/Dashboard/hooks/useRouteInfo/index.spec.tsx +25 -33
- package/js/widgets/Dashboard/index.spec.tsx +49 -43
- package/js/widgets/LanguageSelector/index.spec.tsx +7 -7
- package/js/widgets/LtiConsumer/index.spec.tsx +46 -48
- package/js/widgets/RootSearchSuggestField/index.spec.tsx +8 -6
- package/js/widgets/Search/components/PaginateCourseSearch/index.spec.tsx +10 -3
- package/js/widgets/Search/components/SearchFilterGroup/index.spec.tsx +5 -3
- package/js/widgets/Search/components/SearchFilterGroupModal/index.spec.tsx +8 -4
- package/js/widgets/Search/components/SearchFilterValueLeaf/index.spec.tsx +7 -3
- package/js/widgets/Search/components/SearchFilterValueParent/index.spec.tsx +12 -7
- package/js/widgets/Search/components/SearchFiltersPane/index.spec.tsx +5 -1
- package/js/widgets/Search/hooks/useCourseSearch/index.spec.tsx +4 -12
- package/js/widgets/Search/hooks/useFilterValue/index.spec.tsx +0 -2
- package/js/widgets/Search/index.spec.tsx +14 -6
- package/js/widgets/SearchSuggestField/index.spec.tsx +14 -1
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCertificateItem/index.spec.tsx +16 -31
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseProductCourseRuns/index.spec.tsx +46 -72
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/components/CourseRunItem/index.spec.tsx +5 -2
- package/js/widgets/SyllabusCourseRunsList/components/CourseProductItem/index.spec.tsx +147 -162
- package/js/widgets/SyllabusCourseRunsList/components/CourseRunEnrollment/CourseRunUnenrollmentButton/index.spec.tsx +6 -4
- package/js/widgets/SyllabusCourseRunsList/components/CourseRunEnrollment/index.joanie.spec.tsx +22 -99
- package/js/widgets/SyllabusCourseRunsList/components/CourseRunEnrollment/index.openedx.spec.tsx +27 -83
- package/js/widgets/SyllabusCourseRunsList/components/CourseRunItem/index.spec.tsx +4 -1
- package/js/widgets/SyllabusCourseRunsList/components/CourseRunItemWithEnrollment/index.spec.tsx +28 -35
- package/js/widgets/SyllabusCourseRunsList/components/CourseWishButton/hooks/useCourseWish/index.spec.tsx +9 -28
- package/js/widgets/SyllabusCourseRunsList/components/CourseWishButton/index.login.spec.tsx +23 -48
- package/js/widgets/SyllabusCourseRunsList/components/CourseWishButton/index.logout.spec.tsx +20 -29
- package/js/widgets/SyllabusCourseRunsList/components/SyllabusSimpleCourseRunsList/index.spec.tsx +9 -4
- package/js/widgets/SyllabusCourseRunsList/hooks/useCourseEnrollment/index.spec.tsx +8 -10
- package/js/widgets/SyllabusCourseRunsList/index.spec.tsx +28 -39
- package/js/widgets/UserLogin/components/UserMenu/index.spec.tsx +9 -6
- package/js/widgets/UserLogin/index.not.isJoanieEnabled.spec.tsx +21 -32
- package/js/widgets/UserLogin/index.spec.tsx +15 -37
- package/js/widgets/index.spec.tsx +12 -17
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { QueryClientProvider } from '@tanstack/react-query';
|
|
2
|
-
import { act, fireEvent,
|
|
2
|
+
import { act, fireEvent, screen, waitFor } from '@testing-library/react';
|
|
3
3
|
import fetchMock from 'fetch-mock';
|
|
4
4
|
import queryString from 'query-string';
|
|
5
5
|
import { IntlProvider } from 'react-intl';
|
|
@@ -10,6 +10,7 @@ import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/fac
|
|
|
10
10
|
import context from 'utils/context';
|
|
11
11
|
import { createTestQueryClient } from 'utils/test/createTestQueryClient';
|
|
12
12
|
import { HttpStatusCode } from 'utils/errors/HttpError';
|
|
13
|
+
import { render } from 'utils/test/render';
|
|
13
14
|
import Search from '.';
|
|
14
15
|
|
|
15
16
|
let mockMatches = false;
|
|
@@ -29,6 +30,10 @@ jest.mock('utils/context', () => ({
|
|
|
29
30
|
default: mockRichieContextFactory().one(),
|
|
30
31
|
}));
|
|
31
32
|
|
|
33
|
+
jest.mock('utils/errors/handle', () => ({
|
|
34
|
+
handle: jest.fn(),
|
|
35
|
+
}));
|
|
36
|
+
|
|
32
37
|
describe('<Search />', () => {
|
|
33
38
|
const historyPushState = jest.fn();
|
|
34
39
|
const historyReplaceState = jest.fn();
|
|
@@ -42,11 +47,6 @@ describe('<Search />', () => {
|
|
|
42
47
|
historyReplaceState,
|
|
43
48
|
];
|
|
44
49
|
|
|
45
|
-
afterEach(() => {
|
|
46
|
-
fetchMock.restore();
|
|
47
|
-
jest.resetAllMocks();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
50
|
it('shows a spinner while the results are loading', async () => {
|
|
51
51
|
fetchMock.get('/api/v1.0/courses/?limit=20&offset=0', {
|
|
52
52
|
meta: {
|
|
@@ -63,6 +63,7 @@ describe('<Search />', () => {
|
|
|
63
63
|
</HistoryContext.Provider>
|
|
64
64
|
</IntlProvider>
|
|
65
65
|
</QueryClientProvider>,
|
|
66
|
+
{ wrapper: null },
|
|
66
67
|
);
|
|
67
68
|
|
|
68
69
|
expect(screen.getByText('Loading search results...').parentElement).toHaveAttribute(
|
|
@@ -118,6 +119,7 @@ describe('<Search />', () => {
|
|
|
118
119
|
</HistoryContext.Provider>
|
|
119
120
|
</IntlProvider>
|
|
120
121
|
</QueryClientProvider>,
|
|
122
|
+
{ wrapper: null },
|
|
121
123
|
);
|
|
122
124
|
|
|
123
125
|
// Wait for search results to be loaded
|
|
@@ -142,6 +144,7 @@ describe('<Search />', () => {
|
|
|
142
144
|
</HistoryContext.Provider>
|
|
143
145
|
</IntlProvider>
|
|
144
146
|
</QueryClientProvider>,
|
|
147
|
+
{ wrapper: null },
|
|
145
148
|
);
|
|
146
149
|
|
|
147
150
|
expect(screen.getByText('Loading search results...').parentElement).toHaveAttribute(
|
|
@@ -172,6 +175,7 @@ describe('<Search />', () => {
|
|
|
172
175
|
</HistoryContext.Provider>
|
|
173
176
|
</IntlProvider>
|
|
174
177
|
</QueryClientProvider>,
|
|
178
|
+
{ wrapper: null },
|
|
175
179
|
);
|
|
176
180
|
|
|
177
181
|
await waitFor(() => {
|
|
@@ -198,6 +202,7 @@ describe('<Search />', () => {
|
|
|
198
202
|
</HistoryContext.Provider>
|
|
199
203
|
</IntlProvider>
|
|
200
204
|
</QueryClientProvider>,
|
|
205
|
+
{ wrapper: null },
|
|
201
206
|
);
|
|
202
207
|
|
|
203
208
|
// there is a button to toggle the filters pane, placed right before the filters pane in the DOM
|
|
@@ -265,6 +270,7 @@ describe('<Search />', () => {
|
|
|
265
270
|
</HistoryContext.Provider>
|
|
266
271
|
</IntlProvider>
|
|
267
272
|
</QueryClientProvider>,
|
|
273
|
+
{ wrapper: null },
|
|
268
274
|
);
|
|
269
275
|
|
|
270
276
|
// both filters and results zones are regions that are correctly labelled
|
|
@@ -301,6 +307,7 @@ describe('<Search />', () => {
|
|
|
301
307
|
</HistoryContext.Provider>
|
|
302
308
|
</IntlProvider>
|
|
303
309
|
</QueryClientProvider>,
|
|
310
|
+
{ wrapper: null },
|
|
304
311
|
);
|
|
305
312
|
});
|
|
306
313
|
|
|
@@ -333,6 +340,7 @@ describe('<Search />', () => {
|
|
|
333
340
|
</HistoryContext.Provider>
|
|
334
341
|
</IntlProvider>
|
|
335
342
|
</QueryClientProvider>,
|
|
343
|
+
{ wrapper: null },
|
|
336
344
|
);
|
|
337
345
|
});
|
|
338
346
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { act, fireEvent,
|
|
1
|
+
import { act, fireEvent, waitFor } from '@testing-library/react';
|
|
2
2
|
import fetchMock from 'fetch-mock';
|
|
3
3
|
import { IntlProvider } from 'react-intl';
|
|
4
4
|
import { CourseSearchParamsAction, useCourseSearchParams } from 'hooks/useCourseSearchParams';
|
|
@@ -7,6 +7,7 @@ import { history, location } from 'utils/indirection/window';
|
|
|
7
7
|
import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
|
|
8
8
|
import { FilterDefinition } from 'types/filters';
|
|
9
9
|
import context from 'utils/context';
|
|
10
|
+
import { render } from 'utils/test/render';
|
|
10
11
|
import SearchSuggestField from '.';
|
|
11
12
|
|
|
12
13
|
jest.mock('settings', () => ({
|
|
@@ -78,6 +79,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
78
79
|
<SearchSuggestField context={context} />
|
|
79
80
|
</HistoryProvider>
|
|
80
81
|
</IntlProvider>,
|
|
82
|
+
{ wrapper: null },
|
|
81
83
|
);
|
|
82
84
|
|
|
83
85
|
// The placeholder text is shown in the input
|
|
@@ -94,6 +96,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
94
96
|
<SearchSuggestField context={context} />
|
|
95
97
|
</HistoryProvider>
|
|
96
98
|
</IntlProvider>,
|
|
99
|
+
{ wrapper: null },
|
|
97
100
|
);
|
|
98
101
|
|
|
99
102
|
// The existing query is shown in the input
|
|
@@ -116,6 +119,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
116
119
|
<OtherComponent />
|
|
117
120
|
</HistoryProvider>
|
|
118
121
|
</IntlProvider>,
|
|
122
|
+
{ wrapper: null },
|
|
119
123
|
);
|
|
120
124
|
|
|
121
125
|
// The existing query is shown in the input
|
|
@@ -134,6 +138,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
134
138
|
<OtherComponent />
|
|
135
139
|
</HistoryProvider>
|
|
136
140
|
</IntlProvider>,
|
|
141
|
+
{ wrapper: null },
|
|
137
142
|
);
|
|
138
143
|
|
|
139
144
|
// The input does not show a value anymore
|
|
@@ -170,6 +175,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
170
175
|
<SearchSuggestField context={context} />
|
|
171
176
|
</HistoryProvider>
|
|
172
177
|
</IntlProvider>,
|
|
178
|
+
{ wrapper: null },
|
|
173
179
|
);
|
|
174
180
|
|
|
175
181
|
const field = getByPlaceholderText('Search for courses, organizations, categories');
|
|
@@ -212,6 +218,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
212
218
|
<SearchSuggestField context={context} />
|
|
213
219
|
</HistoryProvider>
|
|
214
220
|
</IntlProvider>,
|
|
221
|
+
{ wrapper: null },
|
|
215
222
|
);
|
|
216
223
|
|
|
217
224
|
const field = getByPlaceholderText('Search for courses, organizations, categories');
|
|
@@ -257,6 +264,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
257
264
|
<SearchSuggestField context={context} />
|
|
258
265
|
</HistoryProvider>
|
|
259
266
|
</IntlProvider>,
|
|
267
|
+
{ wrapper: null },
|
|
260
268
|
);
|
|
261
269
|
|
|
262
270
|
const field = getByPlaceholderText('Search for courses, organizations, categories');
|
|
@@ -349,6 +357,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
349
357
|
<SearchSuggestField context={context} />
|
|
350
358
|
</HistoryProvider>
|
|
351
359
|
</IntlProvider>,
|
|
360
|
+
{ wrapper: null },
|
|
352
361
|
);
|
|
353
362
|
|
|
354
363
|
const field = getByPlaceholderText('Search for courses, organizations, categories');
|
|
@@ -433,6 +442,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
433
442
|
<SearchSuggestField context={context} />
|
|
434
443
|
</HistoryProvider>
|
|
435
444
|
</IntlProvider>,
|
|
445
|
+
{ wrapper: null },
|
|
436
446
|
);
|
|
437
447
|
|
|
438
448
|
const field = getByPlaceholderText('Search for courses, organizations, categories');
|
|
@@ -477,6 +487,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
477
487
|
<SearchSuggestField context={context} />
|
|
478
488
|
</HistoryProvider>
|
|
479
489
|
</IntlProvider>,
|
|
490
|
+
{ wrapper: null },
|
|
480
491
|
);
|
|
481
492
|
|
|
482
493
|
const field = getByPlaceholderText('Search for courses, organizations, categories');
|
|
@@ -566,6 +577,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
566
577
|
<SearchSuggestField context={context} />
|
|
567
578
|
</HistoryProvider>
|
|
568
579
|
</IntlProvider>,
|
|
580
|
+
{ wrapper: null },
|
|
569
581
|
);
|
|
570
582
|
|
|
571
583
|
const field = getByPlaceholderText('Search for courses, organizations, categories');
|
|
@@ -627,6 +639,7 @@ describe('widgets/Search/components/SearchSuggestField', () => {
|
|
|
627
639
|
<SearchSuggestField context={context} />
|
|
628
640
|
</HistoryProvider>
|
|
629
641
|
</IntlProvider>,
|
|
642
|
+
{ wrapper: null },
|
|
630
643
|
);
|
|
631
644
|
|
|
632
645
|
const field = getByPlaceholderText('Search for courses, organizations, categories');
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { fireEvent,
|
|
1
|
+
import { fireEvent, screen, waitFor } from '@testing-library/react';
|
|
2
2
|
import { faker } from '@faker-js/faker';
|
|
3
3
|
import fetchMock from 'fetch-mock';
|
|
4
|
-
import { PropsWithChildren } from 'react';
|
|
5
|
-
import { IntlProvider } from 'react-intl';
|
|
6
4
|
import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
|
|
7
5
|
import { CertificationDefinitionFactory, OrderLiteFactory } from 'utils/test/factories/joanie';
|
|
8
|
-
import JoanieApiProvider from 'contexts/JoanieApiContext';
|
|
9
6
|
import { CertificateDefinition, OrderLite } from 'types/Joanie';
|
|
10
7
|
import { HttpStatusCode } from 'utils/errors/HttpError';
|
|
8
|
+
import { setupJoanieSession } from 'utils/test/wrappers/JoanieAppWrapper';
|
|
9
|
+
import { render } from 'utils/test/render';
|
|
10
|
+
import { BaseJoanieAppWrapper } from 'utils/test/wrappers/BaseJoanieAppWrapper';
|
|
11
11
|
import CertificateItem from '.';
|
|
12
12
|
|
|
13
13
|
jest.mock('utils/errors/handle');
|
|
@@ -15,16 +15,12 @@ jest.mock('utils/context', () => ({
|
|
|
15
15
|
__esModule: true,
|
|
16
16
|
default: mockRichieContextFactory({
|
|
17
17
|
authentication: { backend: 'fonzie', endpoint: 'https://auth.test' },
|
|
18
|
-
joanie_backend: { endpoint: 'https://joanie.
|
|
18
|
+
joanie_backend: { endpoint: 'https://joanie.endpoint' },
|
|
19
19
|
}).one(),
|
|
20
20
|
}));
|
|
21
21
|
|
|
22
22
|
describe('CourseProductCertificateItem', () => {
|
|
23
|
-
|
|
24
|
-
<IntlProvider locale="en">
|
|
25
|
-
<JoanieApiProvider>{children}</JoanieApiProvider>
|
|
26
|
-
</IntlProvider>
|
|
27
|
-
);
|
|
23
|
+
setupJoanieSession();
|
|
28
24
|
|
|
29
25
|
beforeAll(() => {
|
|
30
26
|
// eslint-disable-next-line compat/compat
|
|
@@ -34,19 +30,12 @@ describe('CourseProductCertificateItem', () => {
|
|
|
34
30
|
HTMLAnchorElement.prototype.click = jest.fn();
|
|
35
31
|
});
|
|
36
32
|
|
|
37
|
-
afterEach(() => {
|
|
38
|
-
fetchMock.restore();
|
|
39
|
-
jest.resetAllMocks();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
33
|
it('displays certificate information', () => {
|
|
43
34
|
const certificateDefinition: CertificateDefinition = CertificationDefinitionFactory().one();
|
|
44
35
|
|
|
45
|
-
render(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</Wrapper>,
|
|
49
|
-
);
|
|
36
|
+
render(<CertificateItem certificateDefinition={certificateDefinition} />, {
|
|
37
|
+
wrapper: BaseJoanieAppWrapper,
|
|
38
|
+
});
|
|
50
39
|
|
|
51
40
|
// the title is not a heading to prevent screen reader users "heading spam",
|
|
52
41
|
// but we want it to visually look like a heading for sighted users
|
|
@@ -60,11 +49,9 @@ describe('CourseProductCertificateItem', () => {
|
|
|
60
49
|
description: '',
|
|
61
50
|
}).one();
|
|
62
51
|
|
|
63
|
-
render(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
</Wrapper>,
|
|
67
|
-
);
|
|
52
|
+
render(<CertificateItem certificateDefinition={certificateDefinition} />, {
|
|
53
|
+
wrapper: BaseJoanieAppWrapper,
|
|
54
|
+
});
|
|
68
55
|
|
|
69
56
|
screen.getByText(
|
|
70
57
|
'You will be able to download your certificate once you will pass all course runs.',
|
|
@@ -75,11 +62,9 @@ describe('CourseProductCertificateItem', () => {
|
|
|
75
62
|
const certificateDefinition: CertificateDefinition = CertificationDefinitionFactory().one();
|
|
76
63
|
const order: OrderLite = OrderLiteFactory({ certificate_id: faker.string.uuid() }).one();
|
|
77
64
|
|
|
78
|
-
render(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
</Wrapper>,
|
|
82
|
-
);
|
|
65
|
+
render(<CertificateItem certificateDefinition={certificateDefinition} order={order} />, {
|
|
66
|
+
wrapper: BaseJoanieAppWrapper,
|
|
67
|
+
});
|
|
83
68
|
|
|
84
69
|
// - The certificate description should not be displayed ...
|
|
85
70
|
expect(screen.queryByText(certificateDefinition.description)).toBeNull();
|
|
@@ -90,7 +75,7 @@ describe('CourseProductCertificateItem', () => {
|
|
|
90
75
|
|
|
91
76
|
// When user clicks on "Download" button, the certificate should be downloaded
|
|
92
77
|
fetchMock.get(
|
|
93
|
-
`https://joanie.
|
|
78
|
+
`https://joanie.endpoint/api/v1.0/certificates/${order.certificate_id}/download/`,
|
|
94
79
|
() => ({
|
|
95
80
|
status: HttpStatusCode.OK,
|
|
96
81
|
body: new Blob(['test']),
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { act, fireEvent,
|
|
2
|
+
import { act, fireEvent, screen } from '@testing-library/react';
|
|
3
3
|
import fetchMock from 'fetch-mock';
|
|
4
4
|
import type { PropsWithChildren } from 'react';
|
|
5
5
|
import { IntlProvider, createIntl } from 'react-intl';
|
|
6
|
-
import { QueryClientProvider } from '@tanstack/react-query';
|
|
7
6
|
import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
|
|
8
7
|
import {
|
|
9
8
|
CourseLightFactory,
|
|
@@ -12,20 +11,21 @@ import {
|
|
|
12
11
|
CredentialOrderFactory,
|
|
13
12
|
ProductFactory,
|
|
14
13
|
} from 'utils/test/factories/joanie';
|
|
15
|
-
import JoanieApiProvider from 'contexts/JoanieApiContext';
|
|
16
14
|
import type { CourseLight, CourseRun, Enrollment } from 'types/Joanie';
|
|
17
15
|
import { Deferred } from 'utils/test/deferred';
|
|
18
16
|
import { CourseStateTextEnum, Priority } from 'types';
|
|
19
|
-
import { createTestQueryClient } from 'utils/test/createTestQueryClient';
|
|
20
17
|
import { IntlHelper } from 'utils/IntlHelper';
|
|
21
18
|
import { HttpStatusCode } from 'utils/errors/HttpError';
|
|
19
|
+
import { render } from 'utils/test/render';
|
|
20
|
+
import { setupJoanieSession } from 'utils/test/wrappers/JoanieAppWrapper';
|
|
21
|
+
import { BaseJoanieAppWrapper } from 'utils/test/wrappers/BaseJoanieAppWrapper';
|
|
22
22
|
import { CourseRunList, EnrollableCourseRunList, EnrolledCourseRun } from '.';
|
|
23
23
|
|
|
24
24
|
jest.mock('utils/context', () => ({
|
|
25
25
|
__esModule: true,
|
|
26
26
|
default: mockRichieContextFactory({
|
|
27
27
|
authentication: { backend: 'fonzie', endpoint: 'https://auth.test' },
|
|
28
|
-
joanie_backend: { endpoint: 'https://joanie.
|
|
28
|
+
joanie_backend: { endpoint: 'https://joanie.endpoint' },
|
|
29
29
|
}).one(),
|
|
30
30
|
}));
|
|
31
31
|
|
|
@@ -46,11 +46,7 @@ describe('CourseProductCourseRuns', () => {
|
|
|
46
46
|
);
|
|
47
47
|
|
|
48
48
|
it('renders a warning message when no course runs are provided', () => {
|
|
49
|
-
render(
|
|
50
|
-
<Wrapper>
|
|
51
|
-
<CourseRunList courseRuns={[]} />
|
|
52
|
-
</Wrapper>,
|
|
53
|
-
);
|
|
49
|
+
render(<CourseRunList courseRuns={[]} />, { wrapper: Wrapper });
|
|
54
50
|
|
|
55
51
|
expect(screen.getByText('No session available for this course.'));
|
|
56
52
|
});
|
|
@@ -58,11 +54,7 @@ describe('CourseProductCourseRuns', () => {
|
|
|
58
54
|
it('renders a list of course runs', () => {
|
|
59
55
|
const courseRuns: CourseRun[] = CourseRunFactory().many(2);
|
|
60
56
|
|
|
61
|
-
const { container } = render(
|
|
62
|
-
<Wrapper>
|
|
63
|
-
<CourseRunList courseRuns={courseRuns} />
|
|
64
|
-
</Wrapper>,
|
|
65
|
-
);
|
|
57
|
+
const { container } = render(<CourseRunList courseRuns={courseRuns} />, { wrapper: Wrapper });
|
|
66
58
|
|
|
67
59
|
// It should render all course runs provided
|
|
68
60
|
expect(screen.getAllByRole('listitem')).toHaveLength(2);
|
|
@@ -118,23 +110,16 @@ describe('CourseProductCourseRuns', () => {
|
|
|
118
110
|
});
|
|
119
111
|
|
|
120
112
|
describe('EnrollableCourseRunList', () => {
|
|
121
|
-
|
|
122
|
-
<IntlProvider locale="en">
|
|
123
|
-
<QueryClientProvider client={createTestQueryClient()}>
|
|
124
|
-
<JoanieApiProvider>{children}</JoanieApiProvider>
|
|
125
|
-
</QueryClientProvider>
|
|
126
|
-
</IntlProvider>
|
|
127
|
-
);
|
|
113
|
+
setupJoanieSession();
|
|
128
114
|
|
|
129
115
|
it('renders a warning message when no course runs are provided', () => {
|
|
130
116
|
const order = CredentialOrderFactory().one();
|
|
131
117
|
const product = ProductFactory().one();
|
|
132
118
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
);
|
|
119
|
+
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
120
|
+
render(<EnrollableCourseRunList courseRuns={[]} order={order} product={product} />, {
|
|
121
|
+
wrapper: BaseJoanieAppWrapper,
|
|
122
|
+
});
|
|
138
123
|
|
|
139
124
|
expect(screen.getByText('No session available for this course.'));
|
|
140
125
|
});
|
|
@@ -146,11 +131,10 @@ describe('CourseProductCourseRuns', () => {
|
|
|
146
131
|
contract_definition: undefined,
|
|
147
132
|
}).one();
|
|
148
133
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
);
|
|
134
|
+
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
135
|
+
render(<EnrollableCourseRunList courseRuns={courseRuns} order={order} product={product} />, {
|
|
136
|
+
wrapper: BaseJoanieAppWrapper,
|
|
137
|
+
});
|
|
154
138
|
|
|
155
139
|
// the list should contain only the course run items, without the call to action button
|
|
156
140
|
expect(screen.getAllByRole('listitem')).toHaveLength(2);
|
|
@@ -228,7 +212,7 @@ describe('CourseProductCourseRuns', () => {
|
|
|
228
212
|
// - User clicks to enroll
|
|
229
213
|
fetchMock.resetHistory();
|
|
230
214
|
const enrollmentDeferred = new Deferred();
|
|
231
|
-
fetchMock.post('https://joanie.
|
|
215
|
+
fetchMock.post('https://joanie.endpoint/api/v1.0/enrollments/', enrollmentDeferred.promise);
|
|
232
216
|
|
|
233
217
|
await act(async () => {
|
|
234
218
|
fireEvent.click($button);
|
|
@@ -241,10 +225,12 @@ describe('CourseProductCourseRuns', () => {
|
|
|
241
225
|
enrollmentDeferred.resolve(HttpStatusCode.OK);
|
|
242
226
|
});
|
|
243
227
|
|
|
244
|
-
const
|
|
245
|
-
|
|
228
|
+
const calledUrls = fetchMock.calls().map((call) => call[0]);
|
|
229
|
+
let nbApiCalls = 1; // post enrollments
|
|
230
|
+
nbApiCalls += 1; // refetch enrollments
|
|
231
|
+
expect(calledUrls).toHaveLength(nbApiCalls);
|
|
246
232
|
// A request to create the enrollment should have been executed
|
|
247
|
-
expect(
|
|
233
|
+
expect(calledUrls[0]).toBe('https://joanie.endpoint/api/v1.0/enrollments/');
|
|
248
234
|
expect(JSON.parse(fetchMock.calls()[0][1]!.body as string)).toEqual({
|
|
249
235
|
is_active: true,
|
|
250
236
|
course_run_id: courseRuns[0].id,
|
|
@@ -258,13 +244,12 @@ describe('CourseProductCourseRuns', () => {
|
|
|
258
244
|
const order = CredentialOrderFactory().one();
|
|
259
245
|
const product = ProductFactory().one();
|
|
260
246
|
product.contract_definition = undefined;
|
|
261
|
-
fetchMock.get(`https://joanie.
|
|
247
|
+
fetchMock.get(`https://joanie.endpoint/api/v1.0/courses/${course.code}/`, HttpStatusCode.OK);
|
|
248
|
+
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
262
249
|
|
|
263
|
-
render(
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
</Wrapper>,
|
|
267
|
-
);
|
|
250
|
+
render(<EnrollableCourseRunList courseRuns={courseRuns} order={order} product={product} />, {
|
|
251
|
+
wrapper: BaseJoanieAppWrapper,
|
|
252
|
+
});
|
|
268
253
|
|
|
269
254
|
// the list should contain only the course run items, without the call to action button
|
|
270
255
|
expect(screen.getAllByRole('listitem')).toHaveLength(2);
|
|
@@ -333,7 +318,7 @@ describe('CourseProductCourseRuns', () => {
|
|
|
333
318
|
// - User clicks to enroll
|
|
334
319
|
fetchMock.resetHistory();
|
|
335
320
|
const enrollmentDeferred = new Deferred();
|
|
336
|
-
fetchMock.post('https://joanie.
|
|
321
|
+
fetchMock.post('https://joanie.endpoint/api/v1.0/enrollments/', enrollmentDeferred.promise);
|
|
337
322
|
|
|
338
323
|
await act(async () => {
|
|
339
324
|
fireEvent.click($button);
|
|
@@ -374,11 +359,10 @@ describe('CourseProductCourseRuns', () => {
|
|
|
374
359
|
product.contract_definition = undefined;
|
|
375
360
|
const order = CredentialOrderFactory().one();
|
|
376
361
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
);
|
|
362
|
+
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
363
|
+
render(<EnrollableCourseRunList courseRuns={[courseRun]} order={order} product={product} />, {
|
|
364
|
+
wrapper: BaseJoanieAppWrapper,
|
|
365
|
+
});
|
|
382
366
|
|
|
383
367
|
// the list should contain only the course run items, without the call to action button
|
|
384
368
|
expect(screen.getAllByRole('listitem')).toHaveLength(1);
|
|
@@ -413,7 +397,7 @@ describe('CourseProductCourseRuns', () => {
|
|
|
413
397
|
// it should be enabled already to allow early user feedback
|
|
414
398
|
expect($button.disabled).toBe(false);
|
|
415
399
|
|
|
416
|
-
fetchMock.post('https://joanie.
|
|
400
|
+
fetchMock.post('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
417
401
|
await act(async () => {
|
|
418
402
|
// - Select the first course run
|
|
419
403
|
const $radio = screen.getByRole('radio', {
|
|
@@ -457,11 +441,10 @@ describe('CourseProductCourseRuns', () => {
|
|
|
457
441
|
const product = ProductFactory().one();
|
|
458
442
|
const order = CredentialOrderFactory().one();
|
|
459
443
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
);
|
|
444
|
+
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
445
|
+
render(<EnrollableCourseRunList courseRuns={[courseRun]} order={order} product={product} />, {
|
|
446
|
+
wrapper: BaseJoanieAppWrapper,
|
|
447
|
+
});
|
|
465
448
|
|
|
466
449
|
// the list should contain only the course run items, without the call to action button
|
|
467
450
|
expect(screen.getAllByRole('listitem')).toHaveLength(1);
|
|
@@ -502,22 +485,14 @@ describe('CourseProductCourseRuns', () => {
|
|
|
502
485
|
});
|
|
503
486
|
|
|
504
487
|
describe('EnrolledCourseRun', () => {
|
|
505
|
-
|
|
506
|
-
<IntlProvider locale="en">
|
|
507
|
-
<QueryClientProvider client={createTestQueryClient()}>
|
|
508
|
-
<JoanieApiProvider>{children}</JoanieApiProvider>
|
|
509
|
-
</QueryClientProvider>
|
|
510
|
-
</IntlProvider>
|
|
511
|
-
);
|
|
512
|
-
|
|
488
|
+
setupJoanieSession();
|
|
513
489
|
it('renders enrollment information', () => {
|
|
514
490
|
const enrollment: Enrollment = EnrollmentFactory().one();
|
|
515
491
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
);
|
|
492
|
+
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
493
|
+
render(<EnrolledCourseRun enrollment={enrollment} />, {
|
|
494
|
+
wrapper: BaseJoanieAppWrapper,
|
|
495
|
+
});
|
|
521
496
|
|
|
522
497
|
// - It should render course dates,
|
|
523
498
|
const $startDate = screen.getByTestId(`enrollment-${enrollment.id}-start-date`);
|
|
@@ -560,11 +535,10 @@ describe('CourseProductCourseRuns', () => {
|
|
|
560
535
|
},
|
|
561
536
|
};
|
|
562
537
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
);
|
|
538
|
+
fetchMock.get('https://joanie.endpoint/api/v1.0/enrollments/', []);
|
|
539
|
+
render(<EnrolledCourseRun enrollment={newEnrollment} />, {
|
|
540
|
+
wrapper: BaseJoanieAppWrapper,
|
|
541
|
+
});
|
|
568
542
|
|
|
569
543
|
await screen.getByText('You are enrolled');
|
|
570
544
|
await screen.getByText('The course starts in 2 months');
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { screen, getByText
|
|
2
|
+
import { screen, getByText } from '@testing-library/react';
|
|
3
3
|
import { CredentialOrderFactory, ProductFactory } from 'utils/test/factories/joanie';
|
|
4
4
|
import type { CourseRun, CredentialOrder } from 'types/Joanie';
|
|
5
5
|
import { OrderState } from 'types/Joanie';
|
|
6
|
+
import { render } from 'utils/test/render';
|
|
6
7
|
import CourseRunItem from '.';
|
|
7
8
|
|
|
8
9
|
jest.mock('../CourseProductCourseRuns', () => ({
|
|
@@ -21,7 +22,9 @@ describe('CourseRunItem', () => {
|
|
|
21
22
|
|
|
22
23
|
const targetCourse = order.target_courses[0];
|
|
23
24
|
|
|
24
|
-
render(<CourseRunItem targetCourse={targetCourse} order={order} product={product}
|
|
25
|
+
render(<CourseRunItem targetCourse={targetCourse} order={order} product={product} />, {
|
|
26
|
+
wrapper: null,
|
|
27
|
+
});
|
|
25
28
|
|
|
26
29
|
// - It should render CourseRunList component
|
|
27
30
|
const $item = screen.getByTestId(`course-item-${targetCourse.code}`);
|