From 5f4ddc8fd7d84500457bb08b0981a84a2d1594b1 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sat, 18 Jun 2022 23:59:14 +0400 Subject: Bump React To 18.2.0 Bump react to v18, and handle all the breaking changes. This includes bumping a lot of other dependencies to versions which support react 18, and handling the breaking changes for those. Refer to the following documents for migration guides: React: https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html Router: https://reactrouter.com/docs/en/v6/upgrading/v5 Signed-off-by: Hassan Abouelela --- src/App.tsx | 50 +++++++++++++++++------------------ src/components/Question.tsx | 16 ++++++++--- src/index.tsx | 15 ++++++----- src/tests/pages/CallbackPage.test.tsx | 14 +++++----- src/tests/pages/FormPage.test.tsx | 14 +++------- src/tests/pages/LandingPage.test.tsx | 21 +++++++-------- 6 files changed, 66 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/App.tsx b/src/App.tsx index 523e583..752a6c6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,11 +3,7 @@ import React, { Suspense } from "react"; import { jsx, css, Global } from "@emotion/react"; -import { - BrowserRouter as Router, - Route, - Switch -} from "react-router-dom"; +import { BrowserRouter, Route, Routes } from "react-router-dom"; import { PropagateLoader } from "react-spinners"; @@ -35,31 +31,33 @@ function PageLoading() { ; } +function Routing(): JSX.Element { + const renderedRoutes = routes.map(({path, Component}) => ( + }> + }/> + )); + + return ( + + {renderedRoutes} + + ); +} + function App(): JSX.Element { return (
- - ( - - - - {routes.map(({path, Component}) => ( - - }> - - - - ))} - - - - )}/> - + + + + + }/> + + + +
); } diff --git a/src/components/Question.tsx b/src/components/Question.tsx index ebacb4a..61e66e0 100644 --- a/src/components/Question.tsx +++ b/src/components/Question.tsx @@ -35,14 +35,22 @@ class RenderedQuestion extends React.Component { } this.blurHandler = this.blurHandler.bind(this); - this.setPublicState("valid", true); - this.setPublicState("error", ""); + const _state: {[key: string]: string | boolean | null} = { + "valid": true, + "error": "", + }; + if (props.question.type === QuestionType.Code) { - this.setPublicState("unittestsFailed", false); + _state["unittestsFailed"] = false; } if (!skip_normal_state.includes(props.question.type)) { - this.setPublicState("value", ""); + _state["value"] = ""; + } + + this.state = _state; + for (const [key, value] of Object.entries(_state)) { + this.props.public_state.set(key, value); } } diff --git a/src/index.tsx b/src/index.tsx index 4bce5a4..2565964 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,7 @@ +/** @jsx jsx */ +import { jsx } from "@emotion/react"; import React from "react"; -import ReactDOM from "react-dom"; +import { createRoot } from "react-dom/client"; import App from "./App"; import * as serviceWorker from "./serviceWorker"; @@ -33,8 +35,10 @@ console.log(` SHA: %c ${process.env.COMMIT_REF} `, `padding: 2px; border-radiu console.log("%cCome join us on Discord! https://discord.gg/python", `font-size: 1.5em; font-family: "Hind", "Arial"; color: ${colors.blurple}`); -/* eslint-disable react/react-in-jsx-scope */ -ReactDOM.render( +const rootDocument = document.getElementById("root"); +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion +const root = createRoot(rootDocument!); +root.render( An error has occurred with Python Discord Forms. Please let us know in the Discord server at discord.gg/python

} @@ -47,10 +51,9 @@ ReactDOM.render( console.log(err); }} > - +
-
, - document.getElementById("root") + ); /* eslint-enable react/react-in-jsx-scope */ diff --git a/src/tests/pages/CallbackPage.test.tsx b/src/tests/pages/CallbackPage.test.tsx index 70f2fed..37fb932 100644 --- a/src/tests/pages/CallbackPage.test.tsx +++ b/src/tests/pages/CallbackPage.test.tsx @@ -1,9 +1,9 @@ import React from "react"; -import { render } from "@testing-library/react"; +import { render, waitFor } from "@testing-library/react"; import CallbackPage from "../../pages/CallbackPage"; -test("callback page sends provided code", () => { +test("callback page sends provided code", async () => { global.opener = { postMessage: jest.fn() }; @@ -14,9 +14,11 @@ test("callback page sends provided code", () => { render(); - expect(global.opener.postMessage).toBeCalledTimes(1); - expect(global.opener.postMessage).toBeCalledWith({ - code: "abcde_code", - state: "abcde_state" + await waitFor(() => { + expect(global.opener.postMessage).toBeCalledTimes(1); + expect(global.opener.postMessage).toBeCalledWith({ + code: "abcde_code", + state: "abcde_state" + }); }); }); diff --git a/src/tests/pages/FormPage.test.tsx b/src/tests/pages/FormPage.test.tsx index 947c075..3a906f3 100644 --- a/src/tests/pages/FormPage.test.tsx +++ b/src/tests/pages/FormPage.test.tsx @@ -1,18 +1,13 @@ import React from "react"; import { render } from "@testing-library/react"; -import { createMemoryHistory } from "history"; - -import { Route, BrowserRouter as Router } from "react-router-dom"; +import { MemoryRouter } from "react-router-dom"; import FormPage from "../../pages/FormPage"; import * as forms from "../../api/forms"; test("renders specific form page with loading bar", () => { - const history = createMemoryHistory(); - history.push("/form/route"); - - const { getByText } = render(); + const { getByText } = render(, {wrapper: MemoryRouter}); // If we rendered the headerbar we rendered the forms page. const headerBar = getByText(/Loading.../); expect(headerBar).toBeInTheDocument(); @@ -20,14 +15,11 @@ test("renders specific form page with loading bar", () => { /* TODO: Find why this test spits out promise errors that fail CI */ test.skip("calls api method to load form", () => { - const history = createMemoryHistory(); - history.push("/form/ban-appeals"); - const oldImpl = forms.getForm; Object.defineProperty(forms, "getForm", {value: jest.fn(oldImpl)}); - render(); + render(, {wrapper: MemoryRouter}); expect(forms.getForm).toBeCalled(); }); diff --git a/src/tests/pages/LandingPage.test.tsx b/src/tests/pages/LandingPage.test.tsx index 6f8a530..727b922 100644 --- a/src/tests/pages/LandingPage.test.tsx +++ b/src/tests/pages/LandingPage.test.tsx @@ -1,10 +1,10 @@ import React from "react"; -import { render } from "@testing-library/react"; +import { render, waitFor } from "@testing-library/react"; import LandingPage from "../../pages/LandingPage"; import * as forms from "../../api/forms"; -import { BrowserRouter as Router } from "react-router-dom"; +import { MemoryRouter } from "react-router-dom"; import { QuestionType } from "../../api/question"; const testingForm: forms.Form = { @@ -25,13 +25,12 @@ const testingForm: forms.Form = { submitted_text: null }; -test("renders landing page", () => { - const setForms = jest.fn(() => [testingForm]); - Object.defineProperty(forms, "getForms", setForms); - const handleForms = jest.spyOn(React, "useState"); - handleForms.mockImplementation(() => [[testingForm], setForms]); - const { getByText } = render(); - // If we rendered the headerbar we rendered the landing page. - const headerBar = getByText(/Python Discord Forms/); - expect(headerBar).toBeInTheDocument(); +test("renders landing page", async () => { + jest.spyOn(forms, "getForms").mockImplementation(() => Promise.resolve([testingForm])); + + const { getByText } = render(, {wrapper: MemoryRouter}); + await waitFor(() => { + const headerBar = getByText(/Python Discord Forms/); + expect(headerBar).toBeInTheDocument(); + }); }); -- cgit v1.2.3