richie-education 2.25.0-b2.dev124 → 2.25.0-b2.dev127
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/hooks/useUnionResource/index.spec.tsx +98 -97
- package/js/hooks/useUnionResource/index.ts +23 -2
- package/js/pages/DashboardCourses/index.spec.tsx +17 -49
- package/js/utils/test/wrappers/BaseAppWrapper.tsx +19 -0
- package/js/utils/test/wrappers/BaseJoanieAppWrapper.tsx +20 -0
- package/js/utils/test/wrappers/JoanieAppWrapper.tsx +6 -16
- package/js/widgets/Dashboard/components/DashboardItem/Order/DashboardItemOrderContract.useUnionResource.cache.spec.tsx +8 -24
- package/package.json +1 -1
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import { renderHook, act, waitFor } from '@testing-library/react';
|
|
2
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
3
|
-
import { IntlProvider } from 'react-intl';
|
|
4
2
|
import fetchMock from 'fetch-mock';
|
|
5
|
-
import
|
|
3
|
+
import queryString from 'query-string';
|
|
6
4
|
import { PaginatedResourceQuery } from 'types/Joanie';
|
|
7
|
-
import { History, HistoryContext } from 'hooks/useHistory';
|
|
8
|
-
import { createTestQueryClient } from 'utils/test/createTestQueryClient';
|
|
9
|
-
import { SessionProvider } from 'contexts/SessionContext';
|
|
10
5
|
import { Deferred } from 'utils/test/deferred';
|
|
11
|
-
|
|
12
6
|
import { noop } from 'utils';
|
|
13
7
|
import { mockPaginatedResponse } from 'utils/test/mockPaginatedResponse';
|
|
14
8
|
import { PER_PAGE } from 'settings';
|
|
15
9
|
import { HttpError, HttpStatusCode } from 'utils/errors/HttpError';
|
|
16
|
-
import {
|
|
10
|
+
import { BaseAppWrapper } from 'utils/test/wrappers/BaseAppWrapper';
|
|
17
11
|
import { QueryConfig, FetchDataFunction } from './utils/fetchEntity';
|
|
18
12
|
import useUnionResource from '.';
|
|
19
13
|
|
|
@@ -37,49 +31,6 @@ interface TestDataB {
|
|
|
37
31
|
created_on: string;
|
|
38
32
|
}
|
|
39
33
|
|
|
40
|
-
const renderUseUnionResource = <
|
|
41
|
-
DataA extends FetchEntityData,
|
|
42
|
-
DataB extends FetchEntityData,
|
|
43
|
-
FiltersA extends PaginatedResourceQuery,
|
|
44
|
-
FiltersB extends PaginatedResourceQuery,
|
|
45
|
-
>(
|
|
46
|
-
queryAConfig: QueryConfig<DataA, FiltersA>,
|
|
47
|
-
queryBConfig: QueryConfig<DataB, FiltersB>,
|
|
48
|
-
) => {
|
|
49
|
-
const Wrapper = ({ client, children }: PropsWithChildren<{ client?: QueryClient }>) => {
|
|
50
|
-
const historyPushState = jest.fn();
|
|
51
|
-
const historyReplaceState = jest.fn();
|
|
52
|
-
const makeHistoryOf: (params: any) => History = () => [
|
|
53
|
-
{
|
|
54
|
-
state: { name: '', data: {} },
|
|
55
|
-
title: '',
|
|
56
|
-
url: `/`,
|
|
57
|
-
},
|
|
58
|
-
historyPushState,
|
|
59
|
-
historyReplaceState,
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<QueryClientProvider client={client ?? createTestQueryClient({ user: true })}>
|
|
64
|
-
<IntlProvider locale="en">
|
|
65
|
-
<HistoryContext.Provider value={makeHistoryOf({})}>
|
|
66
|
-
<SessionProvider>{children}</SessionProvider>
|
|
67
|
-
</HistoryContext.Provider>
|
|
68
|
-
</IntlProvider>
|
|
69
|
-
</QueryClientProvider>
|
|
70
|
-
);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
return renderHook(
|
|
74
|
-
() =>
|
|
75
|
-
useUnionResource<DataA, DataB, FiltersA, FiltersB>({
|
|
76
|
-
queryAConfig,
|
|
77
|
-
queryBConfig,
|
|
78
|
-
}),
|
|
79
|
-
{ wrapper: Wrapper },
|
|
80
|
-
);
|
|
81
|
-
};
|
|
82
|
-
|
|
83
34
|
describe('useUnionResource', () => {
|
|
84
35
|
const perPage = PER_PAGE.useUnionResources;
|
|
85
36
|
let dataAList: TestDataA[];
|
|
@@ -111,14 +62,14 @@ describe('useUnionResource', () => {
|
|
|
111
62
|
|
|
112
63
|
{ name: 'TestDataB', id: '14', created_on: '2022-12-03' },
|
|
113
64
|
];
|
|
114
|
-
const dummyFetchWrapper = async (url: string) => {
|
|
115
|
-
const res = await fetch(url);
|
|
65
|
+
const dummyFetchWrapper = async (url: string, queryParams: { [key: string]: any }) => {
|
|
66
|
+
const res = await fetch(`${url}?${queryString.stringify(queryParams)}`);
|
|
116
67
|
return res.json();
|
|
117
68
|
};
|
|
118
|
-
const fetchDataA = ({ page }: { page: number }) =>
|
|
119
|
-
dummyFetchWrapper(
|
|
69
|
+
const fetchDataA = ({ page, isFiltered }: { page: number; isFiltered?: boolean }) =>
|
|
70
|
+
dummyFetchWrapper('http://data.a/', { page, isFiltered });
|
|
120
71
|
const fetchDataB = ({ page }: { page: number }) =>
|
|
121
|
-
dummyFetchWrapper(
|
|
72
|
+
dummyFetchWrapper('http://data.b/', { page });
|
|
122
73
|
|
|
123
74
|
queryAConfig = {
|
|
124
75
|
queryKey: ['resourceA'],
|
|
@@ -132,11 +83,6 @@ describe('useUnionResource', () => {
|
|
|
132
83
|
};
|
|
133
84
|
});
|
|
134
85
|
|
|
135
|
-
afterEach(() => {
|
|
136
|
-
jest.clearAllMocks();
|
|
137
|
-
fetchMock.restore();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
86
|
it('should handle loading state', async () => {
|
|
141
87
|
const dataADeferred = new Deferred();
|
|
142
88
|
const dataBDeferred = new Deferred();
|
|
@@ -144,12 +90,16 @@ describe('useUnionResource', () => {
|
|
|
144
90
|
const pendingDataBPromise = () => dataBDeferred.promise;
|
|
145
91
|
queryAConfig.fn = pendingDataAPromise as FetchDataFunction<TestDataA, TestDataAFilters>;
|
|
146
92
|
queryBConfig.fn = pendingDataBPromise as FetchDataFunction<TestDataB, PaginatedResourceQuery>;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
93
|
+
|
|
94
|
+
const { result } = renderHook(
|
|
95
|
+
() =>
|
|
96
|
+
useUnionResource<TestDataA, TestDataB, TestDataAFilters, PaginatedResourceQuery>({
|
|
97
|
+
queryAConfig,
|
|
98
|
+
queryBConfig,
|
|
99
|
+
}),
|
|
100
|
+
{ wrapper: BaseAppWrapper },
|
|
101
|
+
);
|
|
102
|
+
|
|
153
103
|
expect(result.current.isLoading).toBe(true);
|
|
154
104
|
expect(result.current.hasMore).toBe(false);
|
|
155
105
|
|
|
@@ -164,12 +114,15 @@ describe('useUnionResource', () => {
|
|
|
164
114
|
it('should render less than 1 page of dataA', async () => {
|
|
165
115
|
fetchMock.get('http://data.a/?page=1', mockPaginatedResponse([dataAList[0]], 1, false));
|
|
166
116
|
fetchMock.get('http://data.b/?page=1', mockPaginatedResponse([], 0, false));
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
117
|
+
|
|
118
|
+
const { result } = renderHook(
|
|
119
|
+
() =>
|
|
120
|
+
useUnionResource<TestDataA, TestDataB, TestDataAFilters, PaginatedResourceQuery>({
|
|
121
|
+
queryAConfig,
|
|
122
|
+
queryBConfig,
|
|
123
|
+
}),
|
|
124
|
+
{ wrapper: BaseAppWrapper },
|
|
125
|
+
);
|
|
173
126
|
|
|
174
127
|
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
175
128
|
expect(result.current.hasMore).toBe(false);
|
|
@@ -180,12 +133,15 @@ describe('useUnionResource', () => {
|
|
|
180
133
|
it('should render less than 1 page of dataB', async () => {
|
|
181
134
|
fetchMock.get('http://data.a/?page=1', mockPaginatedResponse([], 0, false));
|
|
182
135
|
fetchMock.get('http://data.b/?page=1', mockPaginatedResponse([dataBList[0]], 1, false));
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
136
|
+
|
|
137
|
+
const { result } = renderHook(
|
|
138
|
+
() =>
|
|
139
|
+
useUnionResource<TestDataA, TestDataB, TestDataAFilters, PaginatedResourceQuery>({
|
|
140
|
+
queryAConfig,
|
|
141
|
+
queryBConfig,
|
|
142
|
+
}),
|
|
143
|
+
{ wrapper: BaseAppWrapper },
|
|
144
|
+
);
|
|
189
145
|
|
|
190
146
|
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
191
147
|
expect(result.current.hasMore).toBe(false);
|
|
@@ -196,12 +152,15 @@ describe('useUnionResource', () => {
|
|
|
196
152
|
it('should renders less than 1 page of both dataA and dataB', async () => {
|
|
197
153
|
fetchMock.get('http://data.a/?page=1', mockPaginatedResponse([dataAList[0]], 1, false));
|
|
198
154
|
fetchMock.get('http://data.b/?page=1', mockPaginatedResponse([dataBList[0]], 1, false));
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
155
|
+
|
|
156
|
+
const { result } = renderHook(
|
|
157
|
+
() =>
|
|
158
|
+
useUnionResource<TestDataA, TestDataB, TestDataAFilters, PaginatedResourceQuery>({
|
|
159
|
+
queryAConfig,
|
|
160
|
+
queryBConfig,
|
|
161
|
+
}),
|
|
162
|
+
{ wrapper: BaseAppWrapper },
|
|
163
|
+
);
|
|
205
164
|
|
|
206
165
|
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
207
166
|
expect(result.current.hasMore).toBe(false);
|
|
@@ -237,12 +196,14 @@ describe('useUnionResource', () => {
|
|
|
237
196
|
mockPaginatedResponse(dataBList.slice(perPage * 2, perPage * 3), dataAList.length, false),
|
|
238
197
|
);
|
|
239
198
|
|
|
240
|
-
const { result } =
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
199
|
+
const { result } = renderHook(
|
|
200
|
+
() =>
|
|
201
|
+
useUnionResource<TestDataA, TestDataB, TestDataAFilters, PaginatedResourceQuery>({
|
|
202
|
+
queryAConfig,
|
|
203
|
+
queryBConfig,
|
|
204
|
+
}),
|
|
205
|
+
{ wrapper: BaseAppWrapper },
|
|
206
|
+
);
|
|
246
207
|
|
|
247
208
|
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
248
209
|
expect(result.current.hasMore).toBe(true);
|
|
@@ -297,12 +258,16 @@ describe('useUnionResource', () => {
|
|
|
297
258
|
const dataADeferred = new Deferred();
|
|
298
259
|
const pendingDataAPromise = () => dataADeferred.promise;
|
|
299
260
|
queryAConfig.fn = pendingDataAPromise as FetchDataFunction<TestDataA, TestDataAFilters>;
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
261
|
+
|
|
262
|
+
const { result } = renderHook(
|
|
263
|
+
() =>
|
|
264
|
+
useUnionResource<TestDataA, TestDataB, TestDataAFilters, PaginatedResourceQuery>({
|
|
265
|
+
queryAConfig,
|
|
266
|
+
queryBConfig,
|
|
267
|
+
}),
|
|
268
|
+
{ wrapper: BaseAppWrapper },
|
|
269
|
+
);
|
|
270
|
+
|
|
306
271
|
expect(result.current.isLoading).toBe(true);
|
|
307
272
|
|
|
308
273
|
await act(() => {
|
|
@@ -313,4 +278,40 @@ describe('useUnionResource', () => {
|
|
|
313
278
|
expect(result.current.isLoading).toBe(false);
|
|
314
279
|
expect(result.current.error).toBe('An error occurred while fetching data. Please retry later.');
|
|
315
280
|
});
|
|
281
|
+
|
|
282
|
+
it('should refetch data when filters change', async () => {
|
|
283
|
+
fetchMock.get('http://data.a/?page=1', mockPaginatedResponse([dataAList[0]], 1, false));
|
|
284
|
+
fetchMock.get('http://data.b/?page=1', mockPaginatedResponse([], 0, false));
|
|
285
|
+
|
|
286
|
+
const { result, rerender } = renderHook(
|
|
287
|
+
(queries: {
|
|
288
|
+
queryA?: QueryConfig<TestDataA, TestDataAFilters>;
|
|
289
|
+
queryB?: QueryConfig<TestDataB, PaginatedResourceQuery>;
|
|
290
|
+
}) =>
|
|
291
|
+
useUnionResource<TestDataA, TestDataB, TestDataAFilters, PaginatedResourceQuery>({
|
|
292
|
+
queryAConfig: queries?.queryA || queryAConfig,
|
|
293
|
+
queryBConfig: queries?.queryB || queryBConfig,
|
|
294
|
+
}),
|
|
295
|
+
{ wrapper: BaseAppWrapper },
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
299
|
+
let calledUrls = fetchMock.calls().map((call) => call[0]);
|
|
300
|
+
expect(calledUrls).toHaveLength(2);
|
|
301
|
+
expect(calledUrls).toContain('http://data.a/?page=1');
|
|
302
|
+
expect(calledUrls).toContain('http://data.b/?page=1');
|
|
303
|
+
|
|
304
|
+
queryAConfig.filters = { isFiltered: true };
|
|
305
|
+
fetchMock.get(
|
|
306
|
+
'http://data.a/?isFiltered=true&page=1',
|
|
307
|
+
mockPaginatedResponse([dataAList[0]], 1, false),
|
|
308
|
+
);
|
|
309
|
+
rerender({ queryA: queryAConfig, queryB: queryBConfig });
|
|
310
|
+
expect(result.current.isLoading).toBe(true);
|
|
311
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
312
|
+
|
|
313
|
+
calledUrls = fetchMock.calls().map((call) => call[0]);
|
|
314
|
+
expect(calledUrls).toHaveLength(4);
|
|
315
|
+
expect(calledUrls).toContain('http://data.a/?isFiltered=true&page=1');
|
|
316
|
+
});
|
|
316
317
|
});
|
|
@@ -90,6 +90,8 @@ const useUnionResource = <
|
|
|
90
90
|
const eofRef = useRef<Record<string, number>>(queryClient.getQueryData(eofQueryKey) ?? {});
|
|
91
91
|
log('eof', eofRef.current);
|
|
92
92
|
|
|
93
|
+
const [unionQueryKey, setUnionQueryKey] = useState<string>();
|
|
94
|
+
|
|
93
95
|
const reset = () => {
|
|
94
96
|
setStack([]);
|
|
95
97
|
setPage(0);
|
|
@@ -104,6 +106,18 @@ const useUnionResource = <
|
|
|
104
106
|
useQueryKeyInvalidateListener(queryBConfig.queryKey, reset);
|
|
105
107
|
}
|
|
106
108
|
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
// filters have changes, new results will be fetch.
|
|
111
|
+
// let's reset every previous fetches states
|
|
112
|
+
reset();
|
|
113
|
+
|
|
114
|
+
// We need to fetch new results.
|
|
115
|
+
// reset all states isn't enought. If we've a research without results
|
|
116
|
+
// then the next reset would do nothing.
|
|
117
|
+
// to force execution of useEffect::fetchNewPage(), we use a uniq key build with current queries filters.
|
|
118
|
+
setUnionQueryKey(JSON.stringify(queryAConfig.filters) + JSON.stringify(queryBConfig.filters));
|
|
119
|
+
}, [JSON.stringify(queryAConfig.filters), JSON.stringify(queryBConfig.filters)]);
|
|
120
|
+
|
|
107
121
|
useEffect(() => {
|
|
108
122
|
async function fetchNewPage() {
|
|
109
123
|
const {
|
|
@@ -145,11 +159,18 @@ const useUnionResource = <
|
|
|
145
159
|
|
|
146
160
|
// we request more entities than we can display in the right order
|
|
147
161
|
// it's time for new fetching and sorting.
|
|
148
|
-
if (cursor > integrityCount) {
|
|
162
|
+
if (!isSyncing && cursor > integrityCount) {
|
|
149
163
|
setIsSyncing(true);
|
|
150
164
|
fetchNewPage();
|
|
151
165
|
}
|
|
152
|
-
}, [
|
|
166
|
+
}, [
|
|
167
|
+
cursor,
|
|
168
|
+
// FIXME(rlecellier): when stack.length === 0, invalidate the query will not refetch.
|
|
169
|
+
// stack.length is added in the dependency array to force a new fetch on reset.
|
|
170
|
+
stack.length,
|
|
171
|
+
// unionQueryKey assure that we refetch data when query filters change.
|
|
172
|
+
unionQueryKey,
|
|
173
|
+
]);
|
|
153
174
|
|
|
154
175
|
const cursorToUse = Math.min(cursor, integrityCount);
|
|
155
176
|
const next = () => {
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import { act, getByRole,
|
|
2
|
-
import { QueryClient
|
|
3
|
-
import { IntlProvider } from 'react-intl';
|
|
1
|
+
import { act, getByRole, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
4
3
|
import fetchMock from 'fetch-mock';
|
|
5
4
|
import userEvent from '@testing-library/user-event';
|
|
6
|
-
import {
|
|
7
|
-
UserFactory,
|
|
8
|
-
RichieContextFactory as mockRichieContextFactory,
|
|
9
|
-
} from 'utils/test/factories/richie';
|
|
10
|
-
import { History, HistoryContext } from 'hooks/useHistory';
|
|
5
|
+
import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
|
|
11
6
|
import { DashboardTest } from 'widgets/Dashboard/components/DashboardTest';
|
|
12
7
|
import {
|
|
13
8
|
CourseProductRelationFactory,
|
|
@@ -15,7 +10,6 @@ import {
|
|
|
15
10
|
CredentialOrderFactory,
|
|
16
11
|
} from 'utils/test/factories/joanie';
|
|
17
12
|
import { createTestQueryClient } from 'utils/test/createTestQueryClient';
|
|
18
|
-
import { SessionProvider } from 'contexts/SessionContext';
|
|
19
13
|
import { LearnerDashboardPaths } from 'widgets/Dashboard/utils/learnerRouteMessages';
|
|
20
14
|
import { CourseLight, CourseProductRelation, Enrollment, CredentialOrder } from 'types/Joanie';
|
|
21
15
|
import { expectNoSpinner, expectSpinner } from 'utils/test/expectSpinner';
|
|
@@ -25,6 +19,9 @@ import { isOrder } from 'pages/DashboardCourses/useOrdersEnrollments';
|
|
|
25
19
|
import { noop } from 'utils';
|
|
26
20
|
import { PER_PAGE } from 'settings';
|
|
27
21
|
import { HttpStatusCode } from 'utils/errors/HttpError';
|
|
22
|
+
import { setupJoanieSession } from 'utils/test/wrappers/JoanieAppWrapper';
|
|
23
|
+
import { render } from 'utils/test/render';
|
|
24
|
+
import { BaseJoanieAppWrapper } from 'utils/test/wrappers/BaseJoanieAppWrapper';
|
|
28
25
|
|
|
29
26
|
jest.mock('utils/context', () => ({
|
|
30
27
|
__esModule: true,
|
|
@@ -52,44 +49,8 @@ jest.mock('hooks/useIntersectionObserver', () => ({
|
|
|
52
49
|
}));
|
|
53
50
|
|
|
54
51
|
describe('<DashboardCourses/>', () => {
|
|
52
|
+
setupJoanieSession();
|
|
55
53
|
const perPage = PER_PAGE.useOrdersEnrollments;
|
|
56
|
-
const historyPushState = jest.fn();
|
|
57
|
-
const historyReplaceState = jest.fn();
|
|
58
|
-
const makeHistoryOf: (params: any) => History = () => [
|
|
59
|
-
{
|
|
60
|
-
state: { name: '', data: {} },
|
|
61
|
-
title: '',
|
|
62
|
-
url: `/`,
|
|
63
|
-
},
|
|
64
|
-
historyPushState,
|
|
65
|
-
historyReplaceState,
|
|
66
|
-
];
|
|
67
|
-
|
|
68
|
-
beforeEach(() => {
|
|
69
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/addresses/', []);
|
|
70
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', []);
|
|
71
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/orders/', []);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
afterEach(() => {
|
|
75
|
-
jest.clearAllMocks();
|
|
76
|
-
fetchMock.restore();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
const Wrapper = ({ client }: { client?: QueryClient }) => {
|
|
80
|
-
const user = UserFactory().one();
|
|
81
|
-
return (
|
|
82
|
-
<QueryClientProvider client={client ?? createTestQueryClient({ user })}>
|
|
83
|
-
<IntlProvider locale="en">
|
|
84
|
-
<HistoryContext.Provider value={makeHistoryOf({})}>
|
|
85
|
-
<SessionProvider>
|
|
86
|
-
<DashboardTest initialRoute={LearnerDashboardPaths.COURSES} />
|
|
87
|
-
</SessionProvider>
|
|
88
|
-
</HistoryContext.Provider>
|
|
89
|
-
</IntlProvider>
|
|
90
|
-
</QueryClientProvider>
|
|
91
|
-
);
|
|
92
|
-
};
|
|
93
54
|
|
|
94
55
|
const mockOrders = (orders: CredentialOrder[], client?: QueryClient) => {
|
|
95
56
|
const relations: Record<string, CourseProductRelation> = {};
|
|
@@ -150,7 +111,9 @@ describe('<DashboardCourses/>', () => {
|
|
|
150
111
|
enrollmentsDeferred.promise,
|
|
151
112
|
);
|
|
152
113
|
|
|
153
|
-
render(<
|
|
114
|
+
render(<DashboardTest initialRoute={LearnerDashboardPaths.COURSES} />, {
|
|
115
|
+
wrapper: BaseJoanieAppWrapper,
|
|
116
|
+
});
|
|
154
117
|
|
|
155
118
|
await expectSpinner('Loading orders and enrollments...');
|
|
156
119
|
expect(await screen.queryByRole('button', { name: 'Load more' })).not.toBeInTheDocument();
|
|
@@ -242,7 +205,9 @@ describe('<DashboardCourses/>', () => {
|
|
|
242
205
|
|
|
243
206
|
const entities = merge(orders, enrollments);
|
|
244
207
|
|
|
245
|
-
render(<
|
|
208
|
+
render(<DashboardTest initialRoute={LearnerDashboardPaths.COURSES} />, {
|
|
209
|
+
wrapper: BaseJoanieAppWrapper,
|
|
210
|
+
});
|
|
246
211
|
|
|
247
212
|
// Slice 1.
|
|
248
213
|
await expectNoSpinner('Loading orders and enrollments...');
|
|
@@ -277,7 +242,10 @@ describe('<DashboardCourses/>', () => {
|
|
|
277
242
|
{ results: [], next: null, previous: null, count: 0 },
|
|
278
243
|
);
|
|
279
244
|
|
|
280
|
-
render(<
|
|
245
|
+
render(<DashboardTest initialRoute={LearnerDashboardPaths.COURSES} />, {
|
|
246
|
+
wrapper: BaseJoanieAppWrapper,
|
|
247
|
+
});
|
|
248
|
+
|
|
281
249
|
ordersDeferred.resolve({
|
|
282
250
|
status: HttpStatusCode.INTERNAL_SERVER_ERROR,
|
|
283
251
|
body: 'Internal Server Error',
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { SessionProvider } from 'contexts/SessionContext';
|
|
3
|
+
import { IntlWrapper } from './IntlWrapper';
|
|
4
|
+
import { ReactQueryWrapper } from './ReactQueryWrapper';
|
|
5
|
+
import { AppWrapperProps } from './types';
|
|
6
|
+
|
|
7
|
+
export const BaseAppWrapper = ({
|
|
8
|
+
children,
|
|
9
|
+
intlOptions,
|
|
10
|
+
queryOptions,
|
|
11
|
+
}: PropsWithChildren<AppWrapperProps>) => {
|
|
12
|
+
return (
|
|
13
|
+
<IntlWrapper {...(intlOptions || { locale: 'en' })}>
|
|
14
|
+
<ReactQueryWrapper {...(queryOptions || {})}>
|
|
15
|
+
<SessionProvider>{children}</SessionProvider>
|
|
16
|
+
</ReactQueryWrapper>
|
|
17
|
+
</IntlWrapper>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
|
|
3
|
+
import JoanieSessionProvider from 'contexts/SessionContext/JoanieSessionProvider';
|
|
4
|
+
import { IntlWrapper } from './IntlWrapper';
|
|
5
|
+
import { ReactQueryWrapper } from './ReactQueryWrapper';
|
|
6
|
+
import { AppWrapperProps } from './types';
|
|
7
|
+
|
|
8
|
+
export const BaseJoanieAppWrapper = ({
|
|
9
|
+
children,
|
|
10
|
+
intlOptions,
|
|
11
|
+
queryOptions,
|
|
12
|
+
}: PropsWithChildren<AppWrapperProps>) => {
|
|
13
|
+
return (
|
|
14
|
+
<IntlWrapper {...(intlOptions || { locale: 'en' })}>
|
|
15
|
+
<ReactQueryWrapper {...(queryOptions || {})}>
|
|
16
|
+
<JoanieSessionProvider>{children}</JoanieSessionProvider>
|
|
17
|
+
</ReactQueryWrapper>
|
|
18
|
+
</IntlWrapper>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { CunninghamProvider } from '@openfun/cunningham-react';
|
|
2
2
|
import { PropsWithChildren } from 'react';
|
|
3
3
|
import fetchMock from 'fetch-mock';
|
|
4
|
-
import JoanieSessionProvider from 'contexts/SessionContext/JoanieSessionProvider';
|
|
5
4
|
import { DashboardBreadcrumbsProvider } from 'widgets/Dashboard/contexts/DashboardBreadcrumbsContext';
|
|
6
|
-
import { IntlWrapper } from './IntlWrapper';
|
|
7
|
-
import { ReactQueryWrapper } from './ReactQueryWrapper';
|
|
8
5
|
import { RouterWrapper } from './RouterWrapper';
|
|
9
6
|
import { AppWrapperProps } from './types';
|
|
7
|
+
import { BaseJoanieAppWrapper } from './BaseJoanieAppWrapper';
|
|
10
8
|
|
|
11
9
|
export const setupJoanieSession = () => {
|
|
12
10
|
beforeEach(() => {
|
|
@@ -21,10 +19,6 @@ export const setupJoanieSession = () => {
|
|
|
21
19
|
};
|
|
22
20
|
};
|
|
23
21
|
|
|
24
|
-
export const JoanieSessionWrapper = ({ children }: PropsWithChildren) => {
|
|
25
|
-
return <JoanieSessionProvider>{children}</JoanieSessionProvider>;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
22
|
export const JoanieAppWrapper = ({
|
|
29
23
|
children,
|
|
30
24
|
intlOptions,
|
|
@@ -32,16 +26,12 @@ export const JoanieAppWrapper = ({
|
|
|
32
26
|
routerOptions,
|
|
33
27
|
}: PropsWithChildren<AppWrapperProps>) => {
|
|
34
28
|
return (
|
|
35
|
-
<
|
|
29
|
+
<BaseJoanieAppWrapper intlOptions={intlOptions} queryOptions={queryOptions}>
|
|
36
30
|
<CunninghamProvider>
|
|
37
|
-
<
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
<RouterWrapper {...routerOptions}>{children}</RouterWrapper>
|
|
41
|
-
</DashboardBreadcrumbsProvider>
|
|
42
|
-
</JoanieSessionWrapper>
|
|
43
|
-
</ReactQueryWrapper>
|
|
31
|
+
<DashboardBreadcrumbsProvider>
|
|
32
|
+
<RouterWrapper {...routerOptions}>{children}</RouterWrapper>
|
|
33
|
+
</DashboardBreadcrumbsProvider>
|
|
44
34
|
</CunninghamProvider>
|
|
45
|
-
</
|
|
35
|
+
</BaseJoanieAppWrapper>
|
|
46
36
|
);
|
|
47
37
|
};
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
// FIXME: this test is about useUnionResource behavior.
|
|
2
2
|
// we need to rewrite it in useUnionResource tests suite as small and generic as possible.
|
|
3
|
-
import { QueryClientProvider } from '@tanstack/react-query';
|
|
4
|
-
import { IntlProvider } from 'react-intl';
|
|
5
3
|
import fetchMock from 'fetch-mock';
|
|
6
|
-
import { act,
|
|
4
|
+
import { act, screen, waitFor, within } from '@testing-library/react';
|
|
7
5
|
import userEvent from '@testing-library/user-event';
|
|
8
6
|
import { RichieContextFactory as mockRichieContextFactory } from 'utils/test/factories/richie';
|
|
9
|
-
import { createTestQueryClient } from 'utils/test/createTestQueryClient';
|
|
10
|
-
import { SessionProvider } from 'contexts/SessionContext';
|
|
11
7
|
import { DashboardTest } from 'widgets/Dashboard/components/DashboardTest';
|
|
12
8
|
import {
|
|
13
9
|
ContractFactory,
|
|
@@ -19,6 +15,9 @@ import { LearnerDashboardPaths } from 'widgets/Dashboard/utils/learnerRouteMessa
|
|
|
19
15
|
import { Deferred } from 'utils/test/deferred';
|
|
20
16
|
import { expectNoSpinner, expectSpinner } from 'utils/test/expectSpinner';
|
|
21
17
|
import { CONTRACT_SETTINGS } from 'settings';
|
|
18
|
+
import { setupJoanieSession } from 'utils/test/wrappers/JoanieAppWrapper';
|
|
19
|
+
import { render } from 'utils/test/render';
|
|
20
|
+
import { BaseJoanieAppWrapper } from 'utils/test/wrappers/BaseJoanieAppWrapper';
|
|
22
21
|
|
|
23
22
|
jest.mock('utils/context', () => ({
|
|
24
23
|
__esModule: true,
|
|
@@ -35,31 +34,15 @@ jest.mock('hooks/useIntersectionObserver', () => ({
|
|
|
35
34
|
}));
|
|
36
35
|
|
|
37
36
|
describe('<DashboardItemOrder/> Contract', () => {
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<QueryClientProvider client={createTestQueryClient({ user: true })}>
|
|
41
|
-
<IntlProvider locale="en">
|
|
42
|
-
<SessionProvider>
|
|
43
|
-
<DashboardTest initialRoute={route} />
|
|
44
|
-
</SessionProvider>
|
|
45
|
-
</IntlProvider>
|
|
46
|
-
</QueryClientProvider>
|
|
47
|
-
);
|
|
48
|
-
};
|
|
37
|
+
setupJoanieSession();
|
|
49
38
|
|
|
50
39
|
beforeEach(() => {
|
|
51
40
|
jest.useFakeTimers();
|
|
52
41
|
jest.clearAllTimers();
|
|
53
|
-
|
|
54
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/addresses/', []);
|
|
55
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/credit-cards/', []);
|
|
56
|
-
fetchMock.get('https://joanie.endpoint/api/v1.0/orders/', []);
|
|
57
42
|
});
|
|
58
43
|
|
|
59
44
|
afterEach(() => {
|
|
60
45
|
jest.restoreAllMocks();
|
|
61
|
-
jest.clearAllMocks();
|
|
62
|
-
fetchMock.restore();
|
|
63
46
|
});
|
|
64
47
|
|
|
65
48
|
describe('writable', () => {
|
|
@@ -103,9 +86,10 @@ describe('<DashboardItemOrder/> Contract', () => {
|
|
|
103
86
|
// RTL too. See https://github.com/testing-library/user-event/issues/833.
|
|
104
87
|
const user = userEvent.setup({ delay: null });
|
|
105
88
|
|
|
106
|
-
render(
|
|
89
|
+
render(<DashboardTest initialRoute={LearnerDashboardPaths.COURSES} />, {
|
|
90
|
+
wrapper: BaseJoanieAppWrapper,
|
|
91
|
+
});
|
|
107
92
|
|
|
108
|
-
// console.log('apiCalls:2', fetchMock.calls().length);
|
|
109
93
|
await expectNoSpinner('Loading orders and enrollments...');
|
|
110
94
|
|
|
111
95
|
expect(
|