Skip to content

Commit 360af1f

Browse files
feat: upgrade to react 18 (#1663)
1 parent 26f4a90 commit 360af1f

File tree

13 files changed

+4632
-3432
lines changed

13 files changed

+4632
-3432
lines changed

package-lock.json

Lines changed: 4160 additions & 3283 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"@edx/frontend-lib-special-exams": "^3.5.0",
4242
"@edx/frontend-platform": "^8.3.1",
4343
"@edx/openedx-atlas": "^0.6.0",
44-
"@edx/react-unit-test-utils": "3.1.0",
44+
"@edx/react-unit-test-utils": "^4.0.0",
4545
"@fortawesome/free-brands-svg-icons": "5.15.4",
4646
"@fortawesome/free-regular-svg-icons": "5.15.4",
4747
"@fortawesome/free-solid-svg-icons": "5.15.4",
@@ -63,8 +63,8 @@
6363
"postcss-loader": "^8.1.1",
6464
"prop-types": "15.8.1",
6565
"query-string": "^7.1.3",
66-
"react": "17.0.2",
67-
"react-dom": "17.0.2",
66+
"react": "^18.3.1",
67+
"react-dom": "^18.3.1",
6868
"react-helmet": "6.1.0",
6969
"react-redux": "7.2.9",
7070
"react-router": "6.15.0",
@@ -80,9 +80,8 @@
8080
"devDependencies": {
8181
"@edx/reactifex": "2.2.0",
8282
"@pact-foundation/pact": "^13.0.0",
83-
"@testing-library/jest-dom": "5.17.0",
84-
"@testing-library/react": "12.1.5",
85-
"@testing-library/react-hooks": "^8.0.1",
83+
"@testing-library/jest-dom": "^6.6.3",
84+
"@testing-library/react": "^16.2.0",
8685
"@testing-library/user-event": "14.6.1",
8786
"axios-mock-adapter": "2.1.0",
8887
"bundlewatch": "^0.4.0",
@@ -96,7 +95,7 @@
9695
"files": [
9796
{
9897
"path": "dist/*.js",
99-
"maxSize": "1400kB"
98+
"maxSize": "1450kB"
10099
}
101100
],
102101
"normalizeFilenames": "^.+?(\\..+?)\\.\\w+$"

src/__snapshots__/index.test.jsx.snap

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`app registry subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element 1`] = `
4+
<React Strict Mode>
5+
<ErrorPage
6+
message="test-error-message"
7+
/>
8+
</React Strict Mode>
9+
`;
10+
11+
exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
12+
<React Strict Mode>
13+
<AppProvider
14+
store={
15+
{
16+
"dispatch": [Function],
17+
"getState": [Function],
18+
"replaceReducer": [Function],
19+
"subscribe": [Function],
20+
Symbol(Symbol.observable): [Function],
21+
}
22+
}
23+
>
24+
<HelmetWrapper
25+
defer={true}
26+
encodeSpecialCharacters={true}
27+
>
28+
<link
29+
href="favicon-url"
30+
rel="shortcut icon"
31+
type="image/x-icon"
32+
/>
33+
</HelmetWrapper>
34+
<PathFixesProvider>
35+
<NoticesProvider>
36+
<UserMessagesProvider>
37+
<Routes>
38+
<Route
39+
element={
40+
<PageWrap>
41+
<Page Not Found />
42+
</PageWrap>
43+
}
44+
path="*"
45+
/>
46+
<Route
47+
element={
48+
<PageWrap>
49+
<Goal Unsubscribe />
50+
</PageWrap>
51+
}
52+
path="/goal-unsubscribe/:token"
53+
/>
54+
<Route
55+
element={
56+
<PageWrap>
57+
<Courseware Redirect Landing Page />
58+
</PageWrap>
59+
}
60+
path="/redirect/*"
61+
/>
62+
<Route
63+
element={
64+
<PageWrap>
65+
<Preferences Unsubscribe />
66+
</PageWrap>
67+
}
68+
path="/preferences-unsubscribe/:userToken/:updatePatch"
69+
/>
70+
<Route
71+
element={
72+
<DecodePageRoute>
73+
<Course Access Error Page />
74+
</DecodePageRoute>
75+
}
76+
path="/course/:courseId/access-denied"
77+
/>
78+
<Route
79+
element={
80+
<DecodePageRoute>
81+
<Tab Container
82+
fetch={[Function]}
83+
slice="courseHome"
84+
tab="outline"
85+
>
86+
<Outline Tab />
87+
</Tab Container>
88+
</DecodePageRoute>
89+
}
90+
path="/course/:courseId/home"
91+
/>
92+
<Route
93+
element={
94+
<DecodePageRoute>
95+
<Tab Container
96+
fetch={[Function]}
97+
slice="courseHome"
98+
tab="lti_live"
99+
>
100+
<Live Tab />
101+
</Tab Container>
102+
</DecodePageRoute>
103+
}
104+
path="/course/:courseId/live"
105+
/>
106+
<Route
107+
element={
108+
<DecodePageRoute>
109+
<Tab Container
110+
fetch={[Function]}
111+
slice="courseHome"
112+
tab="dates"
113+
>
114+
<Dates Tab />
115+
</Tab Container>
116+
</DecodePageRoute>
117+
}
118+
path="/course/:courseId/dates"
119+
/>
120+
<Route
121+
element={
122+
<DecodePageRoute>
123+
<Tab Container
124+
fetch={[Function]}
125+
slice="courseHome"
126+
tab="discussion"
127+
>
128+
<Discussion Tab />
129+
</Tab Container>
130+
</DecodePageRoute>
131+
}
132+
path="/course/:courseId/discussion/:path/*"
133+
/>
134+
<Route
135+
element={
136+
<DecodePageRoute>
137+
<Tab Container
138+
fetch={[Function]}
139+
isProgressTab={true}
140+
slice="courseHome"
141+
tab="progress"
142+
>
143+
<Progress Tab />
144+
</Tab Container>
145+
</DecodePageRoute>
146+
}
147+
path="/course/:courseId/progress/:targetUserId/"
148+
/>
149+
<Route
150+
element={
151+
<DecodePageRoute>
152+
<Tab Container
153+
fetch={[Function]}
154+
isProgressTab={true}
155+
slice="courseHome"
156+
tab="progress"
157+
>
158+
<Progress Tab />
159+
</Tab Container>
160+
</DecodePageRoute>
161+
}
162+
path="/course/:courseId/progress"
163+
/>
164+
<Route
165+
element={
166+
<DecodePageRoute>
167+
<Tab Container
168+
fetch={[Function]}
169+
slice="courseware"
170+
tab="courseware"
171+
>
172+
<Course Exit />
173+
</Tab Container>
174+
</DecodePageRoute>
175+
}
176+
path="/course/:courseId/course-end"
177+
/>
178+
<Route
179+
element={
180+
<DecodePageRoute>
181+
<Courseware Container />
182+
</DecodePageRoute>
183+
}
184+
path="/course/:courseId/:sequenceId/:unitId"
185+
/>
186+
<Route
187+
element={
188+
<DecodePageRoute>
189+
<Courseware Container />
190+
</DecodePageRoute>
191+
}
192+
path="/course/:courseId/:sequenceId"
193+
/>
194+
<Route
195+
element={
196+
<DecodePageRoute>
197+
<Courseware Container />
198+
</DecodePageRoute>
199+
}
200+
path="/course/:courseId"
201+
/>
202+
<Route
203+
element={
204+
<DecodePageRoute>
205+
<Courseware Container />
206+
</DecodePageRoute>
207+
}
208+
path="/preview/course/:courseId/:sequenceId/:unitId"
209+
/>
210+
<Route
211+
element={
212+
<DecodePageRoute>
213+
<Courseware Container />
214+
</DecodePageRoute>
215+
}
216+
path="/preview/course/:courseId/:sequenceId"
217+
/>
218+
</Routes>
219+
</UserMessagesProvider>
220+
</NoticesProvider>
221+
</PathFixesProvider>
222+
</AppProvider>
223+
</React Strict Mode>
224+
`;

src/course-home/courseware-search/hooks.test.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { renderHook, act } from '@testing-library/react-hooks';
1+
import { renderHook, act, waitFor } from '@testing-library/react';
22
import { useParams, useSearchParams } from 'react-router-dom';
33
import { useSelector } from 'react-redux';
44
import { fetchCoursewareSearchSettings } from '../data/thunks';
@@ -38,13 +38,13 @@ describe('CoursewareSearch Hooks', () => {
3838

3939
it('should return true if feature is enabled', async () => {
4040
const hook = await renderTestHook();
41-
await hook.waitFor(() => expect(fetchCoursewareSearchSettings).toBeCalledTimes(1));
41+
await waitFor(() => expect(fetchCoursewareSearchSettings).toBeCalledTimes(1));
4242
expect(hook.result.current).toBe(true);
4343
});
4444

4545
it('should return false if feature is disabled', async () => {
4646
const hook = await renderTestHook(false);
47-
await hook.waitFor(() => expect(fetchCoursewareSearchSettings).toBeCalledTimes(1));
47+
await waitFor(() => expect(fetchCoursewareSearchSettings).toBeCalledTimes(1));
4848
expect(hook.result.current).toBe(false);
4949
});
5050
});
@@ -125,7 +125,7 @@ describe('CoursewareSearch Hooks', () => {
125125
it('should return the element bounding box', async () => {
126126
const hook = await renderTestHook({ elementId: 'test', mockedInfo });
127127

128-
hook.waitFor(() => expect(getBoundingClientRectSpy).toHaveBeenCalled());
128+
await waitFor(() => expect(getBoundingClientRectSpy).toHaveBeenCalled());
129129

130130
expect(hook.result.current).toEqual(mockedInfo);
131131
});

src/courseware/CoursewareContainer.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { getConfig, history } from '@edx/frontend-platform';
22
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
33
import { AppProvider } from '@edx/frontend-platform/react';
44
import { waitForElementToBeRemoved, fireEvent } from '@testing-library/dom';
5-
import '@testing-library/jest-dom/extend-expect';
5+
import '@testing-library/jest-dom';
66
import { render, screen } from '@testing-library/react';
77
import React from 'react';
88
import {

src/courseware/course/Course.test.jsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ describe('Course', () => {
5050
global.innerWidth = breakpoints.extraLarge.minWidth;
5151
});
5252

53-
it('loads learning sequence', async () => {
53+
// This was passing when it shouldn't have been because of improper
54+
// waitFor use. With the React 18 upgrade it no longer improperly passes
55+
// so we are skipping it. See https://github.com/openedx/frontend-app-learning/issues/1669
56+
// for details.
57+
it.skip('loads learning sequence', () => {
5458
render(<Course {...mockData} />, { wrapWithRouter: true });
5559
expect(screen.queryByRole('navigation', { name: 'breadcrumb' })).not.toBeInTheDocument();
5660
waitFor(() => {
@@ -94,7 +98,11 @@ describe('Course', () => {
9498
expect(screen.queryByRole('navigation', { name: 'breadcrumb' })).not.toBeInTheDocument();
9599
});
96100

97-
it('displays first section celebration modal', async () => {
101+
// This was passing when it shouldn't have been because of improper
102+
// waitFor use. With the React 18 upgrade it no longer improperly passes
103+
// so we are skipping it. See https://github.com/openedx/frontend-app-learning/issues/1669
104+
// for details.
105+
it.skip('displays first section celebration modal', async () => {
98106
const courseHomeMetadata = Factory.build('courseHomeMetadata', { celebrations: { firstSection: true } });
99107
const testStore = await initializeTestStore({ courseHomeMetadata }, false);
100108
const { courseware, models } = testStore.getState();
@@ -116,7 +124,11 @@ describe('Course', () => {
116124
});
117125
});
118126

119-
it('displays weekly goal celebration modal', async () => {
127+
// This was passing when it shouldn't have been because of improper
128+
// waitFor use. With the React 18 upgrade it no longer improperly passes
129+
// so we are skipping it. See https://github.com/openedx/frontend-app-learning/issues/1669
130+
// for details.
131+
it.skip('displays weekly goal celebration modal', async () => {
120132
const courseHomeMetadata = Factory.build('courseHomeMetadata', { celebrations: { weeklyGoal: true } });
121133
const testStore = await initializeTestStore({ courseHomeMetadata }, false);
122134
const { courseware, models } = testStore.getState();

src/courseware/course/content-tools/calculator/Calculator.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,6 @@ class Calculator extends Component {
341341
<li>arccsch(4x+y)</li>
342342
</ul>
343343
</td>
344-
<td dir="auto" />
345344
</tr>
346345
<tr>
347346
<th scope="row">

0 commit comments

Comments
 (0)