Prepare for repo merge
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
0f670b8dc0
commit
b084ff2313
807 changed files with 0 additions and 0 deletions
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { act, fireEvent, render } from "jest-matrix-react";
|
||||
|
||||
import CurrentDeviceSection from "../../../../../src/components/views/settings/devices/CurrentDeviceSection";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
describe("<CurrentDeviceSection />", () => {
|
||||
const deviceId = "alices_device";
|
||||
|
||||
const alicesVerifiedDevice = {
|
||||
device_id: deviceId,
|
||||
isVerified: false,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const alicesUnverifiedDevice = {
|
||||
device_id: deviceId,
|
||||
isVerified: false,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
device: alicesVerifiedDevice,
|
||||
onVerifyCurrentDevice: jest.fn(),
|
||||
onSignOutCurrentDevice: jest.fn(),
|
||||
saveDeviceName: jest.fn(),
|
||||
isLoading: false,
|
||||
isSigningOut: false,
|
||||
otherSessionsCount: 1,
|
||||
setPushNotifications: jest.fn(),
|
||||
};
|
||||
|
||||
const getComponent = (props = {}): React.ReactElement => <CurrentDeviceSection {...defaultProps} {...props} />;
|
||||
|
||||
it("renders spinner while device is loading", () => {
|
||||
const { container } = render(getComponent({ device: undefined, isLoading: true }));
|
||||
expect(container.getElementsByClassName("mx_Spinner").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it("handles when device is falsy", async () => {
|
||||
const { container } = render(getComponent({ device: undefined }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders device and correct security card when device is verified", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders device and correct security card when device is unverified", () => {
|
||||
const { container } = render(getComponent({ device: alicesUnverifiedDevice }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("displays device details on main tile click", () => {
|
||||
const { getByTestId, container } = render(getComponent({ device: alicesUnverifiedDevice }));
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId(`device-tile-${alicesUnverifiedDevice.device_id}`));
|
||||
});
|
||||
|
||||
expect(container.getElementsByClassName("mx_DeviceDetails").length).toBeTruthy();
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId(`device-tile-${alicesUnverifiedDevice.device_id}`));
|
||||
});
|
||||
|
||||
// device details are hidden
|
||||
expect(container.getElementsByClassName("mx_DeviceDetails").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it("displays device details on toggle click", () => {
|
||||
const { container, getByTestId } = render(getComponent({ device: alicesUnverifiedDevice }));
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId("current-session-toggle-details"));
|
||||
});
|
||||
|
||||
expect(container.getElementsByClassName("mx_DeviceDetails")).toMatchSnapshot();
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId("current-session-toggle-details"));
|
||||
});
|
||||
|
||||
// device details are hidden
|
||||
expect(container.getElementsByClassName("mx_DeviceDetails").length).toBeFalsy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { fireEvent, render, RenderResult } from "jest-matrix-react";
|
||||
|
||||
import { DeviceDetailHeading } from "../../../../../src/components/views/settings/devices/DeviceDetailHeading";
|
||||
import { flushPromisesWithFakeTimers } from "../../../../test-utils";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe("<DeviceDetailHeading />", () => {
|
||||
const device = {
|
||||
device_id: "123",
|
||||
display_name: "My device",
|
||||
isVerified: true,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const defaultProps = {
|
||||
device,
|
||||
saveDeviceName: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) => <DeviceDetailHeading {...defaultProps} {...props} />;
|
||||
|
||||
const setInputValue = (getByTestId: RenderResult["getByTestId"], value: string) => {
|
||||
const input = getByTestId("device-rename-input");
|
||||
|
||||
fireEvent.change(input, { target: { value } });
|
||||
};
|
||||
|
||||
it("renders device name", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect({ container }).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders device id as fallback when device has no display name", () => {
|
||||
const { getByText } = render(
|
||||
getComponent({
|
||||
device: { ...device, display_name: undefined },
|
||||
}),
|
||||
);
|
||||
expect(getByText(device.device_id)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("displays name edit form on rename button click", () => {
|
||||
const { getByTestId, container } = render(getComponent());
|
||||
|
||||
fireEvent.click(getByTestId("device-heading-rename-cta"));
|
||||
|
||||
expect({ container }).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("cancelling edit switches back to original display", () => {
|
||||
const { getByTestId, container } = render(getComponent());
|
||||
|
||||
// start editing
|
||||
fireEvent.click(getByTestId("device-heading-rename-cta"));
|
||||
|
||||
// stop editing
|
||||
fireEvent.click(getByTestId("device-rename-cancel-cta"));
|
||||
|
||||
expect(container.getElementsByClassName("mx_DeviceDetailHeading").length).toBe(1);
|
||||
});
|
||||
|
||||
it("clicking submit updates device name with edited value", () => {
|
||||
const saveDeviceName = jest.fn();
|
||||
const { getByTestId } = render(getComponent({ saveDeviceName }));
|
||||
|
||||
// start editing
|
||||
fireEvent.click(getByTestId("device-heading-rename-cta"));
|
||||
|
||||
setInputValue(getByTestId, "new device name");
|
||||
|
||||
fireEvent.click(getByTestId("device-rename-submit-cta"));
|
||||
|
||||
expect(saveDeviceName).toHaveBeenCalledWith("new device name");
|
||||
});
|
||||
|
||||
it("disables form while device name is saving", () => {
|
||||
const { getByTestId, container } = render(getComponent());
|
||||
|
||||
// start editing
|
||||
fireEvent.click(getByTestId("device-heading-rename-cta"));
|
||||
|
||||
setInputValue(getByTestId, "new device name");
|
||||
|
||||
fireEvent.click(getByTestId("device-rename-submit-cta"));
|
||||
|
||||
// buttons disabled
|
||||
expect(getByTestId("device-rename-cancel-cta").getAttribute("aria-disabled")).toEqual("true");
|
||||
expect(getByTestId("device-rename-submit-cta").getAttribute("aria-disabled")).toEqual("true");
|
||||
|
||||
expect(container.getElementsByClassName("mx_Spinner").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it("toggles out of editing mode when device name is saved successfully", async () => {
|
||||
const { getByTestId, findByTestId } = render(getComponent());
|
||||
|
||||
// start editing
|
||||
fireEvent.click(getByTestId("device-heading-rename-cta"));
|
||||
setInputValue(getByTestId, "new device name");
|
||||
fireEvent.click(getByTestId("device-rename-submit-cta"));
|
||||
|
||||
await flushPromisesWithFakeTimers();
|
||||
|
||||
// read mode displayed
|
||||
await expect(findByTestId("device-detail-heading")).resolves.toBeTruthy();
|
||||
});
|
||||
|
||||
it("displays error when device name fails to save", async () => {
|
||||
const saveDeviceName = jest.fn().mockRejectedValueOnce("oups").mockResolvedValue({});
|
||||
const { getByTestId, queryByText, findByText, container } = render(getComponent({ saveDeviceName }));
|
||||
|
||||
// start editing
|
||||
fireEvent.click(getByTestId("device-heading-rename-cta"));
|
||||
setInputValue(getByTestId, "new device name");
|
||||
fireEvent.click(getByTestId("device-rename-submit-cta"));
|
||||
|
||||
// flush promise
|
||||
await flushPromisesWithFakeTimers();
|
||||
// then tick for render
|
||||
await flushPromisesWithFakeTimers();
|
||||
|
||||
// error message displayed
|
||||
await expect(findByText("Failed to set session name")).resolves.toBeTruthy();
|
||||
// spinner removed
|
||||
expect(container.getElementsByClassName("mx_Spinner").length).toBeFalsy();
|
||||
|
||||
// try again
|
||||
fireEvent.click(getByTestId("device-rename-submit-cta"));
|
||||
|
||||
// error message cleared
|
||||
expect(queryByText("Failed to set display name")).toBeFalsy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { ComponentProps } from "react";
|
||||
import { fireEvent, render } from "jest-matrix-react";
|
||||
import { PUSHER_ENABLED } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import DeviceDetails from "../../../../../src/components/views/settings/devices/DeviceDetails";
|
||||
import { mkPusher } from "../../../../test-utils/test-utils";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
describe("<DeviceDetails />", () => {
|
||||
const baseDevice = {
|
||||
device_id: "my-device",
|
||||
isVerified: false,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const defaultProps: ComponentProps<typeof DeviceDetails> = {
|
||||
device: baseDevice,
|
||||
isSigningOut: false,
|
||||
onSignOutDevice: jest.fn(),
|
||||
saveDeviceName: jest.fn(),
|
||||
setPushNotifications: jest.fn(),
|
||||
supportsMSC3881: true,
|
||||
};
|
||||
|
||||
const getComponent = (props = {}) => <DeviceDetails {...defaultProps} {...props} />;
|
||||
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
jest.useFakeTimers();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.setSystemTime(now);
|
||||
});
|
||||
|
||||
it("renders device without metadata", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders device with metadata", () => {
|
||||
const device = {
|
||||
...baseDevice,
|
||||
display_name: "My Device",
|
||||
last_seen_ip: "123.456.789",
|
||||
last_seen_ts: now - 60000000,
|
||||
appName: "Element Web",
|
||||
client: "Firefox 100",
|
||||
deviceModel: "Iphone X",
|
||||
deviceOperatingSystem: "Windows 95",
|
||||
};
|
||||
const { container } = render(getComponent({ device }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders a verified device", () => {
|
||||
const device = {
|
||||
...baseDevice,
|
||||
isVerified: true,
|
||||
};
|
||||
const { container } = render(getComponent({ device }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("disables sign out button while sign out is pending", () => {
|
||||
const device = {
|
||||
...baseDevice,
|
||||
};
|
||||
const { getByTestId } = render(getComponent({ device, isSigningOut: true }));
|
||||
expect(getByTestId("device-detail-sign-out-cta").getAttribute("aria-disabled")).toEqual("true");
|
||||
});
|
||||
|
||||
it("renders the push notification section when a pusher exists", () => {
|
||||
const device = {
|
||||
...baseDevice,
|
||||
};
|
||||
const pusher = mkPusher({
|
||||
device_id: device.device_id,
|
||||
});
|
||||
|
||||
const { getByTestId } = render(
|
||||
getComponent({
|
||||
device,
|
||||
pusher,
|
||||
isSigningOut: true,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(getByTestId("device-detail-push-notification")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("hides the push notification section when no pusher", () => {
|
||||
const device = {
|
||||
...baseDevice,
|
||||
};
|
||||
|
||||
const { getByTestId } = render(
|
||||
getComponent({
|
||||
device,
|
||||
pusher: null,
|
||||
isSigningOut: true,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(() => getByTestId("device-detail-push-notification")).toThrow();
|
||||
});
|
||||
|
||||
it("disables the checkbox when there is no server support", () => {
|
||||
const device = {
|
||||
...baseDevice,
|
||||
};
|
||||
const pusher = mkPusher({
|
||||
device_id: device.device_id,
|
||||
[PUSHER_ENABLED.name]: false,
|
||||
});
|
||||
|
||||
const { getByTestId } = render(
|
||||
getComponent({
|
||||
device,
|
||||
pusher,
|
||||
isSigningOut: true,
|
||||
supportsMSC3881: false,
|
||||
}),
|
||||
);
|
||||
|
||||
const checkbox = getByTestId("device-detail-push-notification-checkbox");
|
||||
|
||||
expect(checkbox.getAttribute("aria-disabled")).toEqual("true");
|
||||
expect(checkbox.getAttribute("aria-checked")).toEqual("false");
|
||||
});
|
||||
|
||||
it("changes the pusher status when clicked", () => {
|
||||
const device = {
|
||||
...baseDevice,
|
||||
};
|
||||
|
||||
const enabled = false;
|
||||
|
||||
const pusher = mkPusher({
|
||||
device_id: device.device_id,
|
||||
[PUSHER_ENABLED.name]: enabled,
|
||||
});
|
||||
|
||||
const { getByTestId } = render(
|
||||
getComponent({
|
||||
device,
|
||||
pusher,
|
||||
isSigningOut: true,
|
||||
}),
|
||||
);
|
||||
|
||||
const checkbox = getByTestId("device-detail-push-notification-checkbox");
|
||||
|
||||
fireEvent.click(checkbox);
|
||||
|
||||
expect(defaultProps.setPushNotifications).toHaveBeenCalledWith(device.device_id, !enabled);
|
||||
});
|
||||
|
||||
it("changes the local notifications settings status when clicked", () => {
|
||||
const device = {
|
||||
...baseDevice,
|
||||
};
|
||||
|
||||
const enabled = false;
|
||||
|
||||
const { getByTestId } = render(
|
||||
getComponent({
|
||||
device,
|
||||
localNotificationSettings: {
|
||||
is_silenced: !enabled,
|
||||
},
|
||||
isSigningOut: true,
|
||||
}),
|
||||
);
|
||||
|
||||
const checkbox = getByTestId("device-detail-push-notification-checkbox");
|
||||
fireEvent.click(checkbox);
|
||||
|
||||
expect(defaultProps.setPushNotifications).toHaveBeenCalledWith(device.device_id, !enabled);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "jest-matrix-react";
|
||||
|
||||
import { DeviceExpandDetailsButton } from "../../../../../src/components/views/settings/devices/DeviceExpandDetailsButton";
|
||||
|
||||
describe("<DeviceExpandDetailsButton />", () => {
|
||||
const defaultProps = {
|
||||
isExpanded: false,
|
||||
onClick: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) => <DeviceExpandDetailsButton {...defaultProps} {...props} />;
|
||||
|
||||
it("renders when not expanded", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect({ container }).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders when expanded", () => {
|
||||
const { container } = render(getComponent({ isExpanded: true }));
|
||||
expect({ container }).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls onClick", () => {
|
||||
const onClick = jest.fn();
|
||||
const { getByTestId } = render(getComponent({ "data-testid": "test", onClick }));
|
||||
fireEvent.click(getByTestId("test"));
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 } from "jest-matrix-react";
|
||||
import React from "react";
|
||||
|
||||
import DeviceSecurityCard from "../../../../../src/components/views/settings/devices/DeviceSecurityCard";
|
||||
import { DeviceSecurityVariation } from "../../../../../src/components/views/settings/devices/types";
|
||||
|
||||
describe("<DeviceSecurityCard />", () => {
|
||||
const defaultProps = {
|
||||
variation: DeviceSecurityVariation.Verified,
|
||||
heading: "Verified session",
|
||||
description: "nice",
|
||||
};
|
||||
const getComponent = (props = {}): React.ReactElement => <DeviceSecurityCard {...defaultProps} {...props} />;
|
||||
|
||||
it("renders basic card", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders with children", () => {
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
children: <div>hey</div>,
|
||||
variation: DeviceSecurityVariation.Unverified,
|
||||
}),
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { render } from "jest-matrix-react";
|
||||
import { IMyDevice } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import DeviceTile from "../../../../../src/components/views/settings/devices/DeviceTile";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
describe("<DeviceTile />", () => {
|
||||
const defaultProps = {
|
||||
device: {
|
||||
device_id: "123",
|
||||
isVerified: false,
|
||||
deviceType: DeviceType.Unknown,
|
||||
},
|
||||
};
|
||||
const getComponent = (props = {}) => <DeviceTile {...defaultProps} {...props} />;
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.setSystemTime(now);
|
||||
});
|
||||
|
||||
it("renders a device with no metadata", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("applies interactive class when tile has click handler", () => {
|
||||
const onClick = jest.fn();
|
||||
const { getByTestId } = render(getComponent({ onClick }));
|
||||
expect(getByTestId("device-tile-123").className.includes("mx_DeviceTile_interactive")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a verified device with no metadata", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders display name with a tooltip", () => {
|
||||
const device: IMyDevice = {
|
||||
device_id: "123",
|
||||
display_name: "My device",
|
||||
};
|
||||
const { container } = render(getComponent({ device }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders last seen ip metadata", () => {
|
||||
const device: IMyDevice = {
|
||||
device_id: "123",
|
||||
display_name: "My device",
|
||||
last_seen_ip: "1.2.3.4",
|
||||
};
|
||||
const { getByTestId } = render(getComponent({ device }));
|
||||
expect(getByTestId("device-metadata-lastSeenIp").textContent).toEqual(device.last_seen_ip);
|
||||
});
|
||||
|
||||
it("separates metadata with a dot", () => {
|
||||
const device: IMyDevice = {
|
||||
device_id: "123",
|
||||
last_seen_ip: "1.2.3.4",
|
||||
last_seen_ts: now - 60000,
|
||||
};
|
||||
const { container } = render(getComponent({ device }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("Last activity", () => {
|
||||
const MS_DAY = 24 * 60 * 60 * 1000;
|
||||
it("renders with day of week and time when last activity is less than 6 days ago", () => {
|
||||
const device: IMyDevice = {
|
||||
device_id: "123",
|
||||
last_seen_ip: "1.2.3.4",
|
||||
last_seen_ts: now - MS_DAY * 3,
|
||||
};
|
||||
const { getByTestId } = render(getComponent({ device }));
|
||||
expect(getByTestId("device-metadata-lastActivity").textContent).toEqual("Last activity Fri 15:14");
|
||||
});
|
||||
|
||||
it("renders with month and date when last activity is more than 6 days ago", () => {
|
||||
const device: IMyDevice = {
|
||||
device_id: "123",
|
||||
last_seen_ip: "1.2.3.4",
|
||||
last_seen_ts: now - MS_DAY * 8,
|
||||
};
|
||||
const { getByTestId } = render(getComponent({ device }));
|
||||
expect(getByTestId("device-metadata-lastActivity").textContent).toEqual("Last activity Mar 6");
|
||||
});
|
||||
|
||||
it("renders with month, date, year when activity is in a different calendar year", () => {
|
||||
const device: IMyDevice = {
|
||||
device_id: "123",
|
||||
last_seen_ip: "1.2.3.4",
|
||||
last_seen_ts: new Date("2021-12-29").getTime(),
|
||||
};
|
||||
const { getByTestId } = render(getComponent({ device }));
|
||||
expect(getByTestId("device-metadata-lastActivity").textContent).toEqual("Last activity Dec 29, 2021");
|
||||
});
|
||||
|
||||
it("renders with inactive notice when last activity was more than 90 days ago", () => {
|
||||
const device: IMyDevice = {
|
||||
device_id: "123",
|
||||
last_seen_ip: "1.2.3.4",
|
||||
last_seen_ts: now - MS_DAY * 100,
|
||||
};
|
||||
const { getByTestId, queryByTestId } = render(getComponent({ device }));
|
||||
expect(getByTestId("device-metadata-inactive").textContent).toEqual("Inactive for 90+ days (Dec 4, 2021)");
|
||||
// last activity and verification not shown when inactive
|
||||
expect(queryByTestId("device-metadata-lastActivity")).toBeFalsy();
|
||||
expect(queryByTestId("device-metadata-verificationStatus")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 } from "jest-matrix-react";
|
||||
import React from "react";
|
||||
|
||||
import { DeviceTypeIcon } from "../../../../../src/components/views/settings/devices/DeviceTypeIcon";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
describe("<DeviceTypeIcon />", () => {
|
||||
const defaultProps = {
|
||||
isVerified: false,
|
||||
isSelected: false,
|
||||
};
|
||||
const getComponent = (props = {}) => <DeviceTypeIcon {...defaultProps} {...props} />;
|
||||
|
||||
it("renders an unverified device", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders a verified device", () => {
|
||||
const { container } = render(getComponent({ isVerified: true }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders correctly when selected", () => {
|
||||
const { container } = render(getComponent({ isSelected: true }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders an unknown device icon when no device type given", () => {
|
||||
const { getByLabelText } = render(getComponent());
|
||||
expect(getByLabelText("Unknown session type")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a desktop device type", () => {
|
||||
const deviceType = DeviceType.Desktop;
|
||||
const { getByLabelText } = render(getComponent({ deviceType }));
|
||||
expect(getByLabelText("Desktop session")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a web device type", () => {
|
||||
const deviceType = DeviceType.Web;
|
||||
const { getByLabelText } = render(getComponent({ deviceType }));
|
||||
expect(getByLabelText("Web session")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a mobile device type", () => {
|
||||
const deviceType = DeviceType.Mobile;
|
||||
const { getByLabelText } = render(getComponent({ deviceType }));
|
||||
expect(getByLabelText("Mobile session")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders an unknown device type", () => {
|
||||
const deviceType = DeviceType.Unknown;
|
||||
const { getByLabelText } = render(getComponent({ deviceType }));
|
||||
expect(getByLabelText("Unknown session type")).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 } from "jest-matrix-react";
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
DeviceVerificationStatusCard,
|
||||
DeviceVerificationStatusCardProps,
|
||||
} from "../../../../../src/components/views/settings/devices/DeviceVerificationStatusCard";
|
||||
import { ExtendedDevice } from "../../../../../src/components/views/settings/devices/types";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
describe("<DeviceVerificationStatusCard />", () => {
|
||||
const deviceId = "test-device";
|
||||
const unverifiedDevice: ExtendedDevice = {
|
||||
device_id: deviceId,
|
||||
isVerified: false,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const verifiedDevice: ExtendedDevice = {
|
||||
...unverifiedDevice,
|
||||
isVerified: true,
|
||||
};
|
||||
const unverifiableDevice: ExtendedDevice = {
|
||||
...unverifiedDevice,
|
||||
isVerified: null,
|
||||
};
|
||||
const defaultProps = {
|
||||
device: unverifiedDevice,
|
||||
onVerifyDevice: jest.fn(),
|
||||
};
|
||||
const getComponent = (props: Partial<DeviceVerificationStatusCardProps> = {}) => (
|
||||
<DeviceVerificationStatusCard {...defaultProps} {...props} />
|
||||
);
|
||||
|
||||
const verifyButtonTestId = `verification-status-button-${deviceId}`;
|
||||
|
||||
describe("for the current device", () => {
|
||||
// current device uses different copy
|
||||
it("renders an unverified device", () => {
|
||||
const { getByText } = render(getComponent({ isCurrentDevice: true }));
|
||||
expect(getByText("Verify your current session for enhanced secure messaging.")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders an unverifiable device", () => {
|
||||
const { getByText } = render(
|
||||
getComponent({
|
||||
device: unverifiableDevice,
|
||||
isCurrentDevice: true,
|
||||
}),
|
||||
);
|
||||
expect(getByText("This session doesn't support encryption and thus can't be verified.")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a verified device", () => {
|
||||
const { getByText } = render(
|
||||
getComponent({
|
||||
device: verifiedDevice,
|
||||
isCurrentDevice: true,
|
||||
}),
|
||||
);
|
||||
expect(getByText("Your current session is ready for secure messaging.")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it("renders an unverified device", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders an unverifiable device", () => {
|
||||
const { container, queryByTestId } = render(getComponent({ device: unverifiableDevice }));
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(queryByTestId(verifyButtonTestId)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("renders a verified device", () => {
|
||||
const { container, queryByTestId } = render(getComponent({ device: verifiedDevice }));
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(queryByTestId(verifyButtonTestId)).toBeFalsy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { ComponentProps } from "react";
|
||||
import { act, fireEvent, render } from "jest-matrix-react";
|
||||
|
||||
import { FilteredDeviceList } from "../../../../../src/components/views/settings/devices/FilteredDeviceList";
|
||||
import { DeviceSecurityVariation } from "../../../../../src/components/views/settings/devices/types";
|
||||
import { flushPromises, mockPlatformPeg } from "../../../../test-utils";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
mockPlatformPeg();
|
||||
|
||||
const MS_DAY = 86400000;
|
||||
describe("<FilteredDeviceList />", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
const newDevice = {
|
||||
device_id: "new",
|
||||
last_seen_ts: Date.now() - 500,
|
||||
last_seen_ip: "123.456.789",
|
||||
display_name: "My Device",
|
||||
isVerified: true,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const unverifiedNoMetadata = {
|
||||
device_id: "unverified-no-metadata",
|
||||
isVerified: false,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const verifiedNoMetadata = {
|
||||
device_id: "verified-no-metadata",
|
||||
isVerified: true,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const hundredDaysOld = {
|
||||
device_id: "100-days-old",
|
||||
isVerified: true,
|
||||
last_seen_ts: Date.now() - MS_DAY * 100,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const hundredDaysOldUnverified = {
|
||||
device_id: "unverified-100-days-old",
|
||||
isVerified: false,
|
||||
last_seen_ts: Date.now() - MS_DAY * 100,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const defaultProps: ComponentProps<typeof FilteredDeviceList> = {
|
||||
onFilterChange: jest.fn(),
|
||||
onDeviceExpandToggle: jest.fn(),
|
||||
onSignOutDevices: jest.fn(),
|
||||
saveDeviceName: jest.fn(),
|
||||
setPushNotifications: jest.fn(),
|
||||
setSelectedDeviceIds: jest.fn(),
|
||||
localNotificationSettings: new Map(),
|
||||
expandedDeviceIds: [],
|
||||
signingOutDeviceIds: [],
|
||||
selectedDeviceIds: [],
|
||||
devices: {
|
||||
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
|
||||
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
|
||||
[newDevice.device_id]: newDevice,
|
||||
[hundredDaysOld.device_id]: hundredDaysOld,
|
||||
[hundredDaysOldUnverified.device_id]: hundredDaysOldUnverified,
|
||||
},
|
||||
pushers: [],
|
||||
supportsMSC3881: true,
|
||||
};
|
||||
|
||||
const getComponent = (props = {}) => <FilteredDeviceList {...defaultProps} {...props} />;
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(global.Date, "now").mockRestore();
|
||||
});
|
||||
|
||||
it("renders devices in correct order", () => {
|
||||
const { container } = render(getComponent());
|
||||
const tiles = container.querySelectorAll(".mx_DeviceTile");
|
||||
expect(tiles[0].getAttribute("data-testid")).toEqual(`device-tile-${newDevice.device_id}`);
|
||||
expect(tiles[1].getAttribute("data-testid")).toEqual(`device-tile-${hundredDaysOld.device_id}`);
|
||||
expect(tiles[2].getAttribute("data-testid")).toEqual(`device-tile-${hundredDaysOldUnverified.device_id}`);
|
||||
expect(tiles[3].getAttribute("data-testid")).toEqual(`device-tile-${unverifiedNoMetadata.device_id}`);
|
||||
expect(tiles[4].getAttribute("data-testid")).toEqual(`device-tile-${verifiedNoMetadata.device_id}`);
|
||||
});
|
||||
|
||||
it("updates list order when devices change", () => {
|
||||
const updatedOldDevice = { ...hundredDaysOld, last_seen_ts: new Date().getTime() };
|
||||
const updatedDevices = {
|
||||
[hundredDaysOld.device_id]: updatedOldDevice,
|
||||
[newDevice.device_id]: newDevice,
|
||||
};
|
||||
const { container, rerender } = render(getComponent());
|
||||
|
||||
rerender(getComponent({ devices: updatedDevices }));
|
||||
|
||||
const tiles = container.querySelectorAll(".mx_DeviceTile");
|
||||
expect(tiles.length).toBe(2);
|
||||
expect(tiles[0].getAttribute("data-testid")).toEqual(`device-tile-${hundredDaysOld.device_id}`);
|
||||
expect(tiles[1].getAttribute("data-testid")).toEqual(`device-tile-${newDevice.device_id}`);
|
||||
});
|
||||
|
||||
it("displays no results message when there are no devices", () => {
|
||||
const { container } = render(getComponent({ devices: {} }));
|
||||
|
||||
expect(container.getElementsByClassName("mx_FilteredDeviceList_noResults")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("filtering", () => {
|
||||
const setFilter = async (container: HTMLElement, option: DeviceSecurityVariation | string) => {
|
||||
const dropdown = container.querySelector('[aria-label="Filter devices"]');
|
||||
|
||||
fireEvent.click(dropdown as Element);
|
||||
// tick to let dropdown render
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(container.querySelector(`#device-list-filter__${option}`) as Element);
|
||||
};
|
||||
|
||||
it("does not display filter description when filter is falsy", () => {
|
||||
const { container } = render(getComponent({ filter: undefined }));
|
||||
const tiles = container.querySelectorAll(".mx_DeviceTile");
|
||||
expect(container.getElementsByClassName("mx_FilteredDeviceList_securityCard").length).toBeFalsy();
|
||||
expect(tiles.length).toEqual(5);
|
||||
});
|
||||
|
||||
it("updates filter when prop changes", () => {
|
||||
const { container, rerender } = render(getComponent({ filter: DeviceSecurityVariation.Verified }));
|
||||
const tiles = container.querySelectorAll(".mx_DeviceTile");
|
||||
expect(tiles.length).toEqual(3);
|
||||
expect(tiles[0].getAttribute("data-testid")).toEqual(`device-tile-${newDevice.device_id}`);
|
||||
expect(tiles[1].getAttribute("data-testid")).toEqual(`device-tile-${hundredDaysOld.device_id}`);
|
||||
expect(tiles[2].getAttribute("data-testid")).toEqual(`device-tile-${verifiedNoMetadata.device_id}`);
|
||||
|
||||
rerender(getComponent({ filter: DeviceSecurityVariation.Inactive }));
|
||||
|
||||
const rerenderedTiles = container.querySelectorAll(".mx_DeviceTile");
|
||||
expect(rerenderedTiles.length).toEqual(2);
|
||||
expect(rerenderedTiles[0].getAttribute("data-testid")).toEqual(`device-tile-${hundredDaysOld.device_id}`);
|
||||
expect(rerenderedTiles[1].getAttribute("data-testid")).toEqual(
|
||||
`device-tile-${hundredDaysOldUnverified.device_id}`,
|
||||
);
|
||||
});
|
||||
|
||||
it("calls onFilterChange handler", async () => {
|
||||
const onFilterChange = jest.fn();
|
||||
const { container } = render(getComponent({ onFilterChange }));
|
||||
await setFilter(container, DeviceSecurityVariation.Verified);
|
||||
|
||||
expect(onFilterChange).toHaveBeenCalledWith(DeviceSecurityVariation.Verified);
|
||||
});
|
||||
|
||||
it("calls onFilterChange handler correctly when setting filter to All", async () => {
|
||||
const onFilterChange = jest.fn();
|
||||
const { container } = render(getComponent({ onFilterChange, filter: DeviceSecurityVariation.Verified }));
|
||||
await setFilter(container, "ALL");
|
||||
|
||||
// filter is cleared
|
||||
expect(onFilterChange).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[DeviceSecurityVariation.Verified, [newDevice, hundredDaysOld, verifiedNoMetadata]],
|
||||
[DeviceSecurityVariation.Unverified, [hundredDaysOldUnverified, unverifiedNoMetadata]],
|
||||
[DeviceSecurityVariation.Inactive, [hundredDaysOld, hundredDaysOldUnverified]],
|
||||
])("filters correctly for %s", (filter, expectedDevices) => {
|
||||
const { container } = render(getComponent({ filter }));
|
||||
expect(container.getElementsByClassName("mx_FilteredDeviceList_securityCard")).toMatchSnapshot();
|
||||
const tileDeviceIds = [...container.querySelectorAll(".mx_DeviceTile")].map((tile) =>
|
||||
tile.getAttribute("data-testid"),
|
||||
);
|
||||
expect(tileDeviceIds).toEqual(expectedDevices.map((device) => `device-tile-${device.device_id}`));
|
||||
});
|
||||
|
||||
it.each([
|
||||
[DeviceSecurityVariation.Verified],
|
||||
[DeviceSecurityVariation.Unverified],
|
||||
[DeviceSecurityVariation.Inactive],
|
||||
])("renders no results correctly for %s", (filter) => {
|
||||
const { container } = render(getComponent({ filter, devices: {} }));
|
||||
expect(container.getElementsByClassName("mx_FilteredDeviceList_securityCard").length).toBeFalsy();
|
||||
expect(container.getElementsByClassName("mx_FilteredDeviceList_noResults")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("clears filter from no results message", () => {
|
||||
const onFilterChange = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
getComponent({
|
||||
onFilterChange,
|
||||
filter: DeviceSecurityVariation.Verified,
|
||||
devices: {
|
||||
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
|
||||
},
|
||||
}),
|
||||
);
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId("devices-clear-filter-btn"));
|
||||
});
|
||||
|
||||
expect(onFilterChange).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("device details", () => {
|
||||
it("renders expanded devices with device details", () => {
|
||||
const expandedDeviceIds = [newDevice.device_id, hundredDaysOld.device_id];
|
||||
const { container, getByTestId } = render(getComponent({ expandedDeviceIds }));
|
||||
expect(container.getElementsByClassName("mx_DeviceDetails").length).toBeTruthy();
|
||||
expect(getByTestId(`device-detail-${newDevice.device_id}`)).toBeTruthy();
|
||||
expect(getByTestId(`device-detail-${hundredDaysOld.device_id}`)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("clicking toggle calls onDeviceExpandToggle", () => {
|
||||
const onDeviceExpandToggle = jest.fn();
|
||||
const { getByTestId } = render(getComponent({ onDeviceExpandToggle }));
|
||||
|
||||
act(() => {
|
||||
const tile = getByTestId(`device-tile-${hundredDaysOld.device_id}`);
|
||||
const toggle = tile.querySelector('[aria-label="Show details"]');
|
||||
fireEvent.click(toggle as Element);
|
||||
});
|
||||
|
||||
expect(onDeviceExpandToggle).toHaveBeenCalledWith(hundredDaysOld.device_id);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { fireEvent, render } from "jest-matrix-react";
|
||||
import React from "react";
|
||||
|
||||
import FilteredDeviceListHeader from "../../../../../src/components/views/settings/devices/FilteredDeviceListHeader";
|
||||
|
||||
describe("<FilteredDeviceListHeader />", () => {
|
||||
const defaultProps = {
|
||||
selectedDeviceCount: 0,
|
||||
isAllSelected: false,
|
||||
toggleSelectAll: jest.fn(),
|
||||
children: <div>test</div>,
|
||||
["data-testid"]: "test123",
|
||||
};
|
||||
const getComponent = (props = {}) => <FilteredDeviceListHeader {...defaultProps} {...props} />;
|
||||
|
||||
it("renders correctly when no devices are selected", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders correctly when all devices are selected", () => {
|
||||
const { container } = render(getComponent({ isAllSelected: true }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders correctly when some devices are selected", () => {
|
||||
const { getByText } = render(getComponent({ selectedDeviceCount: 2 }));
|
||||
expect(getByText("2 sessions selected")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("clicking checkbox toggles selection", () => {
|
||||
const toggleSelectAll = jest.fn();
|
||||
const { getByTestId } = render(getComponent({ toggleSelectAll }));
|
||||
fireEvent.click(getByTestId("device-select-all-checkbox"));
|
||||
|
||||
expect(toggleSelectAll).toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { cleanup, render, waitFor } from "jest-matrix-react";
|
||||
import { MockedObject, mocked } from "jest-mock";
|
||||
import React from "react";
|
||||
import {
|
||||
MSC3906Rendezvous,
|
||||
LegacyRendezvousFailureReason,
|
||||
ClientRendezvousFailureReason,
|
||||
MSC4108SignInWithQR,
|
||||
MSC4108FailureReason,
|
||||
} from "matrix-js-sdk/src/rendezvous";
|
||||
import { HTTPError, LoginTokenPostResponse } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import LoginWithQR from "../../../../../src/components/views/auth/LoginWithQR";
|
||||
import { Click, Mode, Phase } from "../../../../../src/components/views/auth/LoginWithQR-types";
|
||||
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
jest.mock("matrix-js-sdk/src/rendezvous");
|
||||
jest.mock("matrix-js-sdk/src/rendezvous/transports");
|
||||
jest.mock("matrix-js-sdk/src/rendezvous/channels");
|
||||
|
||||
const mockedFlow = jest.fn();
|
||||
|
||||
jest.mock("../../../../../src/components/views/auth/LoginWithQRFlow", () => (props: Record<string, any>) => {
|
||||
mockedFlow(props);
|
||||
return <div />;
|
||||
});
|
||||
|
||||
function makeClient() {
|
||||
return mocked({
|
||||
getUser: jest.fn(),
|
||||
isGuest: jest.fn().mockReturnValue(false),
|
||||
isUserIgnored: jest.fn(),
|
||||
isCryptoEnabled: jest.fn(),
|
||||
getUserId: jest.fn(),
|
||||
on: jest.fn(),
|
||||
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
|
||||
isRoomEncrypted: jest.fn().mockReturnValue(false),
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue("mock-mxcUrlToHttp"),
|
||||
doesServerSupportUnstableFeature: jest.fn().mockReturnValue(true),
|
||||
removeListener: jest.fn(),
|
||||
requestLoginToken: jest.fn(),
|
||||
currentState: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
getClientWellKnown: jest.fn().mockReturnValue({}),
|
||||
getCrypto: jest.fn().mockReturnValue({}),
|
||||
crypto: {},
|
||||
} as unknown as MatrixClient);
|
||||
}
|
||||
|
||||
function unresolvedPromise<T>(): Promise<T> {
|
||||
return new Promise(() => {});
|
||||
}
|
||||
|
||||
describe("<LoginWithQR />", () => {
|
||||
let client!: MockedObject<MatrixClient>;
|
||||
const defaultProps = {
|
||||
legacy: true,
|
||||
mode: Mode.Show,
|
||||
onFinished: jest.fn(),
|
||||
};
|
||||
const mockConfirmationDigits = "mock-confirmation-digits";
|
||||
const mockRendezvousCode = "mock-rendezvous-code";
|
||||
const newDeviceId = "new-device-id";
|
||||
|
||||
beforeEach(() => {
|
||||
mockedFlow.mockReset();
|
||||
jest.resetAllMocks();
|
||||
client = makeClient();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
client = makeClient();
|
||||
jest.clearAllMocks();
|
||||
jest.useRealTimers();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
describe("MSC3906", () => {
|
||||
const getComponent = (props: { client: MatrixClient; onFinished?: () => void }) => (
|
||||
<React.StrictMode>
|
||||
<LoginWithQR {...defaultProps} {...props} />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "generateCode").mockResolvedValue();
|
||||
// @ts-ignore
|
||||
// workaround for https://github.com/facebook/jest/issues/9675
|
||||
MSC3906Rendezvous.prototype.code = mockRendezvousCode;
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "cancel").mockResolvedValue();
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "startAfterShowingCode").mockResolvedValue(mockConfirmationDigits);
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "declineLoginOnExistingDevice").mockResolvedValue();
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "approveLoginOnExistingDevice").mockResolvedValue(newDeviceId);
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "verifyNewDeviceOnExistingDevice").mockResolvedValue(undefined);
|
||||
client.requestLoginToken.mockResolvedValue({
|
||||
login_token: "token",
|
||||
expires_in_ms: 1000 * 1000,
|
||||
} as LoginTokenPostResponse); // we force the type here so that it works with versions of js-sdk that don't have r1 support yet
|
||||
});
|
||||
|
||||
test("no homeserver support", async () => {
|
||||
// simulate no support
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "generateCode").mockRejectedValue("");
|
||||
render(getComponent({ client }));
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.Error,
|
||||
failureReason: LegacyRendezvousFailureReason.HomeserverLacksSupport,
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("failed to connect", async () => {
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "startAfterShowingCode").mockRejectedValue("");
|
||||
render(getComponent({ client }));
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.Error,
|
||||
failureReason: ClientRendezvousFailureReason.Unknown,
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
expect(rendezvous.startAfterShowingCode).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("render QR then back", async () => {
|
||||
const onFinished = jest.fn();
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "startAfterShowingCode").mockReturnValue(unresolvedPromise());
|
||||
render(getComponent({ client, onFinished }));
|
||||
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.ShowingQR,
|
||||
}),
|
||||
),
|
||||
);
|
||||
// display QR code
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.ShowingQR,
|
||||
code: mockRendezvousCode,
|
||||
onClick: expect.any(Function),
|
||||
});
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
expect(rendezvous.startAfterShowingCode).toHaveBeenCalled();
|
||||
|
||||
// back
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Back);
|
||||
expect(onFinished).toHaveBeenCalledWith(false);
|
||||
expect(rendezvous.cancel).toHaveBeenCalledWith(LegacyRendezvousFailureReason.UserCancelled);
|
||||
});
|
||||
|
||||
test("render QR then decline", async () => {
|
||||
const onFinished = jest.fn();
|
||||
render(getComponent({ client, onFinished }));
|
||||
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.LegacyConnected,
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.LegacyConnected,
|
||||
confirmationDigits: mockConfirmationDigits,
|
||||
onClick: expect.any(Function),
|
||||
});
|
||||
|
||||
// decline
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Decline);
|
||||
expect(onFinished).toHaveBeenCalledWith(false);
|
||||
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
expect(rendezvous.startAfterShowingCode).toHaveBeenCalled();
|
||||
expect(rendezvous.declineLoginOnExistingDevice).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("approve - no crypto", async () => {
|
||||
(client as any).crypto = undefined;
|
||||
(client as any).getCrypto = () => undefined;
|
||||
const onFinished = jest.fn();
|
||||
render(getComponent({ client, onFinished }));
|
||||
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.LegacyConnected,
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.LegacyConnected,
|
||||
confirmationDigits: mockConfirmationDigits,
|
||||
onClick: expect.any(Function),
|
||||
});
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
expect(rendezvous.startAfterShowingCode).toHaveBeenCalled();
|
||||
|
||||
// approve
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Approve);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.WaitingForDevice,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith("token");
|
||||
|
||||
expect(onFinished).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
test("approve + verifying", async () => {
|
||||
const onFinished = jest.fn();
|
||||
jest.spyOn(MSC3906Rendezvous.prototype, "verifyNewDeviceOnExistingDevice").mockImplementation(() =>
|
||||
unresolvedPromise(),
|
||||
);
|
||||
render(getComponent({ client, onFinished }));
|
||||
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.LegacyConnected,
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.LegacyConnected,
|
||||
confirmationDigits: mockConfirmationDigits,
|
||||
onClick: expect.any(Function),
|
||||
});
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
expect(rendezvous.startAfterShowingCode).toHaveBeenCalled();
|
||||
|
||||
// approve
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
onClick(Click.Approve);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.Verifying,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith("token");
|
||||
expect(rendezvous.verifyNewDeviceOnExistingDevice).toHaveBeenCalled();
|
||||
// expect(onFinished).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
test("approve + verify", async () => {
|
||||
const onFinished = jest.fn();
|
||||
render(getComponent({ client, onFinished }));
|
||||
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.LegacyConnected,
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.LegacyConnected,
|
||||
confirmationDigits: mockConfirmationDigits,
|
||||
onClick: expect.any(Function),
|
||||
});
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
expect(rendezvous.startAfterShowingCode).toHaveBeenCalled();
|
||||
|
||||
// approve
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Approve);
|
||||
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith("token");
|
||||
expect(rendezvous.verifyNewDeviceOnExistingDevice).toHaveBeenCalled();
|
||||
expect(rendezvous.close).toHaveBeenCalled();
|
||||
expect(onFinished).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
test("approve - rate limited", async () => {
|
||||
mocked(client.requestLoginToken).mockRejectedValue(new HTTPError("rate limit reached", 429));
|
||||
const onFinished = jest.fn();
|
||||
render(getComponent({ client, onFinished }));
|
||||
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.LegacyConnected,
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.LegacyConnected,
|
||||
confirmationDigits: mockConfirmationDigits,
|
||||
onClick: expect.any(Function),
|
||||
});
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
expect(rendezvous.startAfterShowingCode).toHaveBeenCalled();
|
||||
|
||||
// approve
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Approve);
|
||||
|
||||
// the 429 error should be handled and mapped
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.Error,
|
||||
failureReason: "rate_limited",
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("MSC4108", () => {
|
||||
const getComponent = (props: { client: MatrixClient; onFinished?: () => void }) => (
|
||||
<React.StrictMode>
|
||||
<LoginWithQR {...defaultProps} {...props} legacy={false} />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
test("render QR then back", async () => {
|
||||
const onFinished = jest.fn();
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "negotiateProtocols").mockReturnValue(unresolvedPromise());
|
||||
render(getComponent({ client, onFinished }));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.ShowingQR,
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
|
||||
const rendezvous = mocked(MSC4108SignInWithQR).mock.instances[0];
|
||||
expect(rendezvous.generateCode).toHaveBeenCalled();
|
||||
expect(rendezvous.negotiateProtocols).toHaveBeenCalled();
|
||||
|
||||
// back
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Back);
|
||||
expect(onFinished).toHaveBeenCalledWith(false);
|
||||
expect(rendezvous.cancel).toHaveBeenCalledWith(LegacyRendezvousFailureReason.UserCancelled);
|
||||
});
|
||||
|
||||
test("failed to connect", async () => {
|
||||
render(getComponent({ client }));
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "negotiateProtocols").mockResolvedValue({});
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "deviceAuthorizationGrant").mockRejectedValue(
|
||||
new HTTPError("Internal Server Error", 500),
|
||||
);
|
||||
const fn = jest.spyOn(MSC4108SignInWithQR.prototype, "cancel");
|
||||
await waitFor(() => expect(fn).toHaveBeenLastCalledWith(ClientRendezvousFailureReason.Unknown));
|
||||
});
|
||||
|
||||
test("reciprocates login", async () => {
|
||||
jest.spyOn(global.window, "open");
|
||||
|
||||
render(getComponent({ client }));
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "negotiateProtocols").mockResolvedValue({});
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "deviceAuthorizationGrant").mockResolvedValue({
|
||||
verificationUri: "mock-verification-uri",
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.OutOfBandConfirmation,
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Approve);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.WaitingForDevice,
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
expect(global.window.open).toHaveBeenCalledWith("mock-verification-uri", "_blank");
|
||||
});
|
||||
|
||||
test("handles errors during reciprocation", async () => {
|
||||
render(getComponent({ client }));
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "negotiateProtocols").mockResolvedValue({});
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "deviceAuthorizationGrant").mockResolvedValue({});
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.OutOfBandConfirmation,
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "shareSecrets").mockRejectedValue(
|
||||
new HTTPError("Internal Server Error", 500),
|
||||
);
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Approve);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
phase: Phase.Error,
|
||||
failureReason: ClientRendezvousFailureReason.Unknown,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test("handles user cancelling during reciprocation", async () => {
|
||||
render(getComponent({ client }));
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "negotiateProtocols").mockResolvedValue({});
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "deviceAuthorizationGrant").mockResolvedValue({});
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "deviceAuthorizationGrant").mockResolvedValue({});
|
||||
await waitFor(() =>
|
||||
expect(mockedFlow).toHaveBeenLastCalledWith({
|
||||
phase: Phase.OutOfBandConfirmation,
|
||||
onClick: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
|
||||
jest.spyOn(MSC4108SignInWithQR.prototype, "cancel").mockResolvedValue();
|
||||
const onClick = mockedFlow.mock.calls[0][0].onClick;
|
||||
await onClick(Click.Cancel);
|
||||
|
||||
const rendezvous = mocked(MSC4108SignInWithQR).mock.instances[0];
|
||||
expect(rendezvous.cancel).toHaveBeenCalledWith(MSC4108FailureReason.UserCancelled);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { cleanup, fireEvent, render, screen, waitFor } from "jest-matrix-react";
|
||||
import React from "react";
|
||||
import {
|
||||
ClientRendezvousFailureReason,
|
||||
LegacyRendezvousFailureReason,
|
||||
MSC4108FailureReason,
|
||||
} from "matrix-js-sdk/src/rendezvous";
|
||||
|
||||
import LoginWithQRFlow from "../../../../../src/components/views/auth/LoginWithQRFlow";
|
||||
import { LoginWithQRFailureReason, FailureReason } from "../../../../../src/components/views/auth/LoginWithQR";
|
||||
import { Click, Phase } from "../../../../../src/components/views/auth/LoginWithQR-types";
|
||||
|
||||
describe("<LoginWithQRFlow />", () => {
|
||||
const onClick = jest.fn();
|
||||
|
||||
const defaultProps = {
|
||||
onClick,
|
||||
};
|
||||
|
||||
const getComponent = (props: {
|
||||
phase: Phase;
|
||||
onClick?: () => Promise<void>;
|
||||
failureReason?: FailureReason;
|
||||
code?: string;
|
||||
confirmationDigits?: string;
|
||||
}) => <LoginWithQRFlow {...defaultProps} {...props} />;
|
||||
|
||||
beforeEach(() => {});
|
||||
|
||||
afterEach(() => {
|
||||
onClick.mockReset();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it("renders spinner while loading", async () => {
|
||||
const { container } = render(getComponent({ phase: Phase.Loading }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders spinner whilst QR generating", async () => {
|
||||
const { container } = render(getComponent({ phase: Phase.ShowingQR }));
|
||||
expect(screen.getAllByTestId("cancel-button")).toHaveLength(1);
|
||||
expect(container).toMatchSnapshot();
|
||||
fireEvent.click(screen.getByTestId("cancel-button"));
|
||||
expect(onClick).toHaveBeenCalledWith(Click.Cancel, undefined);
|
||||
});
|
||||
|
||||
it("renders QR code", async () => {
|
||||
const { container } = render(getComponent({ phase: Phase.ShowingQR, code: "mock-code" }));
|
||||
// QR code is rendered async so we wait for it:
|
||||
await waitFor(() => screen.getAllByAltText("QR Code").length === 1);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders code when connected", async () => {
|
||||
const { container } = render(getComponent({ phase: Phase.LegacyConnected, confirmationDigits: "mock-digits" }));
|
||||
expect(screen.getAllByText("mock-digits")).toHaveLength(1);
|
||||
expect(screen.getAllByTestId("decline-login-button")).toHaveLength(1);
|
||||
expect(screen.getAllByTestId("approve-login-button")).toHaveLength(1);
|
||||
expect(container).toMatchSnapshot();
|
||||
fireEvent.click(screen.getByTestId("decline-login-button"));
|
||||
expect(onClick).toHaveBeenCalledWith(Click.Decline, undefined);
|
||||
fireEvent.click(screen.getByTestId("approve-login-button"));
|
||||
expect(onClick).toHaveBeenCalledWith(Click.Approve, undefined);
|
||||
});
|
||||
|
||||
it("renders spinner while signing in", async () => {
|
||||
const { container } = render(getComponent({ phase: Phase.WaitingForDevice }));
|
||||
expect(screen.getAllByTestId("cancel-button")).toHaveLength(1);
|
||||
expect(container).toMatchSnapshot();
|
||||
fireEvent.click(screen.getByTestId("cancel-button"));
|
||||
expect(onClick).toHaveBeenCalledWith(Click.Cancel, undefined);
|
||||
});
|
||||
|
||||
it("renders spinner while verifying", async () => {
|
||||
const { container } = render(getComponent({ phase: Phase.Verifying }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders check code confirmation", async () => {
|
||||
const { container } = render(getComponent({ phase: Phase.OutOfBandConfirmation }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
for (const failureReason of [
|
||||
...Object.values(LegacyRendezvousFailureReason),
|
||||
...Object.values(MSC4108FailureReason),
|
||||
...Object.values(LoginWithQRFailureReason),
|
||||
...Object.values(ClientRendezvousFailureReason),
|
||||
]) {
|
||||
it(`renders ${failureReason}`, async () => {
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
phase: Phase.Error,
|
||||
failureReason,
|
||||
}),
|
||||
);
|
||||
expect(screen.getAllByTestId("cancellation-message")).toHaveLength(1);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 } from "jest-matrix-react";
|
||||
import { mocked } from "jest-mock";
|
||||
import { IClientWellKnown, IServerVersions, MatrixClient, GET_LOGIN_TOKEN_CAPABILITY } from "matrix-js-sdk/src/matrix";
|
||||
import React from "react";
|
||||
import fetchMock from "fetch-mock-jest";
|
||||
|
||||
import LoginWithQRSection from "../../../../../src/components/views/settings/devices/LoginWithQRSection";
|
||||
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
|
||||
|
||||
function makeClient(wellKnown: IClientWellKnown) {
|
||||
const crypto = mocked({
|
||||
supportsSecretsForQrLogin: jest.fn().mockReturnValue(true),
|
||||
isCrossSigningReady: jest.fn().mockReturnValue(true),
|
||||
});
|
||||
|
||||
return mocked({
|
||||
getUser: jest.fn(),
|
||||
isGuest: jest.fn().mockReturnValue(false),
|
||||
isUserIgnored: jest.fn(),
|
||||
isCryptoEnabled: jest.fn(),
|
||||
getUserId: jest.fn(),
|
||||
on: jest.fn(),
|
||||
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
|
||||
isRoomEncrypted: jest.fn().mockReturnValue(false),
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue("mock-mxcUrlToHttp"),
|
||||
removeListener: jest.fn(),
|
||||
currentState: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
getClientWellKnown: jest.fn().mockReturnValue(wellKnown),
|
||||
getCrypto: jest.fn().mockReturnValue(crypto),
|
||||
} as unknown as MatrixClient);
|
||||
}
|
||||
|
||||
function makeVersions(unstableFeatures: Record<string, boolean>): IServerVersions {
|
||||
return {
|
||||
versions: [],
|
||||
unstable_features: unstableFeatures,
|
||||
};
|
||||
}
|
||||
|
||||
describe("<LoginWithQRSection />", () => {
|
||||
beforeAll(() => {
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(makeClient({}));
|
||||
});
|
||||
|
||||
describe("MSC3906", () => {
|
||||
const defaultProps = {
|
||||
onShowQr: () => {},
|
||||
versions: makeVersions({}),
|
||||
wellKnown: {},
|
||||
};
|
||||
|
||||
const getComponent = (props = {}) => <LoginWithQRSection {...defaultProps} {...props} />;
|
||||
|
||||
describe("should not render", () => {
|
||||
it("no support at all", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("only get_login_token enabled", async () => {
|
||||
const { container } = render(
|
||||
getComponent({ capabilities: { [GET_LOGIN_TOKEN_CAPABILITY.name]: { enabled: true } } }),
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("MSC3886 + get_login_token disabled", async () => {
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
versions: makeVersions({ "org.matrix.msc3886": true }),
|
||||
capabilities: { [GET_LOGIN_TOKEN_CAPABILITY.name]: { enabled: false } },
|
||||
}),
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("should render panel", () => {
|
||||
it("get_login_token + MSC3886", async () => {
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
versions: makeVersions({
|
||||
"org.matrix.msc3886": true,
|
||||
}),
|
||||
capabilities: {
|
||||
[GET_LOGIN_TOKEN_CAPABILITY.name]: { enabled: true },
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("get_login_token + .well-known", async () => {
|
||||
const wellKnown = {
|
||||
"io.element.rendezvous": {
|
||||
server: "https://rz.local",
|
||||
},
|
||||
};
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(makeClient(wellKnown));
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
versions: makeVersions({}),
|
||||
capabilities: { [GET_LOGIN_TOKEN_CAPABILITY.name]: { enabled: true } },
|
||||
wellKnown,
|
||||
}),
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("MSC4108", () => {
|
||||
describe("MSC4108", () => {
|
||||
const defaultProps = {
|
||||
onShowQr: () => {},
|
||||
versions: makeVersions({ "org.matrix.msc4108": true }),
|
||||
wellKnown: {},
|
||||
};
|
||||
|
||||
const getComponent = (props = {}) => <LoginWithQRSection {...defaultProps} {...props} />;
|
||||
|
||||
let client: MatrixClient;
|
||||
beforeEach(() => {
|
||||
client = makeClient({});
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(client);
|
||||
});
|
||||
|
||||
test("no homeserver support", async () => {
|
||||
const { container } = render(getComponent({ versions: makeVersions({ "org.matrix.msc4108": false }) }));
|
||||
expect(container.textContent).toContain("Not supported by your account provider");
|
||||
});
|
||||
|
||||
test("no support in crypto", async () => {
|
||||
client.getCrypto()!.exportSecretsBundle = undefined;
|
||||
const { container } = render(getComponent({ client }));
|
||||
expect(container.textContent).toContain("Not supported by your account provider");
|
||||
});
|
||||
|
||||
test("failed to connect", async () => {
|
||||
fetchMock.catch(500);
|
||||
const { container } = render(getComponent({ client }));
|
||||
expect(container.textContent).toContain("Not supported by your account provider");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { act, fireEvent, render } from "jest-matrix-react";
|
||||
|
||||
import SecurityRecommendations from "../../../../../src/components/views/settings/devices/SecurityRecommendations";
|
||||
import { DeviceSecurityVariation } from "../../../../../src/components/views/settings/devices/types";
|
||||
|
||||
const MS_DAY = 24 * 60 * 60 * 1000;
|
||||
describe("<SecurityRecommendations />", () => {
|
||||
const unverifiedNoMetadata = { device_id: "unverified-no-metadata", isVerified: false };
|
||||
const verifiedNoMetadata = { device_id: "verified-no-metadata", isVerified: true };
|
||||
const hundredDaysOld = { device_id: "100-days-old", isVerified: true, last_seen_ts: Date.now() - MS_DAY * 100 };
|
||||
const hundredDaysOldUnverified = {
|
||||
device_id: "unverified-100-days-old",
|
||||
isVerified: false,
|
||||
last_seen_ts: Date.now() - MS_DAY * 100,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
devices: {},
|
||||
goToFilteredList: jest.fn(),
|
||||
currentDeviceId: "abc123",
|
||||
};
|
||||
const getComponent = (props = {}) => <SecurityRecommendations {...defaultProps} {...props} />;
|
||||
|
||||
it("renders null when no devices", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container.firstChild).toBeNull();
|
||||
});
|
||||
|
||||
it("renders unverified devices section when user has unverified devices", () => {
|
||||
const devices = {
|
||||
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
|
||||
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
|
||||
[hundredDaysOldUnverified.device_id]: hundredDaysOldUnverified,
|
||||
};
|
||||
const { container } = render(getComponent({ devices }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not render unverified devices section when only the current device is unverified", () => {
|
||||
const devices = {
|
||||
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
|
||||
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
|
||||
};
|
||||
const { container } = render(getComponent({ devices, currentDeviceId: unverifiedNoMetadata.device_id }));
|
||||
// nothing to render
|
||||
expect(container.firstChild).toBeFalsy();
|
||||
});
|
||||
|
||||
it("renders inactive devices section when user has inactive devices", () => {
|
||||
const devices = {
|
||||
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
|
||||
[hundredDaysOldUnverified.device_id]: hundredDaysOldUnverified,
|
||||
};
|
||||
const { container } = render(getComponent({ devices }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders both cards when user has both unverified and inactive devices", () => {
|
||||
const devices = {
|
||||
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
|
||||
[hundredDaysOld.device_id]: hundredDaysOld,
|
||||
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
|
||||
};
|
||||
const { container } = render(getComponent({ devices }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("clicking view all unverified devices button works", () => {
|
||||
const goToFilteredList = jest.fn();
|
||||
const devices = {
|
||||
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
|
||||
[hundredDaysOld.device_id]: hundredDaysOld,
|
||||
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
|
||||
};
|
||||
const { getByTestId } = render(getComponent({ devices, goToFilteredList }));
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId("unverified-devices-cta"));
|
||||
});
|
||||
|
||||
expect(goToFilteredList).toHaveBeenCalledWith(DeviceSecurityVariation.Unverified);
|
||||
});
|
||||
|
||||
it("clicking view all inactive devices button works", () => {
|
||||
const goToFilteredList = jest.fn();
|
||||
const devices = {
|
||||
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
|
||||
[hundredDaysOld.device_id]: hundredDaysOld,
|
||||
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
|
||||
};
|
||||
const { getByTestId } = render(getComponent({ devices, goToFilteredList }));
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId("inactive-devices-cta"));
|
||||
});
|
||||
|
||||
expect(goToFilteredList).toHaveBeenCalledWith(DeviceSecurityVariation.Inactive);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { act, fireEvent, render } from "jest-matrix-react";
|
||||
import React from "react";
|
||||
|
||||
import SelectableDeviceTile from "../../../../../src/components/views/settings/devices/SelectableDeviceTile";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
describe("<SelectableDeviceTile />", () => {
|
||||
const device = {
|
||||
display_name: "My Device",
|
||||
device_id: "my-device",
|
||||
last_seen_ip: "123.456.789",
|
||||
isVerified: false,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const defaultProps = {
|
||||
onSelect: jest.fn(),
|
||||
onClick: jest.fn(),
|
||||
device,
|
||||
children: <div>test</div>,
|
||||
isSelected: false,
|
||||
};
|
||||
const getComponent = (props = {}) => <SelectableDeviceTile {...defaultProps} {...props} />;
|
||||
|
||||
it("renders unselected device tile with checkbox", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders selected tile", () => {
|
||||
const { container } = render(getComponent({ isSelected: true }));
|
||||
expect(container.querySelector(`#device-tile-checkbox-${device.device_id}`)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls onSelect on checkbox click", () => {
|
||||
const onSelect = jest.fn();
|
||||
const { container } = render(getComponent({ onSelect }));
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(container.querySelector(`#device-tile-checkbox-${device.device_id}`)!);
|
||||
});
|
||||
|
||||
expect(onSelect).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls onClick on device tile info click", () => {
|
||||
const onClick = jest.fn();
|
||||
const { getByText } = render(getComponent({ onClick }));
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByText(device.display_name));
|
||||
});
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not call onClick when clicking device tiles actions", () => {
|
||||
const onClick = jest.fn();
|
||||
const onDeviceActionClick = jest.fn();
|
||||
const children = (
|
||||
<button onClick={onDeviceActionClick} data-testid="device-action-button">
|
||||
test
|
||||
</button>
|
||||
);
|
||||
const { getByTestId } = render(getComponent({ onClick, children }));
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId("device-action-button"));
|
||||
});
|
||||
|
||||
// action click handler called
|
||||
expect(onDeviceActionClick).toHaveBeenCalled();
|
||||
// main click handler not called
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,447 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<CurrentDeviceSection /> displays device details on toggle click 1`] = `
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="mx_DeviceDetails mx_CurrentDeviceSection_deviceDetails"
|
||||
data-testid="device-detail-alices_device"
|
||||
>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceDetailHeading"
|
||||
data-testid="device-detail-heading"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
alices_device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_DeviceDetailHeading_renameCta mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="device-heading-rename-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Rename
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify your current session for enhanced secure messaging.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
data-testid="verification-status-button-alices_device"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Verify session
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceDetails_sectionHeading"
|
||||
>
|
||||
Session details
|
||||
</p>
|
||||
<table
|
||||
class="mx_DeviceDetails_metadataTable"
|
||||
data-testid="device-detail-metadata-session"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Session ID
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
alices_device
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_inline"
|
||||
data-testid="device-detail-sign-out-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="mx_DeviceDetails_signOutButtonContent"
|
||||
>
|
||||
Sign out of this session
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`<CurrentDeviceSection /> handles when device is falsy 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="current-session-section"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Current session
|
||||
</h3>
|
||||
<div
|
||||
aria-disabled="true"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Options"
|
||||
class="mx_AccessibleButton mx_AccessibleButton_disabled"
|
||||
data-testid="current-session-menu"
|
||||
disabled=""
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_KebabContextMenu_icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<CurrentDeviceSection /> renders device and correct security card when device is unverified 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="current-session-section"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Current session
|
||||
</h3>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Options"
|
||||
class="mx_AccessibleButton"
|
||||
data-testid="current-session-menu"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_KebabContextMenu_icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTile mx_DeviceTile_interactive"
|
||||
data-testid="device-tile-alices_device"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_info"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
alices_device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_DeviceTile_metadata"
|
||||
>
|
||||
<span
|
||||
data-testid="device-metadata-isVerified"
|
||||
>
|
||||
Unverified
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-deviceId"
|
||||
>
|
||||
alices_device
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_actions"
|
||||
>
|
||||
<div
|
||||
aria-label="Show details"
|
||||
class="mx_AccessibleButton mx_DeviceExpandDetailsButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_icon"
|
||||
data-testid="current-session-toggle-details"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceExpandDetailsButton_icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify your current session for enhanced secure messaging.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
data-testid="verification-status-button-alices_device"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Verify session
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<CurrentDeviceSection /> renders device and correct security card when device is verified 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="current-session-section"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Current session
|
||||
</h3>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Options"
|
||||
class="mx_AccessibleButton"
|
||||
data-testid="current-session-menu"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_KebabContextMenu_icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTile mx_DeviceTile_interactive"
|
||||
data-testid="device-tile-alices_device"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_info"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
alices_device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_DeviceTile_metadata"
|
||||
>
|
||||
<span
|
||||
data-testid="device-metadata-isVerified"
|
||||
>
|
||||
Unverified
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-deviceId"
|
||||
>
|
||||
alices_device
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_actions"
|
||||
>
|
||||
<div
|
||||
aria-label="Show details"
|
||||
class="mx_AccessibleButton mx_DeviceExpandDetailsButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_icon"
|
||||
data-testid="current-session-toggle-details"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceExpandDetailsButton_icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify your current session for enhanced secure messaging.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
data-testid="verification-status-button-alices_device"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Verify session
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,97 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DeviceDetailHeading /> displays name edit form on rename button click 1`] = `
|
||||
{
|
||||
"container": <div>
|
||||
<form
|
||||
aria-disabled="false"
|
||||
class="mx_DeviceDetailHeading_renameForm"
|
||||
method="post"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceDetailHeading_renameFormHeading"
|
||||
id="device-rename-123"
|
||||
>
|
||||
Rename session
|
||||
</p>
|
||||
<div>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_DeviceDetailHeading_renameFormInput"
|
||||
>
|
||||
<input
|
||||
aria-describedby="device-rename-description-123"
|
||||
aria-labelledby="device-rename-123"
|
||||
autocomplete="off"
|
||||
data-testid="device-rename-input"
|
||||
id="mx_Field_1"
|
||||
maxlength="100"
|
||||
type="text"
|
||||
value="My device"
|
||||
/>
|
||||
<label
|
||||
for="mx_Field_1"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="mx_Caption"
|
||||
id="device-rename-description-123"
|
||||
>
|
||||
Please be aware that session names are also visible to people you communicate with.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceDetailHeading_renameFormButtons"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
data-testid="device-rename-submit-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Save
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary"
|
||||
data-testid="device-rename-cancel-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Cancel
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`<DeviceDetailHeading /> renders device name 1`] = `
|
||||
{
|
||||
"container": <div>
|
||||
<div
|
||||
class="mx_DeviceDetailHeading"
|
||||
data-testid="device-detail-heading"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
My device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_DeviceDetailHeading_renameCta mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="device-heading-rename-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Rename
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,428 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DeviceDetails /> renders a verified device 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceDetails"
|
||||
data-testid="device-detail-my-device"
|
||||
>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceDetailHeading"
|
||||
data-testid="device-detail-heading"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
my-device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_DeviceDetailHeading_renameCta mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="device-heading-rename-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Rename
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Verified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Verified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Your current session is ready for secure messaging.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceDetails_sectionHeading"
|
||||
>
|
||||
Session details
|
||||
</p>
|
||||
<table
|
||||
class="mx_DeviceDetails_metadataTable"
|
||||
data-testid="device-detail-metadata-session"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Session ID
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
my-device
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_inline"
|
||||
data-testid="device-detail-sign-out-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="mx_DeviceDetails_signOutButtonContent"
|
||||
>
|
||||
Sign out of this session
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceDetails /> renders device with metadata 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceDetails"
|
||||
data-testid="device-detail-my-device"
|
||||
>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceDetailHeading"
|
||||
data-testid="device-detail-heading"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
My Device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_DeviceDetailHeading_renameCta mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="device-heading-rename-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Rename
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify your current session for enhanced secure messaging.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceDetails_sectionHeading"
|
||||
>
|
||||
Session details
|
||||
</p>
|
||||
<table
|
||||
class="mx_DeviceDetails_metadataTable"
|
||||
data-testid="device-detail-metadata-session"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Session ID
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
my-device
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Last activity
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
Sun 22:34
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table
|
||||
class="mx_DeviceDetails_metadataTable"
|
||||
data-testid="device-detail-metadata-application"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Application
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Name
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
Element Web
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table
|
||||
class="mx_DeviceDetails_metadataTable"
|
||||
data-testid="device-detail-metadata-device"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Device
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Model
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
Iphone X
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Operating system
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
Windows 95
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Browser
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
Firefox 100
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
IP address
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
123.456.789
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_inline"
|
||||
data-testid="device-detail-sign-out-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="mx_DeviceDetails_signOutButtonContent"
|
||||
>
|
||||
Sign out of this session
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceDetails /> renders device without metadata 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceDetails"
|
||||
data-testid="device-detail-my-device"
|
||||
>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceDetailHeading"
|
||||
data-testid="device-detail-heading"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
my-device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_DeviceDetailHeading_renameCta mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="device-heading-rename-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Rename
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify your current session for enhanced secure messaging.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceDetails_sectionHeading"
|
||||
>
|
||||
Session details
|
||||
</p>
|
||||
<table
|
||||
class="mx_DeviceDetails_metadataTable"
|
||||
data-testid="device-detail-metadata-session"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataLabel"
|
||||
>
|
||||
Session ID
|
||||
</td>
|
||||
<td
|
||||
class="mxDeviceDetails_metadataValue"
|
||||
>
|
||||
my-device
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section
|
||||
class="mx_DeviceDetails_section"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_inline"
|
||||
data-testid="device-detail-sign-out-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="mx_DeviceDetails_signOutButtonContent"
|
||||
>
|
||||
Sign out of this session
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,35 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DeviceExpandDetailsButton /> renders when expanded 1`] = `
|
||||
{
|
||||
"container": <div>
|
||||
<div
|
||||
aria-label="Hide details"
|
||||
class="mx_AccessibleButton mx_DeviceExpandDetailsButton mx_DeviceExpandDetailsButton_expanded mx_AccessibleButton_hasKind mx_AccessibleButton_kind_icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceExpandDetailsButton_icon"
|
||||
/>
|
||||
</div>
|
||||
</div>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`<DeviceExpandDetailsButton /> renders when not expanded 1`] = `
|
||||
{
|
||||
"container": <div>
|
||||
<div
|
||||
aria-label="Show details"
|
||||
class="mx_AccessibleButton mx_DeviceExpandDetailsButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceExpandDetailsButton_icon"
|
||||
/>
|
||||
</div>
|
||||
</div>,
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,70 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DeviceSecurityCard /> renders basic card 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Verified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Verified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
nice
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceSecurityCard /> renders with children 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Verified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
nice
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div>
|
||||
hey
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,233 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DeviceTile /> renders a device with no metadata 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceTile"
|
||||
data-testid="device-tile-123"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_info"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
123
|
||||
</h4>
|
||||
<div
|
||||
class="mx_DeviceTile_metadata"
|
||||
>
|
||||
<span
|
||||
data-testid="device-metadata-isVerified"
|
||||
>
|
||||
Unverified
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-deviceId"
|
||||
>
|
||||
123
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_actions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceTile /> renders a verified device with no metadata 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceTile"
|
||||
data-testid="device-tile-123"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_info"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
123
|
||||
</h4>
|
||||
<div
|
||||
class="mx_DeviceTile_metadata"
|
||||
>
|
||||
<span
|
||||
data-testid="device-metadata-isVerified"
|
||||
>
|
||||
Unverified
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-deviceId"
|
||||
>
|
||||
123
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_actions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceTile /> renders display name with a tooltip 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceTile"
|
||||
data-testid="device-tile-123"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_info"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
My device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_DeviceTile_metadata"
|
||||
>
|
||||
<span
|
||||
data-testid="device-metadata-isVerified"
|
||||
>
|
||||
Unverified
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-deviceId"
|
||||
>
|
||||
123
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_actions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceTile /> separates metadata with a dot 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceTile"
|
||||
data-testid="device-tile-123"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_info"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
123
|
||||
</h4>
|
||||
<div
|
||||
class="mx_DeviceTile_metadata"
|
||||
>
|
||||
<span
|
||||
data-testid="device-metadata-isVerified"
|
||||
>
|
||||
Unverified
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-lastActivity"
|
||||
>
|
||||
Last activity 15:13
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-lastSeenIp"
|
||||
>
|
||||
1.2.3.4
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-deviceId"
|
||||
>
|
||||
123
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_actions"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,70 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DeviceTypeIcon /> renders a verified device 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Verified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon verified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceTypeIcon /> renders an unverified device 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceTypeIcon /> renders correctly when selected 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon mx_DeviceTypeIcon_selected"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,127 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DeviceVerificationStatusCard /> renders a verified device 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Verified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Verified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
This session is ready for secure messaging.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceVerificationStatusCard /> renders an unverifiable device 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
This session doesn't support encryption and thus can't be verified.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<DeviceVerificationStatusCard /> renders an unverified device 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified session
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify or sign out from this session for best security and reliability.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
data-testid="verification-status-button-test-device"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Verify session
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,200 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<FilteredDeviceList /> displays no results message when there are no devices 1`] = `
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="mx_FilteredDeviceList_noResults"
|
||||
>
|
||||
No sessions found.
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`<FilteredDeviceList /> filtering filters correctly for Inactive 1`] = `
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="mx_FilteredDeviceList_securityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Inactive"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Inactive sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
<span>
|
||||
Consider signing out from old sessions (90 days or older) you don't use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`<FilteredDeviceList /> filtering filters correctly for Unverified 1`] = `
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="mx_FilteredDeviceList_securityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
<span>
|
||||
Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`<FilteredDeviceList /> filtering filters correctly for Verified 1`] = `
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="mx_FilteredDeviceList_securityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Verified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Verified sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
<span>
|
||||
For best security, sign out from any session that you don't recognize or use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`<FilteredDeviceList /> filtering renders no results correctly for Inactive 1`] = `
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="mx_FilteredDeviceList_noResults"
|
||||
>
|
||||
No inactive sessions found.
|
||||
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="devices-clear-filter-btn"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Show all
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`<FilteredDeviceList /> filtering renders no results correctly for Unverified 1`] = `
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="mx_FilteredDeviceList_noResults"
|
||||
>
|
||||
No unverified sessions found.
|
||||
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="devices-clear-filter-btn"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Show all
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`<FilteredDeviceList /> filtering renders no results correctly for Verified 1`] = `
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="mx_FilteredDeviceList_noResults"
|
||||
>
|
||||
No verified sessions found.
|
||||
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="devices-clear-filter-btn"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Show all
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
|
@ -0,0 +1,90 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<FilteredDeviceListHeader /> renders correctly when all devices are selected 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_FilteredDeviceListHeader"
|
||||
data-testid="test123"
|
||||
>
|
||||
<span
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
|
||||
>
|
||||
<input
|
||||
aria-label="Deselect all"
|
||||
aria-labelledby="floating-ui-6"
|
||||
checked=""
|
||||
data-testid="device-select-all-checkbox"
|
||||
id="device-select-all-checkbox"
|
||||
type="checkbox"
|
||||
/>
|
||||
<label
|
||||
for="device-select-all-checkbox"
|
||||
>
|
||||
<div
|
||||
class="mx_Checkbox_background"
|
||||
>
|
||||
<div
|
||||
class="mx_Checkbox_checkmark"
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="mx_FilteredDeviceListHeader_label"
|
||||
>
|
||||
Sessions
|
||||
</span>
|
||||
<div>
|
||||
test
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<FilteredDeviceListHeader /> renders correctly when no devices are selected 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_FilteredDeviceListHeader"
|
||||
data-testid="test123"
|
||||
>
|
||||
<span
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
|
||||
>
|
||||
<input
|
||||
aria-label="Select all"
|
||||
aria-labelledby="floating-ui-1"
|
||||
data-testid="device-select-all-checkbox"
|
||||
id="device-select-all-checkbox"
|
||||
type="checkbox"
|
||||
/>
|
||||
<label
|
||||
for="device-select-all-checkbox"
|
||||
>
|
||||
<div
|
||||
class="mx_Checkbox_background"
|
||||
>
|
||||
<div
|
||||
class="mx_Checkbox_checkmark"
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="mx_FilteredDeviceListHeader_label"
|
||||
>
|
||||
Sessions
|
||||
</span>
|
||||
<div>
|
||||
test
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,307 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<LoginWithQRSection /> MSC3906 should not render MSC3886 + get_login_token disabled 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Link new device
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_LoginWithQRSection"
|
||||
>
|
||||
<p
|
||||
class="mx_SettingsTab_subsectionText"
|
||||
>
|
||||
Use a QR code to sign in to another device and set up secure messaging.
|
||||
</p>
|
||||
<div
|
||||
aria-disabled="true"
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled"
|
||||
disabled=""
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 5V5h4v4H5Zm-2 5a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-6Zm2 5v-4h4v4H5Zm9-16a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1h-6Zm1 2v4h4V5h-4Z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
<path
|
||||
d="M15 16v-3h-2v3h2Z"
|
||||
/>
|
||||
<path
|
||||
d="M17 16h-2v2h-2v3h2v-3h2v2h4v-2h-2v-5h-2v3Z"
|
||||
/>
|
||||
</svg>
|
||||
Show QR code
|
||||
</div>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
>
|
||||
Not supported by your account provider
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<LoginWithQRSection /> MSC3906 should not render no support at all 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Link new device
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_LoginWithQRSection"
|
||||
>
|
||||
<p
|
||||
class="mx_SettingsTab_subsectionText"
|
||||
>
|
||||
Use a QR code to sign in to another device and set up secure messaging.
|
||||
</p>
|
||||
<div
|
||||
aria-disabled="true"
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled"
|
||||
disabled=""
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 5V5h4v4H5Zm-2 5a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-6Zm2 5v-4h4v4H5Zm9-16a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1h-6Zm1 2v4h4V5h-4Z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
<path
|
||||
d="M15 16v-3h-2v3h2Z"
|
||||
/>
|
||||
<path
|
||||
d="M17 16h-2v2h-2v3h2v-3h2v2h4v-2h-2v-5h-2v3Z"
|
||||
/>
|
||||
</svg>
|
||||
Show QR code
|
||||
</div>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
>
|
||||
Not supported by your account provider
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<LoginWithQRSection /> MSC3906 should not render only get_login_token enabled 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Link new device
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_LoginWithQRSection"
|
||||
>
|
||||
<p
|
||||
class="mx_SettingsTab_subsectionText"
|
||||
>
|
||||
Use a QR code to sign in to another device and set up secure messaging.
|
||||
</p>
|
||||
<div
|
||||
aria-disabled="true"
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled"
|
||||
disabled=""
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 5V5h4v4H5Zm-2 5a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-6Zm2 5v-4h4v4H5Zm9-16a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1h-6Zm1 2v4h4V5h-4Z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
<path
|
||||
d="M15 16v-3h-2v3h2Z"
|
||||
/>
|
||||
<path
|
||||
d="M17 16h-2v2h-2v3h2v-3h2v2h4v-2h-2v-5h-2v3Z"
|
||||
/>
|
||||
</svg>
|
||||
Show QR code
|
||||
</div>
|
||||
<p
|
||||
class="_typography_yh5dq_162 _font-body-sm-regular_yh5dq_40"
|
||||
>
|
||||
Not supported by your account provider
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<LoginWithQRSection /> MSC3906 should render panel get_login_token + .well-known 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Link new device
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_LoginWithQRSection"
|
||||
>
|
||||
<p
|
||||
class="mx_SettingsTab_subsectionText"
|
||||
>
|
||||
Use a QR code to sign in to another device and set up secure messaging.
|
||||
</p>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 5V5h4v4H5Zm-2 5a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-6Zm2 5v-4h4v4H5Zm9-16a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1h-6Zm1 2v4h4V5h-4Z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
<path
|
||||
d="M15 16v-3h-2v3h2Z"
|
||||
/>
|
||||
<path
|
||||
d="M17 16h-2v2h-2v3h2v-3h2v2h4v-2h-2v-5h-2v3Z"
|
||||
/>
|
||||
</svg>
|
||||
Show QR code
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<LoginWithQRSection /> MSC3906 should render panel get_login_token + MSC3886 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Link new device
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_LoginWithQRSection"
|
||||
>
|
||||
<p
|
||||
class="mx_SettingsTab_subsectionText"
|
||||
>
|
||||
Use a QR code to sign in to another device and set up secure messaging.
|
||||
</p>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3 4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 5V5h4v4H5Zm-2 5a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-6Zm2 5v-4h4v4H5Zm9-16a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1h-6Zm1 2v4h4V5h-4Z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
<path
|
||||
d="M15 16v-3h-2v3h2Z"
|
||||
/>
|
||||
<path
|
||||
d="M17 16h-2v2h-2v3h2v-3h2v2h4v-2h-2v-5h-2v3Z"
|
||||
/>
|
||||
</svg>
|
||||
Show QR code
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,376 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<SecurityRecommendations /> renders both cards when user has both unverified and inactive devices 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="security-recommendations-section"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Security recommendations
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_description"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Improve your account security by following these recommendations.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="unverified-devices-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
View all (1)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SecurityRecommendations_spacing"
|
||||
/>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Inactive"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Inactive sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Consider signing out from old sessions (90 days or older) you don't use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="inactive-devices-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
View all (1)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<SecurityRecommendations /> renders inactive devices section when user has inactive devices 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="security-recommendations-section"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Security recommendations
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_description"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Improve your account security by following these recommendations.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="unverified-devices-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
View all (1)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SecurityRecommendations_spacing"
|
||||
/>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Inactive"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Inactive sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Consider signing out from old sessions (90 days or older) you don't use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="inactive-devices-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
View all (1)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<SecurityRecommendations /> renders unverified devices section when user has unverified devices 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
data-testid="security-recommendations-section"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Security recommendations
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_description"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Improve your account security by following these recommendations.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Unverified"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Unverified sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="unverified-devices-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
View all (2)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SecurityRecommendations_spacing"
|
||||
/>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_icon Inactive"
|
||||
>
|
||||
<div
|
||||
height="16"
|
||||
width="16"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_content"
|
||||
>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_heading"
|
||||
>
|
||||
Inactive sessions
|
||||
</p>
|
||||
<p
|
||||
class="mx_DeviceSecurityCard_description"
|
||||
>
|
||||
Consider signing out from old sessions (90 days or older) you don't use anymore.
|
||||
<div
|
||||
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Learn more
|
||||
</div>
|
||||
</p>
|
||||
<div
|
||||
class="mx_DeviceSecurityCard_actions"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
data-testid="inactive-devices-cta"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
View all (1)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,101 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<SelectableDeviceTile /> renders selected tile 1`] = `
|
||||
<input
|
||||
checked=""
|
||||
data-testid="device-tile-checkbox-my-device"
|
||||
id="device-tile-checkbox-my-device"
|
||||
type="checkbox"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`<SelectableDeviceTile /> renders unselected device tile with checkbox 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SelectableDeviceTile"
|
||||
>
|
||||
<span
|
||||
class="mx_Checkbox mx_SelectableDeviceTile_checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
|
||||
>
|
||||
<input
|
||||
data-testid="device-tile-checkbox-my-device"
|
||||
id="device-tile-checkbox-my-device"
|
||||
type="checkbox"
|
||||
/>
|
||||
<label
|
||||
for="device-tile-checkbox-my-device"
|
||||
>
|
||||
<div
|
||||
class="mx_Checkbox_background"
|
||||
>
|
||||
<div
|
||||
class="mx_Checkbox_checkmark"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="mx_DeviceTile mx_DeviceTile_interactive"
|
||||
data-testid="device-tile-my-device"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon"
|
||||
>
|
||||
<div
|
||||
class="mx_DeviceTypeIcon_deviceIconWrapper"
|
||||
>
|
||||
<div
|
||||
aria-label="Unknown session type"
|
||||
class="mx_DeviceTypeIcon_deviceIcon"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Unverified"
|
||||
class="mx_DeviceTypeIcon_verificationIcon unverified"
|
||||
role="img"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_info"
|
||||
>
|
||||
<h4
|
||||
class="mx_Heading_h4"
|
||||
>
|
||||
My Device
|
||||
</h4>
|
||||
<div
|
||||
class="mx_DeviceTile_metadata"
|
||||
>
|
||||
<span
|
||||
data-testid="device-metadata-isVerified"
|
||||
>
|
||||
Unverified
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-lastSeenIp"
|
||||
>
|
||||
123.456.789
|
||||
</span>
|
||||
·
|
||||
<span
|
||||
data-testid="device-metadata-deviceId"
|
||||
>
|
||||
my-device
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_DeviceTile_actions"
|
||||
>
|
||||
<div>
|
||||
test
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,34 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`deleteDevices() opens interactive auth dialog when delete fails with 401 1`] = `
|
||||
{
|
||||
"m.login.sso": {
|
||||
"1": {
|
||||
"body": "Confirm logging out these devices by using Single Sign On to prove your identity.",
|
||||
"continueKind": "primary",
|
||||
"continueText": "Single Sign On",
|
||||
"title": "Use Single Sign On to continue",
|
||||
},
|
||||
"2": {
|
||||
"body": "Click the button below to confirm signing out these devices.",
|
||||
"continueKind": "danger",
|
||||
"continueText": "Sign out devices",
|
||||
"title": "Confirm signing out these devices",
|
||||
},
|
||||
},
|
||||
"org.matrix.login.sso": {
|
||||
"1": {
|
||||
"body": "Confirm logging out these devices by using Single Sign On to prove your identity.",
|
||||
"continueKind": "primary",
|
||||
"continueText": "Single Sign On",
|
||||
"title": "Use Single Sign On to continue",
|
||||
},
|
||||
"2": {
|
||||
"body": "Click the button below to confirm signing out these devices.",
|
||||
"continueKind": "danger",
|
||||
"continueText": "Sign out devices",
|
||||
"title": "Confirm signing out these devices",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { MatrixError, UIAFlow } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { deleteDevicesWithInteractiveAuth } from "../../../../../src/components/views/settings/devices/deleteDevices";
|
||||
import Modal from "../../../../../src/Modal";
|
||||
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../../test-utils";
|
||||
|
||||
describe("deleteDevices()", () => {
|
||||
const userId = "@alice:server.org";
|
||||
const deviceIds = ["device_1", "device_2"];
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(userId),
|
||||
deleteMultipleDevices: jest.fn(),
|
||||
});
|
||||
|
||||
const modalSpy = jest.spyOn(Modal, "createDialog") as jest.SpyInstance;
|
||||
|
||||
const interactiveAuthError = new MatrixError({ flows: [] as UIAFlow[] }, 401);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("deletes devices and calls onFinished when interactive auth is not required", async () => {
|
||||
mockClient.deleteMultipleDevices.mockResolvedValue({});
|
||||
const onFinished = jest.fn();
|
||||
|
||||
await deleteDevicesWithInteractiveAuth(mockClient, deviceIds, onFinished);
|
||||
|
||||
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith(deviceIds, undefined);
|
||||
expect(onFinished).toHaveBeenCalledWith(true, undefined);
|
||||
|
||||
// didnt open modal
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws without opening auth dialog when delete fails with a non-401 status code", async () => {
|
||||
const error = new Error("");
|
||||
// @ts-ignore
|
||||
error.httpStatus = 404;
|
||||
mockClient.deleteMultipleDevices.mockRejectedValue(error);
|
||||
const onFinished = jest.fn();
|
||||
|
||||
await expect(deleteDevicesWithInteractiveAuth(mockClient, deviceIds, onFinished)).rejects.toThrow(error);
|
||||
|
||||
expect(onFinished).not.toHaveBeenCalled();
|
||||
|
||||
// didnt open modal
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws without opening auth dialog when delete fails without data.flows", async () => {
|
||||
const error = new Error("");
|
||||
// @ts-ignore
|
||||
error.httpStatus = 401;
|
||||
// @ts-ignore
|
||||
error.data = {};
|
||||
mockClient.deleteMultipleDevices.mockRejectedValue(error);
|
||||
const onFinished = jest.fn();
|
||||
|
||||
await expect(deleteDevicesWithInteractiveAuth(mockClient, deviceIds, onFinished)).rejects.toThrow(error);
|
||||
|
||||
expect(onFinished).not.toHaveBeenCalled();
|
||||
|
||||
// didnt open modal
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("opens interactive auth dialog when delete fails with 401", async () => {
|
||||
mockClient.deleteMultipleDevices.mockRejectedValue(interactiveAuthError);
|
||||
const onFinished = jest.fn();
|
||||
|
||||
await deleteDevicesWithInteractiveAuth(mockClient, deviceIds, onFinished);
|
||||
|
||||
expect(onFinished).not.toHaveBeenCalled();
|
||||
|
||||
// opened modal
|
||||
expect(modalSpy).toHaveBeenCalled();
|
||||
|
||||
const { title, authData, aestheticsForStagePhases } = modalSpy.mock.calls[0][1]!;
|
||||
|
||||
// modal opened as expected
|
||||
expect(title).toEqual("Authentication");
|
||||
expect(authData).toEqual(interactiveAuthError.data);
|
||||
expect(aestheticsForStagePhases).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { filterDevicesBySecurityRecommendation } from "../../../../../src/components/views/settings/devices/filter";
|
||||
import { DeviceSecurityVariation } from "../../../../../src/components/views/settings/devices/types";
|
||||
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
|
||||
|
||||
const MS_DAY = 86400000;
|
||||
describe("filterDevicesBySecurityRecommendation()", () => {
|
||||
const unverifiedNoMetadata = {
|
||||
device_id: "unverified-no-metadata",
|
||||
isVerified: false,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const verifiedNoMetadata = {
|
||||
device_id: "verified-no-metadata",
|
||||
isVerified: true,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const hundredDaysOld = {
|
||||
device_id: "100-days-old",
|
||||
isVerified: true,
|
||||
last_seen_ts: Date.now() - MS_DAY * 100,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const hundredDaysOldUnverified = {
|
||||
device_id: "unverified-100-days-old",
|
||||
isVerified: false,
|
||||
last_seen_ts: Date.now() - MS_DAY * 100,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
const fiftyDaysOld = {
|
||||
device_id: "50-days-old",
|
||||
isVerified: true,
|
||||
last_seen_ts: Date.now() - MS_DAY * 50,
|
||||
deviceType: DeviceType.Unknown,
|
||||
};
|
||||
|
||||
const devices = [unverifiedNoMetadata, verifiedNoMetadata, hundredDaysOld, hundredDaysOldUnverified, fiftyDaysOld];
|
||||
|
||||
it("returns all devices when no securityRecommendations are passed", () => {
|
||||
expect(filterDevicesBySecurityRecommendation(devices, [])).toBe(devices);
|
||||
});
|
||||
|
||||
it("returns devices older than 90 days as inactive", () => {
|
||||
expect(filterDevicesBySecurityRecommendation(devices, [DeviceSecurityVariation.Inactive])).toEqual([
|
||||
// devices without ts metadata are not filtered as inactive
|
||||
hundredDaysOld,
|
||||
hundredDaysOldUnverified,
|
||||
]);
|
||||
});
|
||||
|
||||
it("returns correct devices for verified filter", () => {
|
||||
expect(filterDevicesBySecurityRecommendation(devices, [DeviceSecurityVariation.Verified])).toEqual([
|
||||
verifiedNoMetadata,
|
||||
hundredDaysOld,
|
||||
fiftyDaysOld,
|
||||
]);
|
||||
});
|
||||
|
||||
it("returns correct devices for unverified filter", () => {
|
||||
expect(filterDevicesBySecurityRecommendation(devices, [DeviceSecurityVariation.Unverified])).toEqual([
|
||||
unverifiedNoMetadata,
|
||||
hundredDaysOldUnverified,
|
||||
]);
|
||||
});
|
||||
|
||||
it("returns correct devices for combined verified and inactive filters", () => {
|
||||
expect(
|
||||
filterDevicesBySecurityRecommendation(devices, [
|
||||
DeviceSecurityVariation.Unverified,
|
||||
DeviceSecurityVariation.Inactive,
|
||||
]),
|
||||
).toEqual([hundredDaysOldUnverified]);
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue