Skip to content

Commit

Permalink
Migrate to React 18 createRoot API (#28256)
Browse files Browse the repository at this point in the history
* Migrate to React 18 createRoot API

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Discard changes to src/components/views/settings/devices/DeviceDetails.tsx

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Attempt to stabilise test

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* legacyRoot?

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix tests

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Improve coverage

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Improve coverage

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
  • Loading branch information
t3chguy authored Nov 20, 2024
1 parent 48fd330 commit ca33d91
Show file tree
Hide file tree
Showing 44 changed files with 703 additions and 715 deletions.
7 changes: 7 additions & 0 deletions src/components/structures/auth/ForgotPassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ interface State {
}

export default class ForgotPassword extends React.Component<Props, State> {
private unmounted = false;
private reset: PasswordReset;
private fieldPassword: Field | null = null;
private fieldPasswordConfirm: Field | null = null;
Expand Down Expand Up @@ -108,14 +109,20 @@ export default class ForgotPassword extends React.Component<Props, State> {
}
}

public componentWillUnmount(): void {
this.unmounted = true;
}

private async checkServerLiveliness(serverConfig: ValidatedServerConfig): Promise<void> {
try {
await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(serverConfig.hsUrl, serverConfig.isUrl);
if (this.unmounted) return;

this.setState({
serverIsAlive: true,
});
} catch (e: any) {
if (this.unmounted) return;
const { serverIsAlive, serverDeadError } = AutoDiscoveryUtils.authComponentStateForError(
e,
"forgot_password",
Expand Down
14 changes: 8 additions & 6 deletions src/vector/init.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import * as ReactDOM from "react-dom";
import { createRoot } from "react-dom/client";
import React, { StrictMode } from "react";
import { logger } from "matrix-js-sdk/src/logger";

Expand Down Expand Up @@ -93,19 +93,21 @@ export async function loadApp(fragParams: {}): Promise<void> {
function setWindowMatrixChat(matrixChat: MatrixChat): void {
window.matrixChat = matrixChat;
}
ReactDOM.render(await module.loadApp(fragParams, setWindowMatrixChat), document.getElementById("matrixchat"));
const app = await module.loadApp(fragParams, setWindowMatrixChat);
const root = createRoot(document.getElementById("matrixchat")!);
root.render(app);
}

export async function showError(title: string, messages?: string[]): Promise<void> {
const { ErrorView } = await import(
/* webpackChunkName: "error-view" */
"../async-components/structures/ErrorView"
);
ReactDOM.render(
const root = createRoot(document.getElementById("matrixchat")!);
root.render(
<StrictMode>
<ErrorView title={title} messages={messages} />
</StrictMode>,
document.getElementById("matrixchat"),
);
}

Expand All @@ -114,11 +116,11 @@ export async function showIncompatibleBrowser(onAccept: () => void): Promise<voi
/* webpackChunkName: "error-view" */
"../async-components/structures/ErrorView"
);
ReactDOM.render(
const root = createRoot(document.getElementById("matrixchat")!);
root.render(
<StrictMode>
<UnsupportedBrowserView onAccept={onAccept} />
</StrictMode>,
document.getElementById("matrixchat"),
);
}

Expand Down
1 change: 0 additions & 1 deletion test/test-utils/jest-matrix-react.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ const wrapWithTooltipProvider = (Wrapper: RenderOptions["wrapper"]) => {

const customRender = (ui: ReactElement, options: RenderOptions = {}) => {
return render(ui, {
legacyRoot: true,
...options,
wrapper: wrapWithTooltipProvider(options?.wrapper) as RenderOptions["wrapper"],
}) as ReturnType<typeof render>;
Expand Down
2 changes: 1 addition & 1 deletion test/test-utils/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export const clearAllModals = async (): Promise<void> => {
// Prevent modals from leaking and polluting other tests
let keepClosingModals = true;
while (keepClosingModals) {
keepClosingModals = Modal.closeCurrentModal();
keepClosingModals = await act(() => Modal.closeCurrentModal());

// Then wait for the screen to update (probably React rerender and async/await).
// Important for tests using Jest fake timers to not get into an infinite loop
Expand Down
14 changes: 7 additions & 7 deletions test/unit-tests/accessibility/RovingTabIndex-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/

import React, { HTMLAttributes } from "react";
import { render } from "jest-matrix-react";
import { act, render } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";

import {
Expand Down Expand Up @@ -79,15 +79,15 @@ describe("RovingTabIndex", () => {
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);

// focus on 2nd button and test it is the only active one
container.querySelectorAll("button")[2].focus();
act(() => container.querySelectorAll("button")[2].focus());
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);

// focus on 1st button and test it is the only active one
container.querySelectorAll("button")[1].focus();
act(() => container.querySelectorAll("button")[1].focus());
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);

// check that the active button does not change even on an explicit blur event
container.querySelectorAll("button")[1].blur();
act(() => container.querySelectorAll("button")[1].blur());
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);

// update the children, it should remain on the same button
Expand Down Expand Up @@ -162,7 +162,7 @@ describe("RovingTabIndex", () => {
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);

// focus on 2nd button and test it is the only active one
container.querySelectorAll("button")[2].focus();
act(() => container.querySelectorAll("button")[2].focus());
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
});

Expand Down Expand Up @@ -390,7 +390,7 @@ describe("RovingTabIndex", () => {
</RovingTabIndexProvider>,
);

container.querySelectorAll("button")[0].focus();
act(() => container.querySelectorAll("button")[0].focus());
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);

await userEvent.keyboard("[ArrowDown]");
Expand Down Expand Up @@ -423,7 +423,7 @@ describe("RovingTabIndex", () => {
</RovingTabIndexProvider>,
);

container.querySelectorAll("button")[0].focus();
act(() => container.querySelectorAll("button")[0].focus());
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);

const button = container.querySelectorAll("button")[1];
Expand Down
28 changes: 17 additions & 11 deletions test/unit-tests/components/structures/MatrixChat-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Please see LICENSE files in the repository root for full details.
import "core-js/stable/structured-clone";
import "fake-indexeddb/auto";
import React, { ComponentProps } from "react";
import { fireEvent, render, RenderResult, screen, waitFor, within } from "jest-matrix-react";
import { fireEvent, render, RenderResult, screen, waitFor, within, act } from "jest-matrix-react";
import fetchMock from "fetch-mock-jest";
import { Mocked, mocked } from "jest-mock";
import { ClientEvent, MatrixClient, MatrixEvent, Room, SyncState } from "matrix-js-sdk/src/matrix";
Expand Down Expand Up @@ -163,7 +163,7 @@ describe("<MatrixChat />", () => {
let initPromise: Promise<void> | undefined;
let defaultProps: ComponentProps<typeof MatrixChat>;
const getComponent = (props: Partial<ComponentProps<typeof MatrixChat>> = {}) =>
render(<MatrixChat {...defaultProps} {...props} />);
render(<MatrixChat {...defaultProps} {...props} />, { legacyRoot: true });

// make test results readable
filterConsole(
Expand Down Expand Up @@ -201,7 +201,7 @@ describe("<MatrixChat />", () => {
// we are logged in, but are still waiting for the /sync to complete
await screen.findByText("Syncing…");
// initial sync
client.emit(ClientEvent.Sync, SyncState.Prepared, null);
await act(() => client.emit(ClientEvent.Sync, SyncState.Prepared, null));
}

// let things settle
Expand Down Expand Up @@ -263,7 +263,7 @@ describe("<MatrixChat />", () => {

// emit a loggedOut event so that all of the Store singletons forget about their references to the mock client
// (must be sync otherwise the next test will start before it happens)
defaultDispatcher.dispatch({ action: Action.OnLoggedOut }, true);
act(() => defaultDispatcher.dispatch({ action: Action.OnLoggedOut }, true));

localStorage.clear();
});
Expand Down Expand Up @@ -328,7 +328,7 @@ describe("<MatrixChat />", () => {

expect(within(dialog).getByText(errorMessage)).toBeInTheDocument();
// just check we're back on welcome page
await expect(await screen.findByTestId("mx_welcome_screen")).toBeInTheDocument();
await expect(screen.findByTestId("mx_welcome_screen")).resolves.toBeInTheDocument();
};

beforeEach(() => {
Expand Down Expand Up @@ -956,9 +956,11 @@ describe("<MatrixChat />", () => {
await screen.findByText("Powered by Matrix");

// go to login page
defaultDispatcher.dispatch({
action: "start_login",
});
act(() =>
defaultDispatcher.dispatch({
action: "start_login",
}),
);

await flushPromises();

Expand Down Expand Up @@ -1126,9 +1128,11 @@ describe("<MatrixChat />", () => {

await getComponentAndLogin();

bootstrapDeferred.resolve();
act(() => bootstrapDeferred.resolve());

await expect(await screen.findByRole("heading", { name: "You're in", level: 1 })).toBeInTheDocument();
await expect(
screen.findByRole("heading", { name: "You're in", level: 1 }),
).resolves.toBeInTheDocument();
});
});
});
Expand Down Expand Up @@ -1397,7 +1401,9 @@ describe("<MatrixChat />", () => {

function simulateSessionLockClaim() {
localStorage.setItem("react_sdk_session_lock_claimant", "testtest");
window.dispatchEvent(new StorageEvent("storage", { key: "react_sdk_session_lock_claimant" }));
act(() =>
window.dispatchEvent(new StorageEvent("storage", { key: "react_sdk_session_lock_claimant" })),
);
}

it("after a session is restored", async () => {
Expand Down
22 changes: 11 additions & 11 deletions test/unit-tests/components/structures/PipContainer-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ describe("PipContainer", () => {
let voiceBroadcastPlaybacksStore: VoiceBroadcastPlaybacksStore;

const actFlushPromises = async () => {
await act(async () => {
await flushPromises();
});
await flushPromises();
};

beforeEach(async () => {
Expand Down Expand Up @@ -165,22 +163,24 @@ describe("PipContainer", () => {
if (!(call instanceof MockedCall)) throw new Error("Failed to create call");

const widget = new Widget(call.widget);
WidgetStore.instance.addVirtualWidget(call.widget, room.roomId);
WidgetMessagingStore.instance.storeMessaging(widget, room.roomId, {
stop: () => {},
} as unknown as ClientWidgetApi);

await act(async () => {
WidgetStore.instance.addVirtualWidget(call.widget, room.roomId);
WidgetMessagingStore.instance.storeMessaging(widget, room.roomId, {
stop: () => {},
} as unknown as ClientWidgetApi);

await call.start();
ActiveWidgetStore.instance.setWidgetPersistence(widget.id, room.roomId, true);
});

await fn(call);

cleanup();
call.destroy();
ActiveWidgetStore.instance.destroyPersistentWidget(widget.id, room.roomId);
WidgetStore.instance.removeVirtualWidget(widget.id, room.roomId);
act(() => {
call.destroy();
ActiveWidgetStore.instance.destroyPersistentWidget(widget.id, room.roomId);
WidgetStore.instance.removeVirtualWidget(widget.id, room.roomId);
});
};

const withWidget = async (fn: () => Promise<void>): Promise<void> => {
Expand Down
Loading

0 comments on commit ca33d91

Please sign in to comment.