Refactor the various email/phone management UI into a single component (#12884)
* Refactor the various email/phone management UI into a single component These were basically the same component copied & pasted 3 times and tweaked to match the behaviour of each case. This de-dupes them into one component. This all could really benefit from playwright tests, but would require setting up a dummy ID server in the playwright tests. This is all legacy pre-MAS stuff so its questionable whether its worth the effort. * Basic test, remove old tests * Use different text to confirm remove & put headers back although the two texts are both 'Remove' in practice * Remove string This was never triggered anyway with sydent & synapse because they don't seem to agree on what error to return. In any case, I think it makes more sense for it to be consistent with the email path, ie. using a dialog. * Avoid nested forms * Snapshots * More snapshots * Test the hs side * Snapshots * Test IS bind/revoke * Test remove can be cancelled * Test unvalidated cases & fix phone error * Reset state between tests * Import useState directly * One more direct React import
This commit is contained in:
parent
de898d1b62
commit
4751c52d82
21 changed files with 1391 additions and 1981 deletions
534
test/components/views/settings/AddRemoveThreepids-test.tsx
Normal file
534
test/components/views/settings/AddRemoveThreepids-test.tsx
Normal file
|
@ -0,0 +1,534 @@
|
|||
/*
|
||||
Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { MatrixClient, ThreepidMedium } from "matrix-js-sdk/src/matrix";
|
||||
import React from "react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import { AddRemoveThreepids } from "../../../../src/components/views/settings/AddRemoveThreepids";
|
||||
import { clearAllModals, stubClient } from "../../../test-utils";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import Modal from "../../../../src/Modal";
|
||||
|
||||
const MOCK_IDENTITY_ACCESS_TOKEN = "mock_identity_access_token";
|
||||
const mockGetAccessToken = jest.fn().mockResolvedValue(MOCK_IDENTITY_ACCESS_TOKEN);
|
||||
jest.mock("../../../../src/IdentityAuthClient", () =>
|
||||
jest.fn().mockImplementation(() => ({
|
||||
getAccessToken: mockGetAccessToken,
|
||||
})),
|
||||
);
|
||||
|
||||
const EMAIL1 = {
|
||||
medium: ThreepidMedium.Email,
|
||||
address: "alice@nowhere.dummy",
|
||||
};
|
||||
|
||||
const PHONE1 = {
|
||||
medium: ThreepidMedium.Phone,
|
||||
address: "447700900000",
|
||||
};
|
||||
|
||||
const PHONE1_LOCALNUM = "07700900000";
|
||||
|
||||
describe("AddRemoveThreepids", () => {
|
||||
let client: MatrixClient;
|
||||
|
||||
beforeEach(() => {
|
||||
client = stubClient();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
clearAllModals();
|
||||
});
|
||||
|
||||
const clientProviderWrapper: React.FC = ({ children }) => (
|
||||
<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
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Email}
|
||||
threepids={[]}
|
||||
isLoading={false}
|
||||
onChange={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should add an email address", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
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);
|
||||
|
||||
expect(client.requestAdd3pidEmailToken).toHaveBeenCalledWith(EMAIL1.address, client.generateClientSecret(), 1);
|
||||
const continueButton = screen.getByRole("button", { name: "Continue" });
|
||||
|
||||
expect(continueButton).toBeEnabled();
|
||||
|
||||
await userEvent.click(continueButton);
|
||||
|
||||
expect(client.addThreePidOnly).toHaveBeenCalledWith({
|
||||
client_secret: client.generateClientSecret(),
|
||||
sid: "1",
|
||||
auth: undefined,
|
||||
});
|
||||
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should display an error if the link has not been clicked", 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 Error("Unauthorized"));
|
||||
|
||||
await userEvent.click(continueButton);
|
||||
|
||||
expect(createDialogFn).toHaveBeenCalledWith(expect.anything(), {
|
||||
description: "Unauthorized",
|
||||
title: "Unable to verify email address.",
|
||||
});
|
||||
|
||||
expect(onChangeFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should add a phone number", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
mocked(client.requestAdd3pidMsisdnToken).mockResolvedValue({
|
||||
sid: "1",
|
||||
msisdn: PHONE1.address,
|
||||
intl_fmt: "+" + PHONE1.address,
|
||||
success: true,
|
||||
submit_url: "https://example.dummy",
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
expect(client.requestAdd3pidMsisdnToken).toHaveBeenCalledWith(
|
||||
"GB",
|
||||
PHONE1_LOCALNUM,
|
||||
client.generateClientSecret(),
|
||||
1,
|
||||
);
|
||||
const continueButton = screen.getByRole("button", { name: "Continue" });
|
||||
|
||||
expect(continueButton).toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
const verificationInput = screen.getByRole("textbox", { name: "Verification code" });
|
||||
await userEvent.type(verificationInput, "123456");
|
||||
|
||||
expect(continueButton).not.toHaveAttribute("aria-disabled", "true");
|
||||
await userEvent.click(continueButton);
|
||||
|
||||
expect(client.addThreePidOnly).toHaveBeenCalledWith({
|
||||
client_secret: client.generateClientSecret(),
|
||||
sid: "1",
|
||||
auth: undefined,
|
||||
});
|
||||
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should display an error if the code is incorrect", 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://example.dummy",
|
||||
});
|
||||
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Phone}
|
||||
threepids={[]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
const input = screen.getByRole("textbox", { name: "Phone Number" });
|
||||
await userEvent.type(input, PHONE1_LOCALNUM);
|
||||
|
||||
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 addButton = screen.getByRole("button", { name: "Add" });
|
||||
await userEvent.click(addButton);
|
||||
|
||||
mocked(client).addThreePidOnly.mockRejectedValueOnce(new Error("Unauthorized"));
|
||||
|
||||
const verificationInput = screen.getByRole("textbox", { name: "Verification code" });
|
||||
await userEvent.type(verificationInput, "123457");
|
||||
|
||||
const continueButton = screen.getByRole("button", { name: "Continue" });
|
||||
await userEvent.click(continueButton);
|
||||
|
||||
expect(createDialogFn).toHaveBeenCalledWith(expect.anything(), {
|
||||
description: "Unauthorized",
|
||||
title: "Unable to verify phone number.",
|
||||
});
|
||||
|
||||
expect(onChangeFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should remove an email address", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Email}
|
||||
threepids={[EMAIL1]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
const removeButton = screen.getByRole("button", { name: "Remove" });
|
||||
await userEvent.click(removeButton);
|
||||
|
||||
expect(screen.getByText(`Remove ${EMAIL1.address}?`)).toBeVisible();
|
||||
|
||||
const confirmRemoveButton = screen.getByRole("button", { name: "Remove" });
|
||||
await userEvent.click(confirmRemoveButton);
|
||||
|
||||
expect(client.deleteThreePid).toHaveBeenCalledWith(ThreepidMedium.Email, EMAIL1.address);
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should return to default view if adding is cancelled", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Email}
|
||||
threepids={[EMAIL1]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
const removeButton = screen.getByRole("button", { name: "Remove" });
|
||||
await userEvent.click(removeButton);
|
||||
|
||||
expect(screen.getByText(`Remove ${EMAIL1.address}?`)).toBeVisible();
|
||||
|
||||
const confirmRemoveButton = screen.getByRole("button", { name: "Cancel" });
|
||||
await userEvent.click(confirmRemoveButton);
|
||||
|
||||
expect(screen.queryByText(`Remove ${EMAIL1.address}?`)).not.toBeInTheDocument();
|
||||
|
||||
expect(client.deleteThreePid).not.toHaveBeenCalledWith(ThreepidMedium.Email, EMAIL1.address);
|
||||
expect(onChangeFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should remove a phone number", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Phone}
|
||||
threepids={[PHONE1]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
const removeButton = screen.getByRole("button", { name: "Remove" });
|
||||
await userEvent.click(removeButton);
|
||||
|
||||
expect(screen.getByText(`Remove ${PHONE1.address}?`)).toBeVisible();
|
||||
|
||||
const confirmRemoveButton = screen.getByRole("button", { name: "Remove" });
|
||||
await userEvent.click(confirmRemoveButton);
|
||||
|
||||
expect(client.deleteThreePid).toHaveBeenCalledWith(ThreepidMedium.Phone, PHONE1.address);
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should bind an email address", async () => {
|
||||
mocked(client).requestEmailToken.mockResolvedValue({ sid: "1" });
|
||||
|
||||
mocked(client).getIdentityServerUrl.mockReturnValue("https://the_best_id_server.dummy");
|
||||
|
||||
const onChangeFn = jest.fn();
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="is"
|
||||
medium={ThreepidMedium.Email}
|
||||
threepids={[Object.assign({}, EMAIL1, { bound: false })]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
expect(screen.getByText(EMAIL1.address)).toBeVisible();
|
||||
const shareButton = screen.getByRole("button", { name: "Share" });
|
||||
await userEvent.click(shareButton);
|
||||
|
||||
expect(screen.getByText("Verify the link in your inbox")).toBeVisible();
|
||||
|
||||
expect(client.requestEmailToken).toHaveBeenCalledWith(
|
||||
EMAIL1.address,
|
||||
client.generateClientSecret(),
|
||||
1,
|
||||
undefined,
|
||||
MOCK_IDENTITY_ACCESS_TOKEN,
|
||||
);
|
||||
|
||||
const completeButton = screen.getByRole("button", { name: "Complete" });
|
||||
await userEvent.click(completeButton);
|
||||
|
||||
expect(client.bindThreePid).toHaveBeenCalledWith({
|
||||
sid: "1",
|
||||
client_secret: client.generateClientSecret(),
|
||||
id_server: "https://the_best_id_server.dummy",
|
||||
id_access_token: MOCK_IDENTITY_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should bind a phone number", async () => {
|
||||
mocked(client).requestMsisdnToken.mockResolvedValue({
|
||||
success: true,
|
||||
sid: "1",
|
||||
msisdn: PHONE1.address,
|
||||
intl_fmt: "+" + PHONE1.address,
|
||||
});
|
||||
|
||||
mocked(client).getIdentityServerUrl.mockReturnValue("https://the_best_id_server.dummy");
|
||||
|
||||
const onChangeFn = jest.fn();
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="is"
|
||||
medium={ThreepidMedium.Phone}
|
||||
threepids={[Object.assign({}, PHONE1, { bound: false })]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
expect(screen.getByText(PHONE1.address)).toBeVisible();
|
||||
const shareButton = screen.getByRole("button", { name: "Share" });
|
||||
await userEvent.click(shareButton);
|
||||
|
||||
expect(screen.getByText("Please enter verification code sent via text.")).toBeVisible();
|
||||
|
||||
expect(client.requestMsisdnToken).toHaveBeenCalledWith(
|
||||
null,
|
||||
"+" + PHONE1.address,
|
||||
client.generateClientSecret(),
|
||||
1,
|
||||
undefined,
|
||||
MOCK_IDENTITY_ACCESS_TOKEN,
|
||||
);
|
||||
|
||||
const codeInput = screen.getByRole("textbox", { name: "Verification code" });
|
||||
await userEvent.type(codeInput, "123456");
|
||||
await userEvent.keyboard("{Enter}");
|
||||
|
||||
expect(client.bindThreePid).toHaveBeenCalledWith({
|
||||
sid: "1",
|
||||
client_secret: client.generateClientSecret(),
|
||||
id_server: "https://the_best_id_server.dummy",
|
||||
id_access_token: MOCK_IDENTITY_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should revoke a bound email address", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="is"
|
||||
medium={ThreepidMedium.Email}
|
||||
threepids={[Object.assign({}, EMAIL1, { bound: true })]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
expect(screen.getByText(EMAIL1.address)).toBeVisible();
|
||||
const revokeButton = screen.getByRole("button", { name: "Revoke" });
|
||||
await userEvent.click(revokeButton);
|
||||
|
||||
expect(client.unbindThreePid).toHaveBeenCalledWith(ThreepidMedium.Email, EMAIL1.address);
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should revoke a bound phone number", async () => {
|
||||
const onChangeFn = jest.fn();
|
||||
render(
|
||||
<AddRemoveThreepids
|
||||
mode="is"
|
||||
medium={ThreepidMedium.Phone}
|
||||
threepids={[Object.assign({}, PHONE1, { bound: true })]}
|
||||
isLoading={false}
|
||||
onChange={onChangeFn}
|
||||
/>,
|
||||
{
|
||||
wrapper: clientProviderWrapper,
|
||||
},
|
||||
);
|
||||
|
||||
expect(screen.getByText(PHONE1.address)).toBeVisible();
|
||||
const revokeButton = screen.getByRole("button", { name: "Revoke" });
|
||||
await userEvent.click(revokeButton);
|
||||
|
||||
expect(client.unbindThreePid).toHaveBeenCalledWith(ThreepidMedium.Phone, PHONE1.address);
|
||||
expect(onChangeFn).toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,172 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AddRemoveThreepids should handle no email addresses 1`] = `
|
||||
<div>
|
||||
<form
|
||||
autocomplete="off"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input"
|
||||
>
|
||||
<input
|
||||
autocomplete="email"
|
||||
id="mx_Field_3"
|
||||
label="Email Address"
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_3"
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Add
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AddRemoveThreepids should render email addresses 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_AddRemoveThreepids_existing"
|
||||
>
|
||||
<span
|
||||
class="mx_AddRemoveThreepids_existing_address"
|
||||
>
|
||||
alice@nowhere.dummy
|
||||
</span>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Remove
|
||||
</div>
|
||||
</div>
|
||||
<form
|
||||
autocomplete="off"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input"
|
||||
>
|
||||
<input
|
||||
autocomplete="email"
|
||||
id="mx_Field_1"
|
||||
label="Email Address"
|
||||
placeholder="Email Address"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_1"
|
||||
>
|
||||
Email Address
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Add
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AddRemoveThreepids should render phone numbers 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_AddRemoveThreepids_existing"
|
||||
>
|
||||
<span
|
||||
class="mx_AddRemoveThreepids_existing_address"
|
||||
>
|
||||
447700900000
|
||||
</span>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Remove
|
||||
</div>
|
||||
</div>
|
||||
<form
|
||||
autocomplete="off"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft"
|
||||
>
|
||||
<span
|
||||
class="mx_Field_prefix"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown mx_PhoneNumbers_country mx_CountryDropdown"
|
||||
>
|
||||
<div
|
||||
aria-describedby="mx_CountryDropdown_value"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-label="Country Dropdown"
|
||||
aria-owns="mx_CountryDropdown_input"
|
||||
class="mx_AccessibleButton mx_Dropdown_input mx_no_textinput"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option"
|
||||
id="mx_CountryDropdown_value"
|
||||
>
|
||||
<span
|
||||
class="mx_CountryDropdown_shortOption"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option_emoji"
|
||||
>
|
||||
🇺🇸
|
||||
</div>
|
||||
+1
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Dropdown_arrow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<input
|
||||
autocomplete="tel-national"
|
||||
id="mx_Field_2"
|
||||
label="Phone Number"
|
||||
placeholder="Phone Number"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_2"
|
||||
>
|
||||
Phone Number
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Add
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import PhoneNumbers from "../../../../../src/components/views/settings/account/PhoneNumbers";
|
||||
import { stubClient } from "../../../../test-utils";
|
||||
import SdkConfig from "../../../../../src/SdkConfig";
|
||||
|
||||
describe("<PhoneNumbers />", () => {
|
||||
it("should allow a phone number to be added", async () => {
|
||||
SdkConfig.add({
|
||||
default_country_code: "GB",
|
||||
});
|
||||
|
||||
const cli = stubClient();
|
||||
const onMsisdnsChange = jest.fn();
|
||||
const { asFragment, getByLabelText, getByText } = render(
|
||||
<PhoneNumbers msisdns={[]} onMsisdnsChange={onMsisdnsChange} />,
|
||||
);
|
||||
|
||||
mocked(cli.requestAdd3pidMsisdnToken).mockResolvedValue({
|
||||
sid: "SID",
|
||||
msisdn: "447900111222",
|
||||
submit_url: "https://server.url",
|
||||
success: true,
|
||||
intl_fmt: "no-clue",
|
||||
});
|
||||
mocked(cli.submitMsisdnTokenOtherUrl).mockResolvedValue({ success: true });
|
||||
mocked(cli.addThreePidOnly).mockResolvedValue({});
|
||||
|
||||
const phoneNumberField = getByLabelText("Phone Number");
|
||||
await userEvent.type(phoneNumberField, "7900111222");
|
||||
await userEvent.click(getByText("Add"));
|
||||
|
||||
expect(cli.requestAdd3pidMsisdnToken).toHaveBeenCalledWith("GB", "7900111222", "t35tcl1Ent5ECr3T", 1);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
const verificationCodeField = getByLabelText("Verification code");
|
||||
await userEvent.type(verificationCodeField, "123666");
|
||||
await userEvent.click(getByText("Continue"));
|
||||
|
||||
expect(cli.submitMsisdnTokenOtherUrl).toHaveBeenCalledWith(
|
||||
"https://server.url",
|
||||
"SID",
|
||||
"t35tcl1Ent5ECr3T",
|
||||
"123666",
|
||||
);
|
||||
expect(onMsisdnsChange).toHaveBeenCalledWith([{ address: "447900111222", medium: "msisdn" }]);
|
||||
});
|
||||
});
|
|
@ -1,110 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<PhoneNumbers /> should allow a phone number to be added 1`] = `
|
||||
<DocumentFragment>
|
||||
<form
|
||||
autocomplete="off"
|
||||
class="mx_PhoneNumbers_new"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="mx_PhoneNumbers_input"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft"
|
||||
>
|
||||
<span
|
||||
class="mx_Field_prefix"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown mx_PhoneNumbers_country mx_CountryDropdown mx_Dropdown_disabled"
|
||||
>
|
||||
<div
|
||||
aria-describedby="mx_CountryDropdown_value"
|
||||
aria-disabled="true"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-label="Country Dropdown"
|
||||
aria-owns="mx_CountryDropdown_input"
|
||||
class="mx_AccessibleButton mx_Dropdown_input mx_no_textinput mx_AccessibleButton_disabled"
|
||||
disabled=""
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option"
|
||||
id="mx_CountryDropdown_value"
|
||||
>
|
||||
<span
|
||||
class="mx_CountryDropdown_shortOption"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option_emoji"
|
||||
>
|
||||
🇬🇧
|
||||
</div>
|
||||
+44
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Dropdown_arrow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<input
|
||||
autocomplete="tel-national"
|
||||
disabled=""
|
||||
id="mx_Field_1"
|
||||
label="Phone Number"
|
||||
placeholder="Phone Number"
|
||||
type="text"
|
||||
value="7900111222"
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_1"
|
||||
>
|
||||
Phone Number
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<div>
|
||||
A text message has been sent to +447900111222. Please enter the verification code it contains.
|
||||
<br />
|
||||
</div>
|
||||
<form
|
||||
autocomplete="off"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
id="mx_Field_2"
|
||||
label="Verification code"
|
||||
placeholder="Verification code"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_2"
|
||||
>
|
||||
Verification code
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
aria-disabled="true"
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled"
|
||||
disabled=""
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Continue
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { IThreepid, ThreepidMedium, IRequestTokenResponse, MatrixError } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { TranslationKey, UserFriendlyError } from "../../../../../src/languageHandler";
|
||||
import EmailAddresses, { EmailAddress } from "../../../../../src/components/views/settings/discovery/EmailAddresses";
|
||||
import { clearAllModals, getMockClientWithEventEmitter } from "../../../../test-utils";
|
||||
|
||||
const mockGetAccessToken = jest.fn().mockResolvedValue("getAccessToken");
|
||||
jest.mock("../../../../../src/IdentityAuthClient", () =>
|
||||
jest.fn().mockImplementation(() => ({
|
||||
getAccessToken: mockGetAccessToken,
|
||||
})),
|
||||
);
|
||||
|
||||
const emailThreepidFixture: IThreepid = {
|
||||
medium: ThreepidMedium.Email,
|
||||
address: "foo@bar.com",
|
||||
validated_at: 12345,
|
||||
added_at: 12342,
|
||||
bound: false,
|
||||
};
|
||||
|
||||
describe("<EmailAddress/>", () => {
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getIdentityServerUrl: jest.fn().mockReturnValue("https://fake-identity-server"),
|
||||
generateClientSecret: jest.fn(),
|
||||
requestEmailToken: jest.fn(),
|
||||
bindThreePid: jest.fn(),
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
jest.useRealTimers();
|
||||
await clearAllModals();
|
||||
});
|
||||
|
||||
it("should track props.email.bound changes", async () => {
|
||||
const { rerender } = render(<EmailAddress email={emailThreepidFixture} />);
|
||||
await screen.findByText("Share");
|
||||
|
||||
rerender(
|
||||
<EmailAddress
|
||||
email={{
|
||||
...emailThreepidFixture,
|
||||
bound: true,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
await screen.findByText("Revoke");
|
||||
});
|
||||
|
||||
describe("Email verification share phase", () => {
|
||||
it("shows translated error message", async () => {
|
||||
render(<EmailAddress email={emailThreepidFixture} />);
|
||||
mockClient.requestEmailToken.mockRejectedValue(
|
||||
new MatrixError(
|
||||
{ errcode: "M_THREEPID_IN_USE", error: "Some fake MatrixError occured" },
|
||||
400,
|
||||
"https://fake-url/",
|
||||
),
|
||||
);
|
||||
fireEvent.click(screen.getByText("Share"));
|
||||
|
||||
// Expect error dialog/modal to be shown. We have to wait for the UI to transition.
|
||||
expect(await screen.findByText("This email address is already in use")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Email verification complete phase", () => {
|
||||
beforeEach(async () => {
|
||||
// Start these tests out at the "Complete" phase
|
||||
render(<EmailAddress email={emailThreepidFixture} />);
|
||||
mockClient.requestEmailToken.mockResolvedValue({ sid: "123-fake-sid" } satisfies IRequestTokenResponse);
|
||||
fireEvent.click(screen.getByText("Share"));
|
||||
// Then wait for the completion screen to come up
|
||||
await screen.findByText("Complete");
|
||||
});
|
||||
|
||||
it("Shows error dialog when share completion fails (email not verified yet)", async () => {
|
||||
mockClient.bindThreePid.mockRejectedValue(
|
||||
new MatrixError(
|
||||
{ errcode: "M_THREEPID_AUTH_FAILED", error: "Some fake MatrixError occured" },
|
||||
403,
|
||||
"https://fake-url/",
|
||||
),
|
||||
);
|
||||
await expect(screen.findByText("Complete")).resolves.not.toHaveAttribute("aria-disabled", "true");
|
||||
fireEvent.click(screen.getByText("Complete"));
|
||||
|
||||
// Expect error dialog/modal to be shown. We have to wait for the UI to transition.
|
||||
// Check the title
|
||||
expect(await screen.findByText("Your email address hasn't been verified yet")).toBeInTheDocument();
|
||||
// Check the description
|
||||
expect(
|
||||
await screen.findByText(
|
||||
"Click the link in the email you received to verify and then click continue again.",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("Shows error dialog when share completion fails (UserFriendlyError)", async () => {
|
||||
const fakeErrorText = "Fake UserFriendlyError error in test" as TranslationKey;
|
||||
mockClient.bindThreePid.mockRejectedValue(new UserFriendlyError(fakeErrorText));
|
||||
await expect(screen.findByText("Complete")).resolves.not.toHaveAttribute("aria-disabled", "true");
|
||||
fireEvent.click(screen.getByText("Complete"));
|
||||
|
||||
// Expect error dialog/modal to be shown. We have to wait for the UI to transition.
|
||||
// Check the title
|
||||
expect(await screen.findByText("Unable to verify email address.")).toBeInTheDocument();
|
||||
// Check the description
|
||||
expect(await screen.findByText(fakeErrorText)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("Shows error dialog when share completion fails (generic error)", async () => {
|
||||
const fakeErrorText = "Fake plain error in test";
|
||||
mockClient.bindThreePid.mockRejectedValue(new Error(fakeErrorText));
|
||||
await expect(screen.findByText("Complete")).resolves.not.toHaveAttribute("aria-disabled", "true");
|
||||
fireEvent.click(screen.getByText("Complete"));
|
||||
|
||||
// Expect error dialog/modal to be shown. We have to wait for the UI to transition.
|
||||
// Check the title
|
||||
expect(await screen.findByText("Unable to verify email address.")).toBeInTheDocument();
|
||||
// Check the description
|
||||
expect(await screen.findByText(fakeErrorText)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("<EmailAddresses />", () => {
|
||||
it("should render a loader while loading", async () => {
|
||||
const { container } = render(<EmailAddresses emails={[emailThreepidFixture]} isLoading={true} />);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render email addresses", async () => {
|
||||
const { container } = render(<EmailAddresses emails={[emailThreepidFixture]} isLoading={false} />);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should handle no email addresses", async () => {
|
||||
const { container } = render(<EmailAddresses emails={[]} isLoading={false} />);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { IThreepid, ThreepidMedium } from "matrix-js-sdk/src/matrix";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import PhoneNumbers, { PhoneNumber } from "../../../../../src/components/views/settings/discovery/PhoneNumbers";
|
||||
import { stubClient } from "../../../../test-utils";
|
||||
|
||||
const msisdn: IThreepid = {
|
||||
medium: ThreepidMedium.Phone,
|
||||
address: "441111111111",
|
||||
validated_at: 12345,
|
||||
added_at: 12342,
|
||||
bound: false,
|
||||
};
|
||||
describe("<PhoneNumber/>", () => {
|
||||
it("should track props.msisdn.bound changes", async () => {
|
||||
const { rerender } = render(<PhoneNumber msisdn={{ ...msisdn }} />);
|
||||
await screen.findByText("Share");
|
||||
|
||||
rerender(<PhoneNumber msisdn={{ ...msisdn, bound: true }} />);
|
||||
await screen.findByText("Revoke");
|
||||
});
|
||||
});
|
||||
|
||||
const mockGetAccessToken = jest.fn().mockResolvedValue("$$getAccessToken");
|
||||
jest.mock("../../../../../src/IdentityAuthClient", () =>
|
||||
jest.fn().mockImplementation(() => ({
|
||||
getAccessToken: mockGetAccessToken,
|
||||
})),
|
||||
);
|
||||
|
||||
describe("<PhoneNumbers />", () => {
|
||||
it("should render a loader while loading", async () => {
|
||||
const { container } = render(<PhoneNumbers msisdns={[{ ...msisdn }]} isLoading={true} />);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render phone numbers", async () => {
|
||||
const { container } = render(<PhoneNumbers msisdns={[{ ...msisdn }]} isLoading={false} />);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should handle no numbers", async () => {
|
||||
const { container } = render(<PhoneNumbers msisdns={[]} isLoading={false} />);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should allow binding msisdn", async () => {
|
||||
const cli = stubClient();
|
||||
const { getByText, getByLabelText, asFragment } = render(
|
||||
<PhoneNumbers msisdns={[{ ...msisdn }]} isLoading={false} />,
|
||||
);
|
||||
|
||||
mocked(cli.requestMsisdnToken).mockResolvedValue({
|
||||
sid: "SID",
|
||||
msisdn: "+447900111222",
|
||||
submit_url: "https://server.url",
|
||||
success: true,
|
||||
intl_fmt: "no-clue",
|
||||
});
|
||||
|
||||
fireEvent.click(getByText("Share"));
|
||||
await waitFor(() =>
|
||||
expect(cli.requestMsisdnToken).toHaveBeenCalledWith(
|
||||
null,
|
||||
"+441111111111",
|
||||
"t35tcl1Ent5ECr3T",
|
||||
1,
|
||||
undefined,
|
||||
"$$getAccessToken",
|
||||
),
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
const verificationCodeField = getByLabelText("Verification code");
|
||||
await userEvent.type(verificationCodeField, "123666{Enter}");
|
||||
|
||||
expect(cli.submitMsisdnToken).toHaveBeenCalledWith("SID", "t35tcl1Ent5ECr3T", "123666", "$$getAccessToken");
|
||||
});
|
||||
});
|
|
@ -1,97 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<EmailAddresses /> should handle no email addresses 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Email addresses
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_description"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Discovery options will appear once you have added an email.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<EmailAddresses /> should render a loader while loading 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Email addresses
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||
>
|
||||
<div
|
||||
class="mx_InlineSpinner"
|
||||
>
|
||||
<div
|
||||
aria-label="Loading…"
|
||||
class="mx_InlineSpinner_icon mx_Spinner_icon"
|
||||
style="width: 16px; height: 16px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<EmailAddresses /> should render email addresses 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Email addresses
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||
>
|
||||
<div
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing"
|
||||
>
|
||||
<span
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing_address"
|
||||
>
|
||||
foo@bar.com
|
||||
</span>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_EmailAddressesPhoneNumbers_discovery_existing_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Share
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -1,163 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<PhoneNumbers /> should allow binding msisdn 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="mx_DiscoveryPhoneNumbers"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Phone numbers
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||
>
|
||||
<div
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing"
|
||||
>
|
||||
<span
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing_address"
|
||||
>
|
||||
+441111111111
|
||||
</span>
|
||||
<span
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing_verification"
|
||||
>
|
||||
<span>
|
||||
Please enter verification code sent via text.
|
||||
<br />
|
||||
</span>
|
||||
<form
|
||||
autocomplete="off"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
id="mx_Field_1"
|
||||
label="Verification code"
|
||||
placeholder="Verification code"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_1"
|
||||
>
|
||||
Verification code
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`<PhoneNumbers /> should handle no numbers 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="mx_DiscoveryPhoneNumbers"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Phone numbers
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_description"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Discovery options will appear once you have added a phone number.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<PhoneNumbers /> should render a loader while loading 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="mx_DiscoveryPhoneNumbers"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Phone numbers
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||
>
|
||||
<div
|
||||
class="mx_InlineSpinner"
|
||||
>
|
||||
<div
|
||||
aria-label="Loading…"
|
||||
class="mx_InlineSpinner_icon mx_Spinner_icon"
|
||||
style="width: 16px; height: 16px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<PhoneNumbers /> should render phone numbers 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="mx_DiscoveryPhoneNumbers"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Phone numbers
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||
>
|
||||
<div
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing"
|
||||
>
|
||||
<span
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing_address"
|
||||
>
|
||||
+
|
||||
441111111111
|
||||
</span>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_EmailAddressesPhoneNumbers_discovery_existing_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Share
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -18,10 +18,10 @@ exports[`<AccountUserSettingsTab /> 3pids should display 3pid email addresses an
|
|||
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||
>
|
||||
<div
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing"
|
||||
class="mx_AddRemoveThreepids_existing"
|
||||
>
|
||||
<span
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing_address"
|
||||
class="mx_AddRemoveThreepids_existing_address"
|
||||
>
|
||||
test@test.io
|
||||
</span>
|
||||
|
@ -84,12 +84,11 @@ exports[`<AccountUserSettingsTab /> 3pids should display 3pid email addresses an
|
|||
class="mx_SettingsSubsection_content mx_SettingsSubsection_contentStretch"
|
||||
>
|
||||
<div
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing"
|
||||
class="mx_AddRemoveThreepids_existing"
|
||||
>
|
||||
<span
|
||||
class="mx_EmailAddressesPhoneNumbers_discovery_existing_address"
|
||||
class="mx_AddRemoveThreepids_existing_address"
|
||||
>
|
||||
+
|
||||
123456789
|
||||
</span>
|
||||
<div
|
||||
|
@ -102,75 +101,70 @@ exports[`<AccountUserSettingsTab /> 3pids should display 3pid email addresses an
|
|||
</div>
|
||||
<form
|
||||
autocomplete="off"
|
||||
class="mx_PhoneNumbers_new"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="mx_PhoneNumbers_input"
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft"
|
||||
<span
|
||||
class="mx_Field_prefix"
|
||||
>
|
||||
<span
|
||||
class="mx_Field_prefix"
|
||||
<div
|
||||
class="mx_Dropdown mx_PhoneNumbers_country mx_CountryDropdown"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown mx_PhoneNumbers_country mx_CountryDropdown"
|
||||
aria-describedby="mx_CountryDropdown_value"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-label="Country Dropdown"
|
||||
aria-owns="mx_CountryDropdown_input"
|
||||
class="mx_AccessibleButton mx_Dropdown_input mx_no_textinput"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
aria-describedby="mx_CountryDropdown_value"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-label="Country Dropdown"
|
||||
aria-owns="mx_CountryDropdown_input"
|
||||
class="mx_AccessibleButton mx_Dropdown_input mx_no_textinput"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="mx_Dropdown_option"
|
||||
id="mx_CountryDropdown_value"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option"
|
||||
id="mx_CountryDropdown_value"
|
||||
>
|
||||
<span
|
||||
class="mx_CountryDropdown_shortOption"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option_emoji"
|
||||
>
|
||||
🇺🇸
|
||||
</div>
|
||||
+1
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Dropdown_arrow"
|
||||
/>
|
||||
class="mx_CountryDropdown_shortOption"
|
||||
>
|
||||
<div
|
||||
class="mx_Dropdown_option_emoji"
|
||||
>
|
||||
🇺🇸
|
||||
</div>
|
||||
+1
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Dropdown_arrow"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
<input
|
||||
autocomplete="tel-national"
|
||||
id="mx_Field_10"
|
||||
label="Phone Number"
|
||||
placeholder="Phone Number"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_10"
|
||||
>
|
||||
Phone Number
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<input
|
||||
autocomplete="tel-national"
|
||||
id="mx_Field_10"
|
||||
label="Phone Number"
|
||||
placeholder="Phone Number"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_10"
|
||||
>
|
||||
Phone Number
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Add
|
||||
</div>
|
||||
</form>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Add
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue