Migrate to React 18 createRoot API (#28256)

* 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>
This commit is contained in:
Michael Telatynski 2024-11-20 13:29:23 +00:00 committed by GitHub
parent 48fd330dd9
commit ca33d9165a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 719 additions and 731 deletions

View file

@ -6,7 +6,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 { render, screen, waitFor } from "jest-matrix-react";
import { render, screen, waitFor, cleanup } from "jest-matrix-react";
import { MatrixClient, MatrixError, ThreepidMedium } from "matrix-js-sdk/src/matrix";
import React from "react";
import userEvent from "@testing-library/user-event";
@ -48,54 +48,13 @@ describe("AddRemoveThreepids", () => {
afterEach(() => {
jest.restoreAllMocks();
clearAllModals();
cleanup();
});
const clientProviderWrapper: React.FC = ({ children }: React.PropsWithChildren) => (
<MatrixClientContext.Provider value={client}>{children}</MatrixClientContext.Provider>
);
it("should render a loader while loading", async () => {
render(
<AddRemoveThreepids
mode="hs"
medium={ThreepidMedium.Email}
threepids={[]}
isLoading={true}
onChange={() => {}}
/>,
);
expect(screen.getByLabelText("Loading…")).toBeInTheDocument();
});
it("should render email addresses", async () => {
const { container } = render(
<AddRemoveThreepids
mode="hs"
medium={ThreepidMedium.Email}
threepids={[EMAIL1]}
isLoading={false}
onChange={() => {}}
/>,
);
expect(container).toMatchSnapshot();
});
it("should render phone numbers", async () => {
const { container } = render(
<AddRemoveThreepids
mode="hs"
medium={ThreepidMedium.Phone}
threepids={[PHONE1]}
isLoading={false}
onChange={() => {}}
/>,
);
expect(container).toMatchSnapshot();
});
it("should handle no email addresses", async () => {
const { container } = render(
<AddRemoveThreepids
@ -107,6 +66,7 @@ describe("AddRemoveThreepids", () => {
/>,
);
await expect(screen.findByText("Email Address")).resolves.toBeVisible();
expect(container).toMatchSnapshot();
});
@ -127,7 +87,7 @@ describe("AddRemoveThreepids", () => {
},
);
const input = screen.getByRole("textbox", { name: "Email Address" });
const input = await screen.findByRole("textbox", { name: "Email Address" });
await userEvent.type(input, EMAIL1.address);
const addButton = screen.getByRole("button", { name: "Add" });
await userEvent.click(addButton);
@ -166,7 +126,7 @@ describe("AddRemoveThreepids", () => {
},
);
const input = screen.getByRole("textbox", { name: "Email Address" });
const input = await screen.findByRole("textbox", { name: "Email Address" });
await userEvent.type(input, EMAIL1.address);
const addButton = screen.getByRole("button", { name: "Add" });
await userEvent.click(addButton);
@ -210,7 +170,7 @@ describe("AddRemoveThreepids", () => {
},
);
const countryDropdown = screen.getByRole("button", { name: /Country Dropdown/ });
const countryDropdown = await screen.findByRole("button", { name: /Country Dropdown/ });
await userEvent.click(countryDropdown);
const gbOption = screen.getByRole("option", { name: "🇬🇧 United Kingdom (+44)" });
await userEvent.click(gbOption);
@ -270,7 +230,7 @@ describe("AddRemoveThreepids", () => {
},
);
const removeButton = screen.getByRole("button", { name: /Remove/ });
const removeButton = await screen.findByRole("button", { name: /Remove/ });
await userEvent.click(removeButton);
expect(screen.getByText(`Remove ${EMAIL1.address}?`)).toBeVisible();
@ -297,7 +257,7 @@ describe("AddRemoveThreepids", () => {
},
);
const removeButton = screen.getByRole("button", { name: /Remove/ });
const removeButton = await screen.findByRole("button", { name: /Remove/ });
await userEvent.click(removeButton);
expect(screen.getByText(`Remove ${EMAIL1.address}?`)).toBeVisible();
@ -326,7 +286,7 @@ describe("AddRemoveThreepids", () => {
},
);
const removeButton = screen.getByRole("button", { name: /Remove/ });
const removeButton = await screen.findByRole("button", { name: /Remove/ });
await userEvent.click(removeButton);
expect(screen.getByText(`Remove ${PHONE1.address}?`)).toBeVisible();
@ -357,7 +317,7 @@ describe("AddRemoveThreepids", () => {
},
);
expect(screen.getByText(EMAIL1.address)).toBeVisible();
await expect(screen.findByText(EMAIL1.address)).resolves.toBeVisible();
const shareButton = screen.getByRole("button", { name: /Share/ });
await userEvent.click(shareButton);
@ -408,7 +368,7 @@ describe("AddRemoveThreepids", () => {
},
);
expect(screen.getByText(PHONE1.address)).toBeVisible();
await expect(screen.findByText(PHONE1.address)).resolves.toBeVisible();
const shareButton = screen.getByRole("button", { name: /Share/ });
await userEvent.click(shareButton);
@ -452,7 +412,7 @@ describe("AddRemoveThreepids", () => {
},
);
expect(screen.getByText(EMAIL1.address)).toBeVisible();
await expect(screen.findByText(EMAIL1.address)).resolves.toBeVisible();
const revokeButton = screen.getByRole("button", { name: /Revoke/ });
await userEvent.click(revokeButton);
@ -475,7 +435,7 @@ describe("AddRemoveThreepids", () => {
},
);
expect(screen.getByText(PHONE1.address)).toBeVisible();
await expect(screen.findByText(PHONE1.address)).resolves.toBeVisible();
const revokeButton = screen.getByRole("button", { name: /Revoke/ });
await userEvent.click(revokeButton);
@ -596,4 +556,48 @@ describe("AddRemoveThreepids", () => {
}),
);
});
it("should render a loader while loading", async () => {
render(
<AddRemoveThreepids
mode="hs"
medium={ThreepidMedium.Email}
threepids={[]}
isLoading={true}
onChange={() => {}}
/>,
);
expect(screen.getByLabelText("Loading…")).toBeInTheDocument();
});
it("should render email addresses", async () => {
const { container } = render(
<AddRemoveThreepids
mode="hs"
medium={ThreepidMedium.Email}
threepids={[EMAIL1]}
isLoading={false}
onChange={() => {}}
/>,
);
await expect(screen.findByText(EMAIL1.address)).resolves.toBeVisible();
expect(container).toMatchSnapshot();
});
it("should render phone numbers", async () => {
const { container } = render(
<AddRemoveThreepids
mode="hs"
medium={ThreepidMedium.Phone}
threepids={[PHONE1]}
isLoading={false}
onChange={() => {}}
/>,
);
await expect(screen.findByText(PHONE1.address)).resolves.toBeVisible();
expect(container).toMatchSnapshot();
});
});

View file

@ -11,14 +11,14 @@ exports[`AddRemoveThreepids should handle no email addresses 1`] = `
>
<input
autocomplete="email"
id="mx_Field_3"
id="mx_Field_1"
label="Email Address"
placeholder="Email Address"
type="text"
value=""
/>
<label
for="mx_Field_3"
for="mx_Field_1"
>
Email Address
</label>
@ -61,14 +61,14 @@ exports[`AddRemoveThreepids should render email addresses 1`] = `
>
<input
autocomplete="email"
id="mx_Field_1"
id="mx_Field_14"
label="Email Address"
placeholder="Email Address"
type="text"
value=""
/>
<label
for="mx_Field_1"
for="mx_Field_14"
>
Email Address
</label>
@ -148,14 +148,14 @@ exports[`AddRemoveThreepids should render phone numbers 1`] = `
</span>
<input
autocomplete="tel-national"
id="mx_Field_2"
id="mx_Field_15"
label="Phone Number"
placeholder="Phone Number"
type="text"
value=""
/>
<label
for="mx_Field_2"
for="mx_Field_15"
>
Phone Number
</label>

View file

@ -79,9 +79,7 @@ describe("<LoginWithQR />", () => {
describe("MSC4108", () => {
const getComponent = (props: { client: MatrixClient; onFinished?: () => void }) => (
<React.StrictMode>
<LoginWithQR {...defaultProps} {...props} />
</React.StrictMode>
<LoginWithQR {...defaultProps} {...props} />
);
test("render QR then back", async () => {

View file

@ -277,9 +277,7 @@ describe("<SessionManagerTab />", () => {
mockClient.getDevices.mockRejectedValue({ httpStatus: 404 });
const { container } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
expect(container.getElementsByClassName("mx_Spinner").length).toBeFalsy();
});
@ -302,9 +300,7 @@ describe("<SessionManagerTab />", () => {
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
expect(mockCrypto.getDeviceVerificationStatus).toHaveBeenCalledTimes(3);
expect(
@ -337,9 +333,7 @@ describe("<SessionManagerTab />", () => {
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
// twice for each device
expect(mockClient.getAccountData).toHaveBeenCalledTimes(4);
@ -356,9 +350,7 @@ describe("<SessionManagerTab />", () => {
const { getByTestId, queryByTestId } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
toggleDeviceDetails(getByTestId, alicesDevice.device_id);
// application metadata section not rendered
@ -369,9 +361,7 @@ describe("<SessionManagerTab />", () => {
mockClient.getDevices.mockResolvedValue({ devices: [alicesDevice] });
const { queryByTestId } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
expect(queryByTestId("other-sessions-section")).toBeFalsy();
});
@ -382,9 +372,7 @@ describe("<SessionManagerTab />", () => {
});
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
expect(getByTestId("other-sessions-section")).toBeTruthy();
});
@ -395,9 +383,7 @@ describe("<SessionManagerTab />", () => {
});
const { getByTestId, container } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
fireEvent.click(getByTestId("unverified-devices-cta"));
@ -908,7 +894,8 @@ describe("<SessionManagerTab />", () => {
});
it("deletes a device when interactive auth is not required", async () => {
mockClient.deleteMultipleDevices.mockResolvedValue({});
const deferredDeleteMultipleDevices = defer<{}>();
mockClient.deleteMultipleDevices.mockReturnValue(deferredDeleteMultipleDevices.promise);
mockClient.getDevices.mockResolvedValue({
devices: [alicesDevice, alicesMobileDevice, alicesOlderMobileDevice],
});
@ -933,6 +920,7 @@ describe("<SessionManagerTab />", () => {
fireEvent.click(signOutButton);
await confirmSignout(getByTestId);
await prom;
deferredDeleteMultipleDevices.resolve({});
// delete called
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith(
@ -991,7 +979,7 @@ describe("<SessionManagerTab />", () => {
const { getByTestId, getByLabelText } = render(getComponent());
await act(flushPromises);
await flushPromises();
// reset mock count after initial load
mockClient.getDevices.mockClear();
@ -1025,7 +1013,7 @@ describe("<SessionManagerTab />", () => {
fireEvent.submit(getByLabelText("Password"));
});
await act(flushPromises);
await flushPromises();
// called again with auth
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([alicesMobileDevice.device_id], {
@ -1551,7 +1539,7 @@ describe("<SessionManagerTab />", () => {
});
const { getByTestId, container } = render(getComponent());
await act(flushPromises);
await flushPromises();
// filter for inactive sessions
await setFilter(container, DeviceSecurityVariation.Inactive);
@ -1577,9 +1565,7 @@ describe("<SessionManagerTab />", () => {
it("lets you change the pusher state", async () => {
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
toggleDeviceDetails(getByTestId, alicesMobileDevice.device_id);
@ -1598,9 +1584,7 @@ describe("<SessionManagerTab />", () => {
it("lets you change the local notification settings state", async () => {
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
toggleDeviceDetails(getByTestId, alicesDevice.device_id);
@ -1621,9 +1605,7 @@ describe("<SessionManagerTab />", () => {
it("updates the UI when another session changes the local notifications", async () => {
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromises();
});
await flushPromises();
toggleDeviceDetails(getByTestId, alicesDevice.device_id);

View file

@ -42,14 +42,14 @@ exports[`<AccountUserSettingsTab /> 3pids should display 3pid email addresses an
>
<input
autocomplete="email"
id="mx_Field_9"
id="mx_Field_3"
label="Email Address"
placeholder="Email Address"
type="text"
value=""
/>
<label
for="mx_Field_9"
for="mx_Field_3"
>
Email Address
</label>
@ -145,14 +145,14 @@ exports[`<AccountUserSettingsTab /> 3pids should display 3pid email addresses an
</span>
<input
autocomplete="tel-national"
id="mx_Field_10"
id="mx_Field_4"
label="Phone Number"
placeholder="Phone Number"
type="text"
value=""
/>
<label
for="mx_Field_10"
for="mx_Field_4"
>
Phone Number
</label>

View file

@ -388,7 +388,7 @@ exports[`<SessionManagerTab /> goes to filtered list from security recommendatio
>
<input
aria-label="Select all"
aria-labelledby=":r4e:"
aria-labelledby=":r3s:"
data-testid="device-select-all-checkbox"
id="device-select-all-checkbox"
type="checkbox"