Use React Suspense when rendering async modals (#28386)
* Use React Suspense when rendering async modals Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix test Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve coverage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve coverage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve coverage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Update src/Modal.tsx --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
9b5d0866e0
commit
27a43e860a
17 changed files with 306 additions and 158 deletions
|
@ -149,6 +149,7 @@ describe("<MatrixChat />", () => {
|
|||
isRoomEncrypted: jest.fn(),
|
||||
logout: jest.fn(),
|
||||
getDeviceId: jest.fn(),
|
||||
getKeyBackupVersion: jest.fn().mockResolvedValue(null),
|
||||
});
|
||||
let mockClient: Mocked<MatrixClient>;
|
||||
const serverConfig = {
|
||||
|
@ -1515,7 +1516,7 @@ describe("<MatrixChat />", () => {
|
|||
|
||||
describe("when key backup failed", () => {
|
||||
it("should show the new recovery method dialog", async () => {
|
||||
const spy = jest.spyOn(Modal, "createDialogAsync");
|
||||
const spy = jest.spyOn(Modal, "createDialog");
|
||||
jest.mock("../../../../src/async-components/views/dialogs/security/NewRecoveryMethodDialog", () => ({
|
||||
__test: true,
|
||||
__esModule: true,
|
||||
|
@ -1530,7 +1531,25 @@ describe("<MatrixChat />", () => {
|
|||
await flushPromises();
|
||||
mockClient.emit(CryptoEvent.KeyBackupFailed, "error code");
|
||||
await waitFor(() => expect(spy).toHaveBeenCalledTimes(1));
|
||||
expect(await spy.mock.lastCall![0]).toEqual(expect.objectContaining({ __test: true }));
|
||||
expect((spy.mock.lastCall![0] as any)._payload._result).toEqual(expect.objectContaining({ __test: true }));
|
||||
});
|
||||
|
||||
it("should show the recovery method removed dialog", async () => {
|
||||
const spy = jest.spyOn(Modal, "createDialog");
|
||||
jest.mock("../../../../src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog", () => ({
|
||||
__test: true,
|
||||
__esModule: true,
|
||||
default: () => <span>mocked dialog</span>,
|
||||
}));
|
||||
|
||||
getComponent({});
|
||||
defaultDispatcher.dispatch({
|
||||
action: "will_start_client",
|
||||
});
|
||||
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 }));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import React from "react";
|
|||
import { mocked, MockedObject } from "jest-mock";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { CryptoApi, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
|
||||
import { render, RenderResult } from "jest-matrix-react";
|
||||
import { fireEvent, render, RenderResult, screen } from "jest-matrix-react";
|
||||
|
||||
import { filterConsole, getMockClientWithEventEmitter, mockClientMethodsCrypto } from "../../../../test-utils";
|
||||
import LogoutDialog from "../../../../../src/components/views/dialogs/LogoutDialog";
|
||||
|
@ -61,6 +61,9 @@ describe("LogoutDialog", () => {
|
|||
const rendered = renderComponent();
|
||||
await rendered.findByText("Start using Key Backup");
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(await screen.findByRole("button", { name: "Manually export keys" }));
|
||||
await expect(screen.findByRole("heading", { name: "Export room keys" })).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when there is an error fetching backups", () => {
|
||||
|
|
|
@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import { render, screen, waitFor } from "jest-matrix-react";
|
||||
import { MatrixClient, ThreepidMedium } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixClient, MatrixError, ThreepidMedium } from "matrix-js-sdk/src/matrix";
|
||||
import React from "react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { mocked } from "jest-mock";
|
||||
|
@ -16,6 +16,7 @@ import { AddRemoveThreepids } from "../../../../../src/components/views/settings
|
|||
import { clearAllModals, stubClient } from "../../../../test-utils";
|
||||
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
|
||||
import Modal from "../../../../../src/Modal";
|
||||
import InteractiveAuthDialog from "../../../../../src/components/views/dialogs/InteractiveAuthDialog.tsx";
|
||||
|
||||
const MOCK_IDENTITY_ACCESS_TOKEN = "mock_identity_access_token";
|
||||
const mockGetAccessToken = jest.fn().mockResolvedValue(MOCK_IDENTITY_ACCESS_TOKEN);
|
||||
|
@ -222,13 +223,13 @@ describe("AddRemoveThreepids", () => {
|
|||
|
||||
const continueButton = await screen.findByRole("button", { name: /Continue/ });
|
||||
|
||||
await expect(continueButton).toHaveAttribute("aria-disabled", "true");
|
||||
expect(continueButton).toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
await expect(
|
||||
await screen.findByText(
|
||||
screen.findByText(
|
||||
`A text message has been sent to +${PHONE1.address}. Please enter the verification code it contains.`,
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
).resolves.toBeInTheDocument();
|
||||
|
||||
expect(client.requestAdd3pidMsisdnToken).toHaveBeenCalledWith(
|
||||
"GB",
|
||||
|
@ -481,4 +482,118 @@ describe("AddRemoveThreepids", () => {
|
|||
expect(client.unbindThreePid).toHaveBeenCalledWith(ThreepidMedium.Phone, PHONE1.address);
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should show UIA dialog when necessary for adding email", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
const createDialogFn = jest.spyOn(Modal, "createDialog");
|
||||
mocked(client.requestAdd3pidEmailToken).mockResolvedValue({ sid: "1" });
|
||||
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Email}
|
||||
threepids={[]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
const input = screen.getByRole("textbox", { name: "Email Address" });
|
||||
await userEvent.type(input, EMAIL1.address);
|
||||
const addButton = screen.getByRole("button", { name: "Add" });
|
||||
await userEvent.click(addButton);
|
||||
|
||||
const continueButton = screen.getByRole("button", { name: "Continue" });
|
||||
|
||||
expect(continueButton).toBeEnabled();
|
||||
|
||||
mocked(client).addThreePidOnly.mockRejectedValueOnce(
|
||||
new MatrixError({ errcode: "M_UNAUTHORIZED", flows: [{ stages: [] }] }, 401),
|
||||
);
|
||||
|
||||
await userEvent.click(continueButton);
|
||||
|
||||
expect(createDialogFn).toHaveBeenCalledWith(
|
||||
InteractiveAuthDialog,
|
||||
expect.objectContaining({
|
||||
title: "Add Email Address",
|
||||
makeRequest: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("should show UIA dialog when necessary for adding msisdn", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
const createDialogFn = jest.spyOn(Modal, "createDialog");
|
||||
mocked(client.requestAdd3pidMsisdnToken).mockResolvedValue({
|
||||
sid: "1",
|
||||
msisdn: PHONE1.address,
|
||||
intl_fmt: PHONE1.address,
|
||||
success: true,
|
||||
submit_url: "https://some-url",
|
||||
});
|
||||
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Phone}
|
||||
threepids={[]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
const countryDropdown = screen.getByRole("button", { name: /Country Dropdown/ });
|
||||
await userEvent.click(countryDropdown);
|
||||
const gbOption = screen.getByRole("option", { name: "🇬🇧 United Kingdom (+44)" });
|
||||
await userEvent.click(gbOption);
|
||||
|
||||
const input = screen.getByRole("textbox", { name: "Phone Number" });
|
||||
await userEvent.type(input, PHONE1_LOCALNUM);
|
||||
|
||||
const addButton = screen.getByRole("button", { name: "Add" });
|
||||
await userEvent.click(addButton);
|
||||
|
||||
const continueButton = screen.getByRole("button", { name: "Continue" });
|
||||
|
||||
expect(continueButton).toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
await expect(
|
||||
screen.findByText(
|
||||
`A text message has been sent to +${PHONE1.address}. Please enter the verification code it contains.`,
|
||||
),
|
||||
).resolves.toBeInTheDocument();
|
||||
|
||||
expect(client.requestAdd3pidMsisdnToken).toHaveBeenCalledWith(
|
||||
"GB",
|
||||
PHONE1_LOCALNUM,
|
||||
client.generateClientSecret(),
|
||||
1,
|
||||
);
|
||||
|
||||
const verificationInput = screen.getByRole("textbox", { name: "Verification code" });
|
||||
await userEvent.type(verificationInput, "123456");
|
||||
|
||||
expect(continueButton).not.toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
mocked(client).addThreePidOnly.mockRejectedValueOnce(
|
||||
new MatrixError({ errcode: "M_UNAUTHORIZED", flows: [{ stages: [] }] }, 401),
|
||||
);
|
||||
|
||||
await userEvent.click(continueButton);
|
||||
|
||||
expect(createDialogFn).toHaveBeenCalledWith(
|
||||
InteractiveAuthDialog,
|
||||
expect.objectContaining({
|
||||
title: "Add Phone Number",
|
||||
makeRequest: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import { render, waitFor } from "jest-matrix-react";
|
||||
import { render, waitFor, screen, fireEvent } from "jest-matrix-react";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
|
@ -64,4 +64,34 @@ describe("CryptographyPanel", () => {
|
|||
// Then "not supported key
|
||||
await waitFor(() => expect(codes[1].innerHTML).toEqual("<strong><not supported></strong>"));
|
||||
});
|
||||
|
||||
it("should open the export e2e keys dialog on click", async () => {
|
||||
const sessionId = "ABCDEFGHIJ";
|
||||
const sessionKey = "AbCDeFghIJK7L/m4nOPqRSTUVW4xyzaBCDef6gHIJkl";
|
||||
|
||||
TestUtils.stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.safeGet();
|
||||
client.deviceId = sessionId;
|
||||
|
||||
mocked(client.getCrypto()!.getOwnDeviceKeys).mockResolvedValue({ ed25519: sessionKey, curve25519: "1234" });
|
||||
|
||||
render(<CryptographyPanel />, withClientContextRenderOptions(client));
|
||||
fireEvent.click(await screen.findByRole("button", { name: "Export E2E room keys" }));
|
||||
await expect(screen.findByRole("heading", { name: "Export room keys" })).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should open the import e2e keys dialog on click", async () => {
|
||||
const sessionId = "ABCDEFGHIJ";
|
||||
const sessionKey = "AbCDeFghIJK7L/m4nOPqRSTUVW4xyzaBCDef6gHIJkl";
|
||||
|
||||
TestUtils.stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.safeGet();
|
||||
client.deviceId = sessionId;
|
||||
|
||||
mocked(client.getCrypto()!.getOwnDeviceKeys).mockResolvedValue({ ed25519: sessionKey, curve25519: "1234" });
|
||||
|
||||
render(<CryptographyPanel />, withClientContextRenderOptions(client));
|
||||
fireEvent.click(await screen.findByRole("button", { name: "Import E2E room keys" }));
|
||||
await expect(screen.findByRole("heading", { name: "Import room keys" })).resolves.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue