Update react monorepo to v19 (major) (#28914)

* Update react monorepo to v19

* Import JSX explicitly for React 19 compatibility

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

* Update usages of refs for React 19 compatibility

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

* Update react imports

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

* Avoid legacy contexts as much as possible

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

* Avoid deprecated React symbols

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

* Stash

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

* Update usages of refs for React 19 compatibility

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>

* Switch pillify to use a html-react-parser approach rather than DOM muddling

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

* Iterate

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

* Iterate react html parsing

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

* Iterate react html parsing

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

* Iterate html parsing

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

* Memoize the EventContentBody component

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

* Iterate html parsing

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>

* Simplify

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

* Iterate

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

* Discard changes to src/Linkify.tsx

* Discard changes to src/components/views/messages/TextualBody.tsx

* Discard changes to src/settings/handlers/AbstractLocalStorageSettingsHandler.ts

* 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>

* Prepare for React 19 upgrade

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

* Iterate

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

* Remove stale comment

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
renovate[bot]
2025-04-09 19:03:09 +00:00
committed by GitHub
parent f54fbf7231
commit e1b2e3a101
44 changed files with 300 additions and 290 deletions

View File

@@ -118,7 +118,7 @@ describe("<MatrixChat />", () => {
startup: jest.fn(),
},
login: jest.fn(),
loginFlows: jest.fn(),
loginFlows: jest.fn().mockResolvedValue({ flows: [] }),
isGuest: jest.fn().mockReturnValue(false),
clearStores: jest.fn(),
setGuest: jest.fn(),
@@ -165,12 +165,9 @@ describe("<MatrixChat />", () => {
isNameResolvable: true,
warning: "",
};
let initPromise: Promise<void> | undefined;
let defaultProps: ComponentProps<typeof MatrixChat>;
const getComponent = (props: Partial<ComponentProps<typeof MatrixChat>> = {}) => {
// MatrixChat does many questionable things which bomb tests in modern React mode,
// we'll want to refactor and break up MatrixChat before turning off legacyRoot mode
return render(<MatrixChat {...defaultProps} {...props} />, { legacyRoot: true });
return render(<MatrixChat {...defaultProps} {...props} />);
};
// make test results readable
@@ -220,6 +217,8 @@ describe("<MatrixChat />", () => {
};
beforeEach(async () => {
localStorage.clear();
jest.restoreAllMocks();
defaultProps = {
config: {
brand: "Test",
@@ -235,10 +234,8 @@ describe("<MatrixChat />", () => {
onNewScreen: jest.fn(),
onTokenLoginCompleted: jest.fn(),
realQueryParams: {},
initPromiseCallback: (p: Promise<void>) => (initPromise = p),
};
initPromise = undefined;
mockClient = getMockClientWithEventEmitter(getMockClientMethods());
jest.spyOn(MatrixJs, "createClient").mockReturnValue(mockClient);
@@ -257,18 +254,9 @@ describe("<MatrixChat />", () => {
});
afterEach(async () => {
// Wait for the promise that MatrixChat gives us to complete so that we know
// it's finished running its login code. We either need to do this or make the
// login code abort halfway through once the test finishes testing whatever it
// needs to test. If we do nothing, the login code will just continue running
// and interfere with the subsequent tests.
await initPromise;
// @ts-ignore
DMRoomMap.setShared(null);
jest.restoreAllMocks();
// 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)
act(() => defaultDispatcher.dispatch({ action: Action.OnLoggedOut }, true));
@@ -313,7 +301,6 @@ describe("<MatrixChat />", () => {
state: state,
};
const userId = "@alice:server.org";
const deviceId = "test-device-id";
const accessToken = "test-access-token-from-oidc";
@@ -335,8 +322,6 @@ describe("<MatrixChat />", () => {
const dialog = await screen.findByRole("dialog");
expect(within(dialog).getByText(errorMessage)).toBeInTheDocument();
// just check we're back on welcome page
await expect(screen.findByTestId("mx_welcome_screen")).resolves.toBeInTheDocument();
};
beforeEach(() => {
@@ -518,6 +503,9 @@ describe("<MatrixChat />", () => {
it("should set logged in and start MatrixClient", async () => {
getComponent({ realQueryParams });
defaultDispatcher.dispatch({
action: "will_start_client",
});
// client successfully started
await waitFor(() =>
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ action: "client_started" }),
@@ -597,9 +585,7 @@ describe("<MatrixChat />", () => {
// wait for logged in view to load
await screen.findByLabelText("User menu");
expect(screen.queryByRole("progressbar")).not.toBeInTheDocument();
const h1Element = screen.getByRole("heading", { level: 1 });
expect(h1Element).toHaveTextContent(`Welcome Ernie`);
await screen.findByRole("heading", { level: 1, name: "Welcome Ernie" });
});
describe("clean up drafts", () => {
@@ -612,9 +598,6 @@ describe("<MatrixChat />", () => {
localStorage.setItem(`mx_cider_state_${roomId}`, "fake_content");
mockClient.getRoom.mockImplementation((id) => [room].find((room) => room.roomId === id) || null);
});
afterEach(() => {
jest.restoreAllMocks();
});
it("should clean up drafts", async () => {
Date.now = jest.fn(() => timestamp);
localStorage.setItem(`mx_cider_state_${roomId}`, "fake_content");
@@ -1113,8 +1096,6 @@ describe("<MatrixChat />", () => {
"org.matrix.e2e_cross_signing",
);
await flushPromises();
// logged in
await screen.findByLabelText("User menu");
});
@@ -1210,7 +1191,6 @@ describe("<MatrixChat />", () => {
};
let loginClient!: ReturnType<typeof getMockClientWithEventEmitter>;
const userId = "@alice:server.org";
const deviceId = "test-device-id";
const accessToken = "test-access-token";
const clientLoginResponse = {
@@ -1304,6 +1284,7 @@ describe("<MatrixChat />", () => {
},
);
});
it("should clear storage", async () => {
const localStorageClearSpy = jest.spyOn(localStorage.__proto__, "clear");
@@ -1349,6 +1330,9 @@ describe("<MatrixChat />", () => {
it("should continue to post login setup when no session is found in local storage", async () => {
getComponent({ realQueryParams });
defaultDispatcher.dispatch({
action: "will_start_client",
});
// logged in but waiting for sync screen
await screen.findByText("Logout");
@@ -1604,8 +1588,13 @@ describe("<MatrixChat />", () => {
});
await flushPromises();
mockClient.emit(CryptoEvent.KeyBackupFailed, "error code");
await waitFor(() => expect(spy).toHaveBeenCalledTimes(1));
expect((spy.mock.lastCall![0] as any)._payload._result).toEqual(expect.objectContaining({ __test: true }));
await waitFor(() =>
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
_payload: expect.objectContaining({ _result: expect.objectContaining({ __test: true }) }),
}),
),
);
});
it("should show the recovery method removed dialog", async () => {
@@ -1622,8 +1611,13 @@ describe("<MatrixChat />", () => {
});
await flushPromises();
mockClient.emit(CryptoEvent.KeyBackupFailed, "error code");
await waitFor(() => expect(spy).toHaveBeenCalledTimes(1));
expect((spy.mock.lastCall![0] as any)._payload._result).toEqual(expect.objectContaining({ __test: true }));
await waitFor(() =>
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
_payload: expect.objectContaining({ _result: expect.objectContaining({ __test: true }) }),
}),
),
);
});
});
});