Merge branch 'develop' into t3chguy/fix/27078

This commit is contained in:
Michael Telatynski
2024-12-04 10:02:26 +00:00
committed by GitHub
473 changed files with 6113 additions and 19397 deletions

View File

@@ -15,10 +15,11 @@ import RecordingPlayback, {
PlaybackLayout,
} from "../../../../../src/components/views/audio_messages/RecordingPlayback";
import { Playback } from "../../../../../src/audio/Playback";
import RoomContext, { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { createAudioContext } from "../../../../../src/audio/compat";
import { flushPromises } from "../../../../test-utils";
import { IRoomState } from "../../../../../src/components/structures/RoomView";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
jest.mock("../../../../../src/WorkerManager", () => ({
WorkerManager: jest.fn(() => ({
@@ -56,9 +57,9 @@ describe("<RecordingPlayback />", () => {
const defaultRoom = { roomId: "!room:server.org", timelineRenderingType: TimelineRenderingType.File } as IRoomState;
const getComponent = (props: React.ComponentProps<typeof RecordingPlayback>, room = defaultRoom) =>
render(
<RoomContext.Provider value={room}>
<ScopedRoomContextProvider {...room}>
<RecordingPlayback {...props} />
</RoomContext.Provider>,
</ScopedRoomContextProvider>,
);
beforeEach(() => {

View File

@@ -12,11 +12,11 @@ import { MatrixClient, PendingEventOrdering, Room, RoomMember } from "matrix-js-
import React, { ComponentProps } from "react";
import MemberAvatar from "../../../../../src/components/views/avatars/MemberAvatar";
import RoomContext from "../../../../../src/contexts/RoomContext";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { getRoomContext } from "../../../../test-utils/room";
import { stubClient } from "../../../../test-utils/test-utils";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
describe("MemberAvatar", () => {
const ROOM_ID = "roomId";
@@ -27,9 +27,9 @@ describe("MemberAvatar", () => {
function getComponent(props: Partial<ComponentProps<typeof MemberAvatar>>) {
return (
<RoomContext.Provider value={getRoomContext(room, {})}>
<ScopedRoomContextProvider {...getRoomContext(room, {})}>
<MemberAvatar member={null} size="35px" {...props} />
</RoomContext.Provider>
</ScopedRoomContextProvider>
);
}

View File

@@ -27,7 +27,7 @@ import { mocked } from "jest-mock";
import userEvent from "@testing-library/user-event";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import RoomContext, { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { IRoomState } from "../../../../../src/components/structures/RoomView";
import { canEditContent } from "../../../../../src/utils/EventUtils";
import { copyPlaintext, getSelectedText } from "../../../../../src/utils/strings";
@@ -37,9 +37,8 @@ import dispatcher from "../../../../../src/dispatcher/dispatcher";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { ReadPinsEventId } from "../../../../../src/components/views/right_panel/types";
import { Action } from "../../../../../src/dispatcher/actions";
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
import { VoiceBroadcastInfoState } from "../../../../../src/voice-broadcast";
import { createMessageEventContent } from "../../../../test-utils/events";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
jest.mock("../../../../../src/utils/strings", () => ({
copyPlaintext: jest.fn(),
@@ -233,17 +232,6 @@ describe("MessageContextMenu", () => {
expect(document.querySelector('li[aria-label="Forward"]')).toBeFalsy();
});
it("should not allow forwarding a voice broadcast", () => {
const broadcastStartEvent = mkVoiceBroadcastInfoStateEvent(
roomId,
VoiceBroadcastInfoState.Started,
"@user:example.com",
"ABC123",
);
createMenu(broadcastStartEvent);
expect(document.querySelector('li[aria-label="Forward"]')).toBeFalsy();
});
describe("forwarding beacons", () => {
const aliceId = "@alice:server.org";
@@ -546,8 +534,8 @@ function createMenu(
client.getRoom = jest.fn().mockReturnValue(room);
return render(
<RoomContext.Provider value={context as IRoomState}>
<ScopedRoomContextProvider {...(context as IRoomState)}>
<MessageContextMenu mxEvent={mxEvent} onFinished={jest.fn()} {...props} />
</RoomContext.Provider>,
</ScopedRoomContextProvider>,
);
}

View File

@@ -120,7 +120,7 @@ describe("RoomGeneralContextMenu", () => {
user: "@user:id",
ts: 1000,
});
room.addLiveEvents([event], {});
room.addLiveEvents([event], { addToState: true });
const { container } = getComponent({});

View File

@@ -6,14 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { Feature, ServerSupport } from "matrix-js-sdk/src/feature";
import { MatrixClient, MatrixEvent, RelationType } from "matrix-js-sdk/src/matrix";
import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { screen, act } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { flushPromises, mkEvent, stubClient } from "../../../../test-utils";
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
import { VoiceBroadcastInfoState } from "../../../../../src/voice-broadcast";
import { createRedactEventDialog } from "../../../../../src/components/views/dialogs/ConfirmRedactDialog";
describe("ConfirmRedactDialog", () => {
@@ -21,15 +18,6 @@ describe("ConfirmRedactDialog", () => {
let client: MatrixClient;
let mxEvent: MatrixEvent;
const setUpVoiceBroadcastStartedEvent = () => {
mxEvent = mkVoiceBroadcastInfoStateEvent(
roomId,
VoiceBroadcastInfoState.Started,
client.getUserId()!,
client.deviceId!,
);
};
const confirmDeleteVoiceBroadcastStartedEvent = async () => {
act(() => createRedactEventDialog({ mxEvent }));
// double-flush promises required for the dialog to show up
@@ -68,44 +56,4 @@ describe("ConfirmRedactDialog", () => {
`cannot redact event ${mxEvent.getId()} without room ID`,
);
});
describe("when redacting a voice broadcast started event", () => {
beforeEach(() => {
setUpVoiceBroadcastStartedEvent();
});
describe("and the server does not support relation based redactions", () => {
beforeEach(() => {
client.canSupport.set(Feature.RelationBasedRedactions, ServerSupport.Unsupported);
});
describe("and displaying and confirm the dialog for a voice broadcast", () => {
beforeEach(async () => {
await confirmDeleteVoiceBroadcastStartedEvent();
});
it("should call redact without `with_rel_types`", () => {
expect(client.redactEvent).toHaveBeenCalledWith(roomId, mxEvent.getId(), undefined, {});
});
});
});
describe("and the server supports relation based redactions", () => {
beforeEach(() => {
client.canSupport.set(Feature.RelationBasedRedactions, ServerSupport.Unstable);
});
describe("and displaying and confirm the dialog for a voice broadcast", () => {
beforeEach(async () => {
await confirmDeleteVoiceBroadcastStartedEvent();
});
it("should call redact with `with_rel_types`", () => {
expect(client.redactEvent).toHaveBeenCalledWith(roomId, mxEvent.getId(), undefined, {
with_rel_types: [RelationType.Reference],
});
});
});
});
});
});

View File

@@ -67,7 +67,6 @@ describe("ForwardDialog", () => {
getAccountData: jest.fn().mockReturnValue(accountDataEvent),
getPushActionsForEvent: jest.fn(),
mxcUrlToHttp: jest.fn().mockReturnValue(""),
isRoomEncrypted: jest.fn().mockReturnValue(false),
getProfileInfo: jest.fn().mockResolvedValue({
displayname: "Alice",
}),

View File

@@ -141,16 +141,19 @@ describe("InviteDialog", () => {
jest.clearAllMocks();
room = new Room(roomId, mockClient, mockClient.getSafeUserId());
room.addLiveEvents([
mkMessage({
msg: "Hello",
relatesTo: undefined,
event: true,
room: roomId,
user: mockClient.getSafeUserId(),
ts: Date.now(),
}),
]);
room.addLiveEvents(
[
mkMessage({
msg: "Hello",
relatesTo: undefined,
event: true,
room: roomId,
user: mockClient.getSafeUserId(),
ts: Date.now(),
}),
],
{ addToState: true },
);
room.currentState.setStateEvents([
mkRoomCreateEvent(bobId, roomId),
mkMembership({

View File

@@ -1,104 +0,0 @@
/*
* Copyright 2024 New Vector Ltd.
* Copyright 2023 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, screen } from "jest-matrix-react";
import { Device, MatrixClient } from "matrix-js-sdk/src/matrix";
import { stubClient } from "../../../../test-utils";
import { ManualDeviceKeyVerificationDialog } from "../../../../../src/components/views/dialogs/ManualDeviceKeyVerificationDialog";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
describe("ManualDeviceKeyVerificationDialog", () => {
let mockClient: MatrixClient;
function renderDialog(userId: string, device: Device, onLegacyFinished: (confirm: boolean) => void) {
return render(
<MatrixClientContext.Provider value={mockClient}>
<ManualDeviceKeyVerificationDialog userId={userId} device={device} onFinished={onLegacyFinished} />
</MatrixClientContext.Provider>,
);
}
beforeEach(() => {
mockClient = stubClient();
});
it("should display the device", () => {
// When
const deviceId = "XYZ";
const device = new Device({
userId: mockClient.getUserId()!,
deviceId,
displayName: "my device",
algorithms: [],
keys: new Map([[`ed25519:${deviceId}`, "ABCDEFGH"]]),
});
const { container } = renderDialog(mockClient.getUserId()!, device, jest.fn());
// Then
expect(container).toMatchSnapshot();
});
it("should display the device of another user", () => {
// When
const userId = "@alice:example.com";
const deviceId = "XYZ";
const device = new Device({
userId,
deviceId,
displayName: "my device",
algorithms: [],
keys: new Map([[`ed25519:${deviceId}`, "ABCDEFGH"]]),
});
const { container } = renderDialog(userId, device, jest.fn());
// Then
expect(container).toMatchSnapshot();
});
it("should call onFinished and matrixClient.setDeviceVerified", () => {
// When
const deviceId = "XYZ";
const device = new Device({
userId: mockClient.getUserId()!,
deviceId,
displayName: "my device",
algorithms: [],
keys: new Map([[`ed25519:${deviceId}`, "ABCDEFGH"]]),
});
const onFinished = jest.fn();
renderDialog(mockClient.getUserId()!, device, onFinished);
screen.getByRole("button", { name: "Verify session" }).click();
// Then
expect(onFinished).toHaveBeenCalledWith(true);
expect(mockClient.setDeviceVerified).toHaveBeenCalledWith(mockClient.getUserId(), deviceId, true);
});
it("should call onFinished and not matrixClient.setDeviceVerified", () => {
// When
const deviceId = "XYZ";
const device = new Device({
userId: mockClient.getUserId()!,
deviceId,
displayName: "my device",
algorithms: [],
keys: new Map([[`ed25519:${deviceId}`, "ABCDEFGH"]]),
});
const onFinished = jest.fn();
renderDialog(mockClient.getUserId()!, device, onFinished);
screen.getByRole("button", { name: "Cancel" }).click();
// Then
expect(onFinished).toHaveBeenCalledWith(false);
expect(mockClient.setDeviceVerified).not.toHaveBeenCalled();
});
});

View File

@@ -7,111 +7,139 @@ Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { EventTimeline, MatrixEvent, Room, RoomMember } from "matrix-js-sdk/src/matrix";
import { render, RenderOptions } from "jest-matrix-react";
import { MatrixClient, MatrixEvent, Room, RoomMember } from "matrix-js-sdk/src/matrix";
import { render, screen, act } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { waitFor } from "@testing-library/dom";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
import { _t } from "../../../../../src/languageHandler";
import ShareDialog from "../../../../../src/components/views/dialogs/ShareDialog";
import { ShareDialog } from "../../../../../src/components/views/dialogs/ShareDialog";
import { UIFeature } from "../../../../../src/settings/UIFeature";
import { stubClient } from "../../../../test-utils";
jest.mock("../../../../../src/utils/ShieldUtils");
function getWrapper(): RenderOptions {
return {
wrapper: ({ children }) => (
<MatrixClientContext.Provider value={MatrixClientPeg.safeGet()}>{children}</MatrixClientContext.Provider>
),
};
}
import { stubClient, withClientContextRenderOptions } from "../../../../test-utils";
import * as StringsModule from "../../../../../src/utils/strings";
import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks.ts";
describe("ShareDialog", () => {
let client: MatrixClient;
let room: Room;
const ROOM_ID = "!1:example.org";
const copyTextFunc = jest.fn();
beforeEach(async () => {
stubClient();
room = new Room(ROOM_ID, MatrixClientPeg.get()!, "@alice:example.org");
client = stubClient();
room = new Room("!1:example.org", client, "@alice:example.org");
jest.spyOn(StringsModule, "copyPlaintext").mockImplementation(copyTextFunc);
});
afterEach(() => {
jest.restoreAllMocks();
copyTextFunc.mockClear();
});
it("renders room share dialog", () => {
const { container: withoutEvents } = render(<ShareDialog target={room} onFinished={jest.fn()} />, getWrapper());
expect(withoutEvents).toHaveTextContent(_t("share|title_room"));
function renderComponent(target: Room | RoomMember | URL) {
return render(<ShareDialog target={target} onFinished={jest.fn()} />, withClientContextRenderOptions(client));
}
jest.spyOn(room, "getLiveTimeline").mockReturnValue({ getEvents: () => [{} as MatrixEvent] } as EventTimeline);
const { container: withEvents } = render(<ShareDialog target={room} onFinished={jest.fn()} />, getWrapper());
expect(withEvents).toHaveTextContent(_t("share|permalink_most_recent"));
const getUrl = () => new URL("https://matrix.org/");
const getRoomMember = () => new RoomMember(room.roomId, "@alice:example.org");
test.each([
{ name: "an URL", title: "Share Link", url: "https://matrix.org/", getTarget: getUrl },
{
name: "a room member",
title: "Share User",
url: "https://matrix.to/#/@alice:example.org",
getTarget: getRoomMember,
},
])("should render a share dialog for $name", async ({ title, url, getTarget }) => {
const { asFragment } = renderComponent(getTarget());
expect(screen.getByRole("heading", { name: title })).toBeInTheDocument();
expect(screen.getByText(url)).toBeInTheDocument();
expect(asFragment()).toMatchSnapshot();
await userEvent.click(screen.getByRole("button", { name: "Copy link" }));
expect(copyTextFunc).toHaveBeenCalledWith(url);
});
it("renders user share dialog", () => {
mockRoomMembers(room, 1);
const { container } = render(
<ShareDialog target={room.getJoinedMembers()[0]} onFinished={jest.fn()} />,
getWrapper(),
it("should render a share dialog for a room", async () => {
const expectedURL = "https://matrix.to/#/!1:example.org";
jest.spyOn(room.getLiveTimeline(), "getEvents").mockReturnValue([new MatrixEvent({ event_id: "!eventId" })]);
const { asFragment } = renderComponent(room);
expect(screen.getByRole("heading", { name: "Share Room" })).toBeInTheDocument();
expect(screen.getByText(expectedURL)).toBeInTheDocument();
expect(screen.getByRole("checkbox", { name: "Link to most recent message" })).toBeInTheDocument();
expect(asFragment()).toMatchSnapshot();
await userEvent.click(screen.getByRole("button", { name: "Copy link" }));
expect(copyTextFunc).toHaveBeenCalledWith(expectedURL);
// Click on the checkbox to link to the most recent message
await userEvent.click(screen.getByRole("checkbox", { name: "Link to most recent message" }));
const newExpectedURL = "https://matrix.to/#/!1:example.org/!eventId";
expect(screen.getByText(newExpectedURL)).toBeInTheDocument();
});
it("should render a share dialog for a matrix event", async () => {
const matrixEvent = new MatrixEvent({ event_id: "!eventId" });
const permalinkCreator = new RoomPermalinkCreator(room);
const expectedURL = "https://matrix.to/#/!1:example.org/!eventId";
const { asFragment } = render(
<ShareDialog target={matrixEvent} permalinkCreator={permalinkCreator} onFinished={jest.fn()} />,
withClientContextRenderOptions(client),
);
expect(container).toHaveTextContent(_t("share|title_user"));
expect(screen.getByRole("heading", { name: "Share Room Message" })).toBeInTheDocument();
expect(screen.getByText(expectedURL)).toBeInTheDocument();
expect(screen.getByRole("checkbox", { name: "Link to selected message" })).toBeChecked();
expect(asFragment()).toMatchSnapshot();
await userEvent.click(screen.getByRole("button", { name: "Copy link" }));
expect(copyTextFunc).toHaveBeenCalledWith(expectedURL);
// Click on the checkbox to link to the room
await userEvent.click(screen.getByRole("checkbox", { name: "Link to selected message" }));
expect(screen.getByText("https://matrix.to/#/!1:example.org")).toBeInTheDocument();
});
it("renders link share dialog", () => {
mockRoomMembers(room, 1);
const { container } = render(
<ShareDialog target={new URL("https://matrix.org")} onFinished={jest.fn()} />,
getWrapper(),
);
expect(container).toHaveTextContent(_t("share|title_link"));
it("should change the copy button text when clicked", async () => {
jest.useFakeTimers();
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
// To not be bother with rtl warnings about QR code state update
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
renderComponent(room);
await user.click(screen.getByRole("button", { name: "Copy link" }));
// Move after `copyPlaintext`
await jest.advanceTimersToNextTimerAsync();
expect(screen.getByRole("button", { name: "Link copied" })).toBeInTheDocument();
// 2 sec after the button should be back to normal
act(() => jest.advanceTimersByTime(2000));
await waitFor(() => expect(screen.getByRole("button", { name: "Copy link" })).toBeInTheDocument());
});
it("renders the QR code if configured", () => {
it("should not render the QR code if disabled", () => {
const originalGetValue = SettingsStore.getValue;
jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => {
if (feature === UIFeature.ShareQRCode) return true;
if (feature === UIFeature.ShareQRCode) return false;
return originalGetValue(feature);
});
const { container } = render(<ShareDialog target={room} onFinished={jest.fn()} />, getWrapper());
const qrCodesVisible = container.getElementsByClassName("mx_ShareDialog_qrcode_container").length > 0;
expect(qrCodesVisible).toBe(true);
const { asFragment } = renderComponent(room);
expect(screen.queryByRole("img", { name: "QR code" })).toBeNull();
expect(asFragment()).toMatchSnapshot();
});
it("renders the social button if configured", () => {
it("should not render the socials if disabled", () => {
const originalGetValue = SettingsStore.getValue;
jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => {
if (feature === UIFeature.ShareSocial) return true;
if (feature === UIFeature.ShareSocial) return false;
return originalGetValue(feature);
});
const { container } = render(<ShareDialog target={room} onFinished={jest.fn()} />, getWrapper());
const qrCodesVisible = container.getElementsByClassName("mx_ShareDialog_social_container").length > 0;
expect(qrCodesVisible).toBe(true);
});
it("renders custom title and subtitle", () => {
const { container } = render(
<ShareDialog
target={room}
customTitle="test_title_123"
subtitle="custom_subtitle_1234"
onFinished={jest.fn()}
/>,
getWrapper(),
);
expect(container).toHaveTextContent("test_title_123");
expect(container).toHaveTextContent("custom_subtitle_1234");
const { asFragment } = renderComponent(room);
expect(screen.queryByRole("link", { name: "Reddit" })).toBeNull();
expect(asFragment()).toMatchSnapshot();
});
});
/**
*
* @param count the number of users to create
*/
function mockRoomMembers(room: Room, count: number) {
const members = Array(count)
.fill(0)
.map((_, index) => new RoomMember(room.roomId, "@alice:example.org"));
room.currentState.setJoinedMemberCount(members.length);
room.getJoinedMembers = jest.fn().mockReturnValue(members);
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2024 New Vector Ltd.
*
* 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 { Device, MatrixClient, User } from "matrix-js-sdk/src/matrix";
import { render, screen } from "jest-matrix-react";
import { stubClient } from "../../../../test-utils";
import UntrustedDeviceDialog from "../../../../../src/components/views/dialogs/UntrustedDeviceDialog.tsx";
describe("<UntrustedDeviceDialog />", () => {
let client: MatrixClient;
let user: User;
let device: Device;
const onFinished = jest.fn();
beforeEach(() => {
client = stubClient();
user = User.createUser("@alice:example.org", client);
user.setDisplayName("Alice");
device = new Device({ deviceId: "device_id", userId: user.userId, algorithms: [], keys: new Map() });
});
afterEach(() => {
onFinished.mockReset();
});
function renderComponent() {
return render(<UntrustedDeviceDialog user={user} device={device} onFinished={onFinished} />);
}
it("should display the dialog for the device of another user", () => {
const { asFragment } = renderComponent();
expect(asFragment()).toMatchSnapshot();
});
it("should display the dialog for the device of the current user", () => {
jest.spyOn(client, "getUserId").mockReturnValue(user.userId);
const { asFragment } = renderComponent();
expect(asFragment()).toMatchSnapshot();
});
it("should call onFinished without parameter when Done is clicked", () => {
renderComponent();
screen.getByRole("button", { name: "Done" }).click();
expect(onFinished).toHaveBeenCalledWith();
});
it("should call onFinished with sas when Interactively verify by emoji is clicked", () => {
renderComponent();
screen.getByRole("button", { name: "Interactively verify by emoji" }).click();
expect(onFinished).toHaveBeenCalledWith("sas");
});
});

View File

@@ -185,33 +185,6 @@ exports[`DevtoolsDialog renders the devtools dialog 1`] = `
/>
</div>
</div>
<div
class="mx_SettingsFlag"
>
<label
class="mx_SettingsFlag_label"
for="mx_SettingsFlag_4yVCeEefiPqp"
>
<span
class="mx_SettingsFlag_labelText"
>
Force 15s voice broadcast chunk length
</span>
</label>
<div
aria-checked="false"
aria-disabled="false"
aria-label="Force 15s voice broadcast chunk length"
class="mx_AccessibleButton mx_ToggleSwitch mx_ToggleSwitch_enabled"
id="mx_SettingsFlag_4yVCeEefiPqp"
role="switch"
tabindex="0"
>
<div
class="mx_ToggleSwitch_ball"
/>
</div>
</div>
</div>
</div>
<div

View File

@@ -1,231 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ManualDeviceKeyVerificationDialog should display the device 1`] = `
<div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Verify session
</h1>
</div>
<div
class="mx_Dialog_content"
id="mx_Dialog_content"
>
<div>
<p>
Confirm by comparing the following with the User Settings in your other session:
</p>
<div
class="mx_DeviceVerifyDialog_cryptoSection"
>
<ul>
<li>
<label>
Session name
:
</label>
<span>
my device
</span>
</li>
<li>
<label>
Session ID
:
</label>
<span>
<code>
XYZ
</code>
</span>
</li>
<li>
<label>
Session key
:
</label>
<span>
<code>
<strong>
ABCD EFGH
</strong>
</code>
</span>
</li>
</ul>
</div>
<p>
If they don't match, the security of your communication may be compromised.
</p>
</div>
</div>
<div
class="mx_Dialog_buttons"
>
<span
class="mx_Dialog_buttons_row"
>
<button
data-testid="dialog-cancel-button"
type="button"
>
Cancel
</button>
<button
class="mx_Dialog_primary"
data-testid="dialog-primary-button"
type="button"
>
Verify session
</button>
</span>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</div>
`;
exports[`ManualDeviceKeyVerificationDialog should display the device of another user 1`] = `
<div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_QuestionDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Verify session
</h1>
</div>
<div
class="mx_Dialog_content"
id="mx_Dialog_content"
>
<div>
<p>
Confirm this user's session by comparing the following with their User Settings:
</p>
<div
class="mx_DeviceVerifyDialog_cryptoSection"
>
<ul>
<li>
<label>
Session name
:
</label>
<span>
my device
</span>
</li>
<li>
<label>
Session ID
:
</label>
<span>
<code>
XYZ
</code>
</span>
</li>
<li>
<label>
Session key
:
</label>
<span>
<code>
<strong>
ABCD EFGH
</strong>
</code>
</span>
</li>
</ul>
</div>
<p>
If they don't match, the security of your communication may be compromised.
</p>
</div>
</div>
<div
class="mx_Dialog_buttons"
>
<span
class="mx_Dialog_buttons_row"
>
<button
data-testid="dialog-cancel-button"
type="button"
>
Cancel
</button>
<button
class="mx_Dialog_primary"
data-testid="dialog-primary-button"
type="button"
>
Verify session
</button>
</span>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</div>
`;

View File

@@ -0,0 +1,852 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ShareDialog should not render the QR code if disabled 1`] = `
<DocumentFragment>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Share Room
</h1>
</div>
<div
class="mx_ShareDialog_content"
>
<div
class="mx_ShareDialog_top"
>
<span>
https://matrix.to/#/!1:example.org
</span>
</div>
<button
class="_button_i91xf_17 _has-icon_i91xf_66"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 19.071c-.978.978-2.157 1.467-3.536 1.467-1.378 0-2.557-.489-3.535-1.467-.978-.978-1.467-2.157-1.467-3.536 0-1.378.489-2.557 1.467-3.535L7.05 9.879c.2-.2.436-.3.707-.3.271 0 .507.1.707.3.2.2.301.436.301.707 0 .27-.1.506-.3.707l-2.122 2.121a2.893 2.893 0 0 0-.884 2.122c0 .824.295 1.532.884 2.12.59.59 1.296.885 2.121.885s1.533-.295 2.122-.884l2.121-2.121c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707L12 19.07Zm-1.414-4.243c-.2.2-.436.3-.707.3a.967.967 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l4.243-4.242c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707l-4.242 4.242Zm6.364-.707c-.2.2-.436.3-.707.3a.968.968 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l2.122-2.121c.59-.59.884-1.297.884-2.122s-.295-1.532-.884-2.12a2.893 2.893 0 0 0-2.121-.885c-.825 0-1.532.295-2.122.884l-2.121 2.121c-.2.2-.436.301-.707.301a.968.968 0 0 1-.707-.3.97.97 0 0 1-.3-.708c0-.27.1-.506.3-.707L12 4.93c.978-.978 2.157-1.467 3.536-1.467 1.378 0 2.557.489 3.535 1.467.978.978 1.467 2.157 1.467 3.535 0 1.38-.489 2.558-1.467 3.536l-2.121 2.121Z"
/>
</svg>
Copy link
</button>
<div
class="mx_ShareDialog_social"
>
<a
href="https://www.facebook.com/sharer/sharer.php?u=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="Facebook"
>
<img
alt="Facebook"
src="image-file-stub"
/>
</a>
<a
href="https://twitter.com/home?status=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="Twitter"
>
<img
alt="Twitter"
src="image-file-stub"
/>
</a>
<a
href="https://www.linkedin.com/shareArticle?mini=true&url=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="LinkedIn"
>
<img
alt="LinkedIn"
src="image-file-stub"
/>
</a>
<a
href="https://www.reddit.com/submit?url=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="Reddit"
>
<img
alt="Reddit"
src="image-file-stub"
/>
</a>
<a
href="mailto:?body=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="email"
>
<img
alt="email"
src="image-file-stub"
/>
</a>
</div>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</DocumentFragment>
`;
exports[`ShareDialog should not render the socials if disabled 1`] = `
<DocumentFragment>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Share Room
</h1>
</div>
<div
class="mx_ShareDialog_content"
>
<div
class="mx_ShareDialog_top"
>
<div
class="mx_QRCode"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<span>
https://matrix.to/#/!1:example.org
</span>
</div>
<button
class="_button_i91xf_17 _has-icon_i91xf_66"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 19.071c-.978.978-2.157 1.467-3.536 1.467-1.378 0-2.557-.489-3.535-1.467-.978-.978-1.467-2.157-1.467-3.536 0-1.378.489-2.557 1.467-3.535L7.05 9.879c.2-.2.436-.3.707-.3.271 0 .507.1.707.3.2.2.301.436.301.707 0 .27-.1.506-.3.707l-2.122 2.121a2.893 2.893 0 0 0-.884 2.122c0 .824.295 1.532.884 2.12.59.59 1.296.885 2.121.885s1.533-.295 2.122-.884l2.121-2.121c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707L12 19.07Zm-1.414-4.243c-.2.2-.436.3-.707.3a.967.967 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l4.243-4.242c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707l-4.242 4.242Zm6.364-.707c-.2.2-.436.3-.707.3a.968.968 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l2.122-2.121c.59-.59.884-1.297.884-2.122s-.295-1.532-.884-2.12a2.893 2.893 0 0 0-2.121-.885c-.825 0-1.532.295-2.122.884l-2.121 2.121c-.2.2-.436.301-.707.301a.968.968 0 0 1-.707-.3.97.97 0 0 1-.3-.708c0-.27.1-.506.3-.707L12 4.93c.978-.978 2.157-1.467 3.536-1.467 1.378 0 2.557.489 3.535 1.467.978.978 1.467 2.157 1.467 3.535 0 1.38-.489 2.558-1.467 3.536l-2.121 2.121Z"
/>
</svg>
Copy link
</button>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</DocumentFragment>
`;
exports[`ShareDialog should render a share dialog for a matrix event 1`] = `
<DocumentFragment>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Share Room Message
</h1>
</div>
<div
class="mx_ShareDialog_content"
>
<div
class="mx_ShareDialog_top"
>
<div
class="mx_QRCode"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<span>
https://matrix.to/#/!1:example.org/!eventId
</span>
</div>
<label>
<div
class="_container_1wloq_18"
>
<input
checked=""
class="_input_1wloq_26"
type="checkbox"
/>
<div
class="_ui_1wloq_27"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575c-.133 0-.258-.02-.375-.063a.876.876 0 0 1-.325-.212L4.55 13c-.183-.183-.27-.42-.263-.713.009-.291.105-.529.288-.712a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275L9.55 15.15l8.475-8.475c.183-.183.42-.275.713-.275.291 0 .529.092.712.275.183.183.275.42.275.713 0 .291-.092.529-.275.712l-9.2 9.2c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063Z"
/>
</svg>
</div>
</div>
Link to selected message
</label>
<button
class="_button_i91xf_17 _has-icon_i91xf_66"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 19.071c-.978.978-2.157 1.467-3.536 1.467-1.378 0-2.557-.489-3.535-1.467-.978-.978-1.467-2.157-1.467-3.536 0-1.378.489-2.557 1.467-3.535L7.05 9.879c.2-.2.436-.3.707-.3.271 0 .507.1.707.3.2.2.301.436.301.707 0 .27-.1.506-.3.707l-2.122 2.121a2.893 2.893 0 0 0-.884 2.122c0 .824.295 1.532.884 2.12.59.59 1.296.885 2.121.885s1.533-.295 2.122-.884l2.121-2.121c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707L12 19.07Zm-1.414-4.243c-.2.2-.436.3-.707.3a.967.967 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l4.243-4.242c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707l-4.242 4.242Zm6.364-.707c-.2.2-.436.3-.707.3a.968.968 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l2.122-2.121c.59-.59.884-1.297.884-2.122s-.295-1.532-.884-2.12a2.893 2.893 0 0 0-2.121-.885c-.825 0-1.532.295-2.122.884l-2.121 2.121c-.2.2-.436.301-.707.301a.968.968 0 0 1-.707-.3.97.97 0 0 1-.3-.708c0-.27.1-.506.3-.707L12 4.93c.978-.978 2.157-1.467 3.536-1.467 1.378 0 2.557.489 3.535 1.467.978.978 1.467 2.157 1.467 3.535 0 1.38-.489 2.558-1.467 3.536l-2.121 2.121Z"
/>
</svg>
Copy link
</button>
<div
class="mx_ShareDialog_social"
>
<a
href="https://www.facebook.com/sharer/sharer.php?u=https://matrix.to/#/!1:example.org/!eventId"
rel="noreferrer noopener"
target="_blank"
title="Facebook"
>
<img
alt="Facebook"
src="image-file-stub"
/>
</a>
<a
href="https://twitter.com/home?status=https://matrix.to/#/!1:example.org/!eventId"
rel="noreferrer noopener"
target="_blank"
title="Twitter"
>
<img
alt="Twitter"
src="image-file-stub"
/>
</a>
<a
href="https://www.linkedin.com/shareArticle?mini=true&url=https://matrix.to/#/!1:example.org/!eventId"
rel="noreferrer noopener"
target="_blank"
title="LinkedIn"
>
<img
alt="LinkedIn"
src="image-file-stub"
/>
</a>
<a
href="https://www.reddit.com/submit?url=https://matrix.to/#/!1:example.org/!eventId"
rel="noreferrer noopener"
target="_blank"
title="Reddit"
>
<img
alt="Reddit"
src="image-file-stub"
/>
</a>
<a
href="mailto:?body=https://matrix.to/#/!1:example.org/!eventId"
rel="noreferrer noopener"
target="_blank"
title="email"
>
<img
alt="email"
src="image-file-stub"
/>
</a>
</div>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</DocumentFragment>
`;
exports[`ShareDialog should render a share dialog for a room 1`] = `
<DocumentFragment>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Share Room
</h1>
</div>
<div
class="mx_ShareDialog_content"
>
<div
class="mx_ShareDialog_top"
>
<div
class="mx_QRCode"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<span>
https://matrix.to/#/!1:example.org
</span>
</div>
<label>
<div
class="_container_1wloq_18"
>
<input
class="_input_1wloq_26"
type="checkbox"
/>
<div
class="_ui_1wloq_27"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575c-.133 0-.258-.02-.375-.063a.876.876 0 0 1-.325-.212L4.55 13c-.183-.183-.27-.42-.263-.713.009-.291.105-.529.288-.712a.948.948 0 0 1 .7-.275.95.95 0 0 1 .7.275L9.55 15.15l8.475-8.475c.183-.183.42-.275.713-.275.291 0 .529.092.712.275.183.183.275.42.275.713 0 .291-.092.529-.275.712l-9.2 9.2c-.1.1-.208.17-.325.212a1.106 1.106 0 0 1-.375.063Z"
/>
</svg>
</div>
</div>
Link to most recent message
</label>
<button
class="_button_i91xf_17 _has-icon_i91xf_66"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 19.071c-.978.978-2.157 1.467-3.536 1.467-1.378 0-2.557-.489-3.535-1.467-.978-.978-1.467-2.157-1.467-3.536 0-1.378.489-2.557 1.467-3.535L7.05 9.879c.2-.2.436-.3.707-.3.271 0 .507.1.707.3.2.2.301.436.301.707 0 .27-.1.506-.3.707l-2.122 2.121a2.893 2.893 0 0 0-.884 2.122c0 .824.295 1.532.884 2.12.59.59 1.296.885 2.121.885s1.533-.295 2.122-.884l2.121-2.121c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707L12 19.07Zm-1.414-4.243c-.2.2-.436.3-.707.3a.967.967 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l4.243-4.242c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707l-4.242 4.242Zm6.364-.707c-.2.2-.436.3-.707.3a.968.968 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l2.122-2.121c.59-.59.884-1.297.884-2.122s-.295-1.532-.884-2.12a2.893 2.893 0 0 0-2.121-.885c-.825 0-1.532.295-2.122.884l-2.121 2.121c-.2.2-.436.301-.707.301a.968.968 0 0 1-.707-.3.97.97 0 0 1-.3-.708c0-.27.1-.506.3-.707L12 4.93c.978-.978 2.157-1.467 3.536-1.467 1.378 0 2.557.489 3.535 1.467.978.978 1.467 2.157 1.467 3.535 0 1.38-.489 2.558-1.467 3.536l-2.121 2.121Z"
/>
</svg>
Copy link
</button>
<div
class="mx_ShareDialog_social"
>
<a
href="https://www.facebook.com/sharer/sharer.php?u=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="Facebook"
>
<img
alt="Facebook"
src="image-file-stub"
/>
</a>
<a
href="https://twitter.com/home?status=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="Twitter"
>
<img
alt="Twitter"
src="image-file-stub"
/>
</a>
<a
href="https://www.linkedin.com/shareArticle?mini=true&url=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="LinkedIn"
>
<img
alt="LinkedIn"
src="image-file-stub"
/>
</a>
<a
href="https://www.reddit.com/submit?url=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="Reddit"
>
<img
alt="Reddit"
src="image-file-stub"
/>
</a>
<a
href="mailto:?body=https://matrix.to/#/!1:example.org"
rel="noreferrer noopener"
target="_blank"
title="email"
>
<img
alt="email"
src="image-file-stub"
/>
</a>
</div>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</DocumentFragment>
`;
exports[`ShareDialog should render a share dialog for a room member 1`] = `
<DocumentFragment>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Share User
</h1>
</div>
<div
class="mx_ShareDialog_content"
>
<div
class="mx_ShareDialog_top"
>
<div
class="mx_QRCode"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<span>
https://matrix.to/#/@alice:example.org
</span>
</div>
<button
class="_button_i91xf_17 _has-icon_i91xf_66"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 19.071c-.978.978-2.157 1.467-3.536 1.467-1.378 0-2.557-.489-3.535-1.467-.978-.978-1.467-2.157-1.467-3.536 0-1.378.489-2.557 1.467-3.535L7.05 9.879c.2-.2.436-.3.707-.3.271 0 .507.1.707.3.2.2.301.436.301.707 0 .27-.1.506-.3.707l-2.122 2.121a2.893 2.893 0 0 0-.884 2.122c0 .824.295 1.532.884 2.12.59.59 1.296.885 2.121.885s1.533-.295 2.122-.884l2.121-2.121c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707L12 19.07Zm-1.414-4.243c-.2.2-.436.3-.707.3a.967.967 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l4.243-4.242c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707l-4.242 4.242Zm6.364-.707c-.2.2-.436.3-.707.3a.968.968 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l2.122-2.121c.59-.59.884-1.297.884-2.122s-.295-1.532-.884-2.12a2.893 2.893 0 0 0-2.121-.885c-.825 0-1.532.295-2.122.884l-2.121 2.121c-.2.2-.436.301-.707.301a.968.968 0 0 1-.707-.3.97.97 0 0 1-.3-.708c0-.27.1-.506.3-.707L12 4.93c.978-.978 2.157-1.467 3.536-1.467 1.378 0 2.557.489 3.535 1.467.978.978 1.467 2.157 1.467 3.535 0 1.38-.489 2.558-1.467 3.536l-2.121 2.121Z"
/>
</svg>
Copy link
</button>
<div
class="mx_ShareDialog_social"
>
<a
href="https://www.facebook.com/sharer/sharer.php?u=https://matrix.to/#/@alice:example.org"
rel="noreferrer noopener"
target="_blank"
title="Facebook"
>
<img
alt="Facebook"
src="image-file-stub"
/>
</a>
<a
href="https://twitter.com/home?status=https://matrix.to/#/@alice:example.org"
rel="noreferrer noopener"
target="_blank"
title="Twitter"
>
<img
alt="Twitter"
src="image-file-stub"
/>
</a>
<a
href="https://www.linkedin.com/shareArticle?mini=true&url=https://matrix.to/#/@alice:example.org"
rel="noreferrer noopener"
target="_blank"
title="LinkedIn"
>
<img
alt="LinkedIn"
src="image-file-stub"
/>
</a>
<a
href="https://www.reddit.com/submit?url=https://matrix.to/#/@alice:example.org"
rel="noreferrer noopener"
target="_blank"
title="Reddit"
>
<img
alt="Reddit"
src="image-file-stub"
/>
</a>
<a
href="mailto:?body=https://matrix.to/#/@alice:example.org"
rel="noreferrer noopener"
target="_blank"
title="email"
>
<img
alt="email"
src="image-file-stub"
/>
</a>
</div>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</DocumentFragment>
`;
exports[`ShareDialog should render a share dialog for an URL 1`] = `
<DocumentFragment>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_ShareDialog"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Share Link
</h1>
</div>
<div
class="mx_ShareDialog_content"
>
<div
class="mx_ShareDialog_top"
>
<div
class="mx_QRCode"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading…"
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
/>
</div>
</div>
<span>
https://matrix.org/
</span>
</div>
<button
class="_button_i91xf_17 _has-icon_i91xf_66"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 19.071c-.978.978-2.157 1.467-3.536 1.467-1.378 0-2.557-.489-3.535-1.467-.978-.978-1.467-2.157-1.467-3.536 0-1.378.489-2.557 1.467-3.535L7.05 9.879c.2-.2.436-.3.707-.3.271 0 .507.1.707.3.2.2.301.436.301.707 0 .27-.1.506-.3.707l-2.122 2.121a2.893 2.893 0 0 0-.884 2.122c0 .824.295 1.532.884 2.12.59.59 1.296.885 2.121.885s1.533-.295 2.122-.884l2.121-2.121c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707L12 19.07Zm-1.414-4.243c-.2.2-.436.3-.707.3a.967.967 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l4.243-4.242c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707l-4.242 4.242Zm6.364-.707c-.2.2-.436.3-.707.3a.968.968 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l2.122-2.121c.59-.59.884-1.297.884-2.122s-.295-1.532-.884-2.12a2.893 2.893 0 0 0-2.121-.885c-.825 0-1.532.295-2.122.884l-2.121 2.121c-.2.2-.436.301-.707.301a.968.968 0 0 1-.707-.3.97.97 0 0 1-.3-.708c0-.27.1-.506.3-.707L12 4.93c.978-.978 2.157-1.467 3.536-1.467 1.378 0 2.557.489 3.535 1.467.978.978 1.467 2.157 1.467 3.535 0 1.38-.489 2.558-1.467 3.536l-2.121 2.121Z"
/>
</svg>
Copy link
</button>
<div
class="mx_ShareDialog_social"
>
<a
href="https://www.facebook.com/sharer/sharer.php?u=https://matrix.org/"
rel="noreferrer noopener"
target="_blank"
title="Facebook"
>
<img
alt="Facebook"
src="image-file-stub"
/>
</a>
<a
href="https://twitter.com/home?status=https://matrix.org/"
rel="noreferrer noopener"
target="_blank"
title="Twitter"
>
<img
alt="Twitter"
src="image-file-stub"
/>
</a>
<a
href="https://www.linkedin.com/shareArticle?mini=true&url=https://matrix.org/"
rel="noreferrer noopener"
target="_blank"
title="LinkedIn"
>
<img
alt="LinkedIn"
src="image-file-stub"
/>
</a>
<a
href="https://www.reddit.com/submit?url=https://matrix.org/"
rel="noreferrer noopener"
target="_blank"
title="Reddit"
>
<img
alt="Reddit"
src="image-file-stub"
/>
</a>
<a
href="mailto:?body=https://matrix.org/"
rel="noreferrer noopener"
target="_blank"
title="email"
>
<img
alt="email"
src="image-file-stub"
/>
</a>
</div>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</DocumentFragment>
`;

View File

@@ -0,0 +1,149 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<UntrustedDeviceDialog /> should display the dialog for the device of another user 1`] = `
<DocumentFragment>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-labelledby="mx_BaseDialog_title"
class="mx_UntrustedDeviceDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
<div
class="mx_E2EIcon mx_E2EIcon_warning"
style="width: 24px; height: 24px;"
/>
Not Trusted
</h1>
</div>
<div
class="mx_Dialog_content"
id="mx_Dialog_content"
>
<p>
Alice (@alice:example.org) signed in to a new session without verifying it:
</p>
<p>
(device_id)
</p>
<p>
Ask this user to verify their session, or manually verify it below.
</p>
</div>
<div
class="mx_Dialog_buttons"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
role="button"
tabindex="0"
>
Interactively verify by emoji
</div>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
role="button"
tabindex="0"
>
Done
</div>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</DocumentFragment>
`;
exports[`<UntrustedDeviceDialog /> should display the dialog for the device of the current user 1`] = `
<DocumentFragment>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-labelledby="mx_BaseDialog_title"
class="mx_UntrustedDeviceDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header"
>
<h1
class="mx_Heading_h3 mx_Dialog_title"
id="mx_BaseDialog_title"
>
<div
class="mx_E2EIcon mx_E2EIcon_warning"
style="width: 24px; height: 24px;"
/>
Not Trusted
</h1>
</div>
<div
class="mx_Dialog_content"
id="mx_Dialog_content"
>
<p>
You signed in to a new session without verifying it:
</p>
<p>
(device_id)
</p>
<p>
Verify your other session using one of the options below.
</p>
</div>
<div
class="mx_Dialog_buttons"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
role="button"
tabindex="0"
>
Interactively verify by emoji
</div>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
role="button"
tabindex="0"
>
Done
</div>
</div>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</DocumentFragment>
`;

View File

@@ -9,7 +9,8 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { screen, fireEvent, render, waitFor, act } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { Crypto, IMegolmSessionData } from "matrix-js-sdk/src/matrix";
import { IMegolmSessionData } from "matrix-js-sdk/src/matrix";
import { CryptoApi } from "matrix-js-sdk/src/crypto-api";
import * as MegolmExportEncryption from "../../../../../../src/utils/MegolmExportEncryption";
import ExportE2eKeysDialog from "../../../../../../src/async-components/views/dialogs/security/ExportE2eKeysDialog";
@@ -62,7 +63,7 @@ describe("ExportE2eKeysDialog", () => {
cli.getCrypto = () => {
return {
exportRoomKeysAsJson,
} as unknown as Crypto.CryptoApi;
} as unknown as CryptoApi;
};
// Mock the result of encrypting the sessions. If we don't do this, the

View File

@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { fireEvent, render, waitFor } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { Crypto } from "matrix-js-sdk/src/matrix";
import { CryptoApi } from "matrix-js-sdk/src/crypto-api";
import ImportE2eKeysDialog from "../../../../../../src/async-components/views/dialogs/security/ImportE2eKeysDialog";
import * as MegolmExportEncryption from "../../../../../../src/utils/MegolmExportEncryption";
@@ -67,7 +67,7 @@ describe("ImportE2eKeysDialog", () => {
cli.getCrypto = () => {
return {
importRoomKeysAsJson,
} as unknown as Crypto.CryptoApi;
} as unknown as CryptoApi;
};
// Mock the result of decrypting the sessions, to avoid needing to

View File

@@ -86,7 +86,7 @@ describe("<Pill>", () => {
room: room1Id,
msg: "Room 1 Message",
});
room1.addLiveEvents([room1Message]);
room1.addLiveEvents([room1Message], { addToState: true });
room2 = new Room(room2Id, client, user1Id);
room2.currentState.setStateEvents([mkRoomMemberJoinEvent(user2Id, room2Id)]);

View File

@@ -41,7 +41,7 @@ describe("<RoomTopic/>", () => {
ts: 123,
event: true,
});
room.addLiveEvents([topicEvent]);
room.addLiveEvents([topicEvent], { addToState: true });
return room;
}

View File

@@ -20,7 +20,8 @@ import {
import { MediaEventHelper } from "../../../../../src/utils/MediaEventHelper";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import MFileBody from "../../../../../src/components/views/messages/MFileBody.tsx";
import RoomContext, { TimelineRenderingType } from "../../../../../src/contexts/RoomContext.ts";
import { TimelineRenderingType } from "../../../../../src/contexts/RoomContext.ts";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
jest.mock("matrix-encrypt-attachment", () => ({
decryptAttachment: jest.fn(),
@@ -72,14 +73,14 @@ describe("<MFileBody/>", () => {
it("should show a download button in file rendering type", async () => {
const { container, getByRole } = render(
<RoomContext.Provider value={{ timelineRenderingType: TimelineRenderingType.File } as any}>
<ScopedRoomContextProvider {...({ timelineRenderingType: TimelineRenderingType.File } as any)}>
<MFileBody
{...props}
mxEvent={mediaEvent}
mediaEventHelper={new MediaEventHelper(mediaEvent)}
showGenericPlaceholder={false}
/>
</RoomContext.Provider>,
</ScopedRoomContextProvider>,
);
expect(getByRole("link", { name: "Download" })).toBeInTheDocument();

View File

@@ -35,6 +35,7 @@ import dispatcher from "../../../../../src/dispatcher/dispatcher";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { Action } from "../../../../../src/dispatcher/actions";
import PinningUtils from "../../../../../src/utils/PinningUtils";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
jest.mock("../../../../../src/dispatcher/dispatcher");
@@ -117,9 +118,9 @@ describe("<MessageActionBar />", () => {
} as unknown as IRoomState;
const getComponent = (props = {}, roomContext: Partial<IRoomState> = {}) =>
render(
<RoomContext.Provider value={{ ...defaultRoomContext, ...roomContext }}>
<ScopedRoomContextProvider {...defaultRoomContext} {...roomContext}>
<MessageActionBar {...defaultProps} {...props} />
</RoomContext.Provider>,
</ScopedRoomContextProvider>,
);
beforeEach(() => {

View File

@@ -14,7 +14,6 @@ import fs from "fs";
import path from "path";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "../../../../../src/voice-broadcast";
import { mkEvent, mkRoom, stubClient } from "../../../../test-utils";
import MessageEvent from "../../../../../src/components/views/messages/MessageEvent";
import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks";
@@ -24,10 +23,6 @@ jest.mock("../../../../../src/components/views/messages/UnknownBody", () => ({
default: () => <div data-testid="unknown-body" />,
}));
jest.mock("../../../../../src/voice-broadcast/components/VoiceBroadcastBody", () => ({
VoiceBroadcastBody: () => <div data-testid="voice-broadcast-body" />,
}));
jest.mock("../../../../../src/components/views/messages/MImageBody", () => ({
__esModule: true,
default: () => <div data-testid="image-body" />,
@@ -81,27 +76,6 @@ describe("MessageEvent", () => {
jest.spyOn(SettingsStore, "unwatchSetting").mockImplementation(jest.fn());
});
describe("when a voice broadcast start event occurs", () => {
let result: RenderResult;
beforeEach(() => {
event = mkEvent({
event: true,
type: VoiceBroadcastInfoEventType,
user: client.getUserId()!,
room: room.roomId,
content: {
state: VoiceBroadcastInfoState.Started,
},
});
result = renderMessageEvent();
});
it("should render a VoiceBroadcast component", () => {
result.getByTestId("voice-broadcast-body");
});
});
describe("when an image with a caption is sent", () => {
let result: RenderResult;

View File

@@ -20,9 +20,9 @@ import {
} from "../../../../../src/components/views/messages/RoomPredecessorTile";
import { stubClient, upsertRoomStateEvents } from "../../../../test-utils/test-utils";
import { Action } from "../../../../../src/dispatcher/actions";
import RoomContext from "../../../../../src/contexts/RoomContext";
import { filterConsole, getRoomContext } from "../../../../test-utils";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
jest.mock("../../../../../src/dispatcher/dispatcher");
@@ -99,9 +99,9 @@ describe("<RoomPredecessorTile />", () => {
expect(createEvent).toBeTruthy();
return render(
<RoomContext.Provider value={getRoomContext(room, {})}>
<ScopedRoomContextProvider {...getRoomContext(room, {})}>
<RoomPredecessorTile mxEvent={createEvent} />
</RoomContext.Provider>,
</ScopedRoomContextProvider>,
);
}

View File

@@ -15,7 +15,7 @@ import userEvent from "@testing-library/user-event";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import RoomSummaryCard from "../../../../../src/components/views/right_panel/RoomSummaryCard";
import ShareDialog from "../../../../../src/components/views/dialogs/ShareDialog";
import { ShareDialog } from "../../../../../src/components/views/dialogs/ShareDialog";
import ExportDialog from "../../../../../src/components/views/dialogs/ExportDialog";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
import defaultDispatcher from "../../../../../src/dispatcher/dispatcher";
@@ -30,7 +30,8 @@ import { _t } from "../../../../../src/languageHandler";
import { tagRoom } from "../../../../../src/utils/room/tagRoom";
import { DefaultTagID } from "../../../../../src/stores/room-list/models";
import { Action } from "../../../../../src/dispatcher/actions";
import RoomContext, { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
jest.mock("../../../../../src/utils/room/tagRoom");
@@ -172,14 +173,14 @@ describe("<RoomSummaryCard />", () => {
const onSearchChange = jest.fn();
const { rerender } = render(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={{ timelineRenderingType: TimelineRenderingType.Search } as any}>
<ScopedRoomContextProvider {...({ timelineRenderingType: TimelineRenderingType.Search } as any)}>
<RoomSummaryCard
room={room}
permalinkCreator={new RoomPermalinkCreator(room)}
onSearchChange={onSearchChange}
focusRoomSearch={true}
/>
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
@@ -188,13 +189,13 @@ describe("<RoomSummaryCard />", () => {
rerender(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={{ timelineRenderingType: TimelineRenderingType.Room } as any}>
<ScopedRoomContextProvider {...({ timelineRenderingType: TimelineRenderingType.Room } as any)}>
<RoomSummaryCard
room={room}
permalinkCreator={new RoomPermalinkCreator(room)}
onSearchChange={onSearchChange}
/>
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
expect(screen.getByPlaceholderText("Search messages…")).toHaveValue("");
@@ -254,10 +255,7 @@ describe("<RoomSummaryCard />", () => {
fireEvent.click(getByText("People"));
expect(RightPanelStore.instance.pushCard).toHaveBeenCalledWith(
{ phase: RightPanelPhases.RoomMemberList },
true,
);
expect(RightPanelStore.instance.pushCard).toHaveBeenCalledWith({ phase: RightPanelPhases.MemberList }, true);
});
it("opens room threads list on button click", () => {

View File

@@ -49,7 +49,7 @@ import ErrorDialog from "../../../../../src/components/views/dialogs/ErrorDialog
import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents";
import { UIComponent } from "../../../../../src/settings/UIFeature";
import { Action } from "../../../../../src/dispatcher/actions";
import ShareDialog from "../../../../../src/components/views/dialogs/ShareDialog";
import { ShareDialog } from "../../../../../src/components/views/dialogs/ShareDialog";
import BulkRedactDialog from "../../../../../src/components/views/dialogs/BulkRedactDialog";
jest.mock("../../../../../src/utils/direct-messages", () => ({
@@ -188,7 +188,7 @@ describe("<UserInfo />", () => {
const defaultProps = {
user: defaultUser,
// idk what is wrong with this type
phase: RightPanelPhases.RoomMemberInfo as RightPanelPhases.RoomMemberInfo,
phase: RightPanelPhases.MemberInfo as RightPanelPhases.MemberInfo,
onClose: jest.fn(),
};
@@ -455,7 +455,7 @@ describe("<UserInfo />", () => {
mockCrypto.getUserVerificationStatus.mockResolvedValue(new UserVerificationStatus(false, false, false));
const { container } = renderComponent({
phase: RightPanelPhases.SpaceMemberInfo,
phase: RightPanelPhases.MemberInfo,
verificationRequest,
room: mockRoom,
});
@@ -649,7 +649,7 @@ describe("<UserInfo />", () => {
mockClient.getDomain.mockReturnValue("example.com");
const { container } = renderComponent({
phase: RightPanelPhases.RoomMemberInfo,
phase: RightPanelPhases.MemberInfo,
room: mockRoom,
});

View File

@@ -88,7 +88,7 @@ exports[`<UserInfo /> with crypto enabled renders <BasicUserInfo /> 1`] = `
</p>
</div>
<button
aria-labelledby=":r6s:"
aria-labelledby=":r74:"
class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
data-testid="base-card-close-button"
role="button"
@@ -402,7 +402,7 @@ exports[`<UserInfo /> with crypto enabled should render a deactivate button for
</p>
</div>
<button
aria-labelledby=":r92:"
aria-labelledby=":r9a:"
class="_icon-button_bh2qc_17 _subtle-bg_bh2qc_38"
data-testid="base-card-close-button"
role="button"

View File

@@ -27,12 +27,12 @@ import {
import DocumentOffset from "../../../../../src/editor/offset";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import EditorStateTransfer from "../../../../../src/utils/EditorStateTransfer";
import RoomContext from "../../../../../src/contexts/RoomContext";
import { IRoomState } from "../../../../../src/components/structures/RoomView";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
import Autocompleter, { IProviderCompletions } from "../../../../../src/autocomplete/Autocompleter";
import NotifProvider from "../../../../../src/autocomplete/NotifProvider";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
describe("<EditMessageComposer/>", () => {
const userId = "@alice:server.org";
@@ -79,7 +79,7 @@ describe("<EditMessageComposer/>", () => {
render(<EditMessageComposerWithMatrixClient editState={editState} />, {
wrapper: ({ children }) => (
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={roomContext}>{children}</RoomContext.Provider>
<ScopedRoomContextProvider {...roomContext}>{children}</ScopedRoomContextProvider>
</MatrixClientContext.Provider>
),
});
@@ -128,7 +128,7 @@ describe("<EditMessageComposer/>", () => {
const expectedBody = {
...editedEvent.getContent(),
"body": " * original message + edit",
"body": "* original message + edit",
"m.new_content": {
"body": "original message + edit",
"msgtype": "m.text",
@@ -160,7 +160,7 @@ describe("<EditMessageComposer/>", () => {
const content = createEditContent(model, editedEvent);
expect(content).toEqual({
"body": " * hello world",
"body": "* hello world",
"msgtype": "m.text",
"m.new_content": {
"body": "hello world",
@@ -183,10 +183,10 @@ describe("<EditMessageComposer/>", () => {
const content = createEditContent(model, editedEvent);
expect(content).toEqual({
"body": " * hello *world*",
"body": "* hello *world*",
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"formatted_body": " * hello <em>world</em>",
"formatted_body": "* hello <em>world</em>",
"m.new_content": {
"body": "hello *world*",
"msgtype": "m.text",
@@ -210,10 +210,10 @@ describe("<EditMessageComposer/>", () => {
const content = createEditContent(model, editedEvent);
expect(content).toEqual({
"body": " * blinks __quickly__",
"body": "* blinks __quickly__",
"msgtype": "m.emote",
"format": "org.matrix.custom.html",
"formatted_body": " * blinks <strong>quickly</strong>",
"formatted_body": "* blinks <strong>quickly</strong>",
"m.new_content": {
"body": "blinks __quickly__",
"msgtype": "m.emote",
@@ -238,7 +238,7 @@ describe("<EditMessageComposer/>", () => {
const content = createEditContent(model, editedEvent);
expect(content).toEqual({
"body": " * ✨sparkles✨",
"body": "* ✨sparkles✨",
"msgtype": "m.emote",
"m.new_content": {
"body": "✨sparkles✨",
@@ -264,7 +264,7 @@ describe("<EditMessageComposer/>", () => {
// TODO Edits do not properly strip the double slash used to skip
// command processing.
expect(content).toEqual({
"body": " * //dev/null is my favourite place",
"body": "* //dev/null is my favourite place",
"msgtype": "m.text",
"m.new_content": {
"body": "//dev/null is my favourite place",

View File

@@ -30,7 +30,7 @@ import { mkEncryptedMatrixEvent } from "matrix-js-sdk/src/testing";
import EventTile, { EventTileProps } from "../../../../../src/components/views/rooms/EventTile";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
import RoomContext, { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import { filterConsole, flushPromises, getRoomContext, mkEvent, mkMessage, stubClient } from "../../../../test-utils";
import { mkThread } from "../../../../test-utils/threads";
@@ -40,6 +40,7 @@ import { Action } from "../../../../../src/dispatcher/actions";
import { IRoomState } from "../../../../../src/components/structures/RoomView";
import PinningUtils from "../../../../../src/utils/PinningUtils";
import { Layout } from "../../../../../src/settings/enums/Layout";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
describe("EventTile", () => {
const ROOM_ID = "!roomId:example.org";
@@ -56,13 +57,13 @@ describe("EventTile", () => {
}) {
return (
<MatrixClientContext.Provider value={client}>
<RoomContext.Provider value={props.roomContext}>
<ScopedRoomContextProvider {...props.roomContext}>
<EventTile
mxEvent={mxEvent}
replacingEventId={mxEvent.replacingEventId()}
{...(props.eventTilePropertyOverrides ?? {})}
/>
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>
);
}
@@ -70,9 +71,11 @@ describe("EventTile", () => {
function getComponent(
overrides: Partial<EventTileProps> = {},
renderingType: TimelineRenderingType = TimelineRenderingType.Room,
roomContext: Partial<IRoomState> = {},
) {
const context = getRoomContext(room, {
timelineRenderingType: renderingType,
...roomContext,
});
return render(<WrappedEventTile roomContext={context} eventTilePropertyOverrides={overrides} />);
}
@@ -301,6 +304,8 @@ describe("EventTile", () => {
[EventShieldReason.UNKNOWN_DEVICE, "unknown or deleted device"],
[EventShieldReason.AUTHENTICITY_NOT_GUARANTEED, "can't be guaranteed"],
[EventShieldReason.MISMATCHED_SENDER_KEY, "Encrypted by an unverified session"],
[EventShieldReason.SENT_IN_CLEAR, "Not encrypted"],
[EventShieldReason.VERIFICATION_VIOLATION, "Sender's verified identity has changed"],
])("shows the correct reason code for %i (%s)", async (reasonCode: EventShieldReason, expectedText: string) => {
mxEvent = await mkEncryptedMatrixEvent({
plainContent: { msgtype: "m.text", body: "msg1" },
@@ -434,8 +439,6 @@ describe("EventTile", () => {
});
it("should update the warning when the event is replaced with an unencrypted one", async () => {
jest.spyOn(client, "isRoomEncrypted").mockReturnValue(true);
// we start out with an event from the trusted device
mxEvent = await mkEncryptedMatrixEvent({
plainContent: { msgtype: "m.text", body: "msg1" },
@@ -449,7 +452,7 @@ describe("EventTile", () => {
shieldReason: null,
} as EventEncryptionInfo);
const roomContext = getRoomContext(room, {});
const roomContext = getRoomContext(room, { isRoomEncrypted: true });
const { container, rerender } = render(<WrappedEventTile roomContext={roomContext} />);
await flushPromises();
@@ -578,4 +581,28 @@ describe("EventTile", () => {
});
});
});
it("should display the not encrypted status for an unencrypted event when the room becomes encrypted", async () => {
jest.spyOn(client.getCrypto()!, "getEncryptionInfoForEvent").mockResolvedValue({
shieldColour: EventShieldColour.NONE,
shieldReason: null,
});
const { rerender } = getComponent();
await flushPromises();
// The room and the event are unencrypted, the tile should not show the not encrypted status
expect(screen.queryByText("Not encrypted")).toBeNull();
// The room is now encrypted
rerender(
<WrappedEventTile
roomContext={getRoomContext(room, {
isRoomEncrypted: true,
})}
/>,
);
// The event tile should now show the not encrypted status
await waitFor(() => expect(screen.getByText("Not encrypted")).toBeInTheDocument());
});
});

View File

@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import * as React from "react";
import { EventType, MatrixEvent, Room, RoomMember, THREAD_RELATION_TYPE } from "matrix-js-sdk/src/matrix";
import { EventType, MatrixEvent, RoomMember, THREAD_RELATION_TYPE } from "matrix-js-sdk/src/matrix";
import { act, fireEvent, render, screen, waitFor } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
@@ -19,17 +19,14 @@ import {
mkStubRoom,
mockPlatformPeg,
stubClient,
waitEnoughCyclesForModal,
} from "../../../../test-utils";
import MessageComposer from "../../../../../src/components/views/rooms/MessageComposer";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import RoomContext from "../../../../../src/contexts/RoomContext";
import { IRoomState } from "../../../../../src/components/structures/RoomView";
import ResizeNotifier from "../../../../../src/utils/ResizeNotifier";
import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks";
import { LocalRoom } from "../../../../../src/models/LocalRoom";
import { Features } from "../../../../../src/settings/Settings";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import dis from "../../../../../src/dispatcher/dispatcher";
@@ -37,9 +34,7 @@ import { E2EStatus } from "../../../../../src/utils/ShieldUtils";
import { addTextToComposerRTL } from "../../../../test-utils/composer";
import UIStore, { UI_EVENTS } from "../../../../../src/stores/UIStore";
import { Action } from "../../../../../src/dispatcher/actions";
import { VoiceBroadcastInfoState, VoiceBroadcastRecording } from "../../../../../src/voice-broadcast";
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
import { SdkContextClass } from "../../../../../src/contexts/SDKContext";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
const openStickerPicker = async (): Promise<void> => {
await userEvent.click(screen.getByLabelText("More options"));
@@ -51,15 +46,6 @@ const startVoiceMessage = async (): Promise<void> => {
await userEvent.click(screen.getByLabelText("Voice Message"));
};
const setCurrentBroadcastRecording = (room: Room, state: VoiceBroadcastInfoState): void => {
const recording = new VoiceBroadcastRecording(
mkVoiceBroadcastInfoStateEvent(room.roomId, state, "@user:example.com", "ABC123"),
MatrixClientPeg.safeGet(),
state,
);
act(() => SdkContextClass.instance.voiceBroadcastRecordingsStore.setCurrent(recording));
};
const expectVoiceMessageRecordingTriggered = (): void => {
// Checking for the voice message dialog text, if no mic can be found.
// By this we know at least that starting a voice message was triggered.
@@ -78,14 +64,11 @@ describe("MessageComposer", () => {
await clearAllModals();
jest.useRealTimers();
SdkContextClass.instance.voiceBroadcastRecordingsStore.clearCurrent();
// restore settings
act(() => {
[
"MessageComposerInput.showStickersButton",
"MessageComposerInput.showPollsButton",
Features.VoiceBroadcast,
"feature_wysiwyg_composer",
].forEach((setting: string): void => {
SettingsStore.setValue(setting, null, SettingLevel.DEVICE, SettingsStore.getDefaultValue(setting));
@@ -212,10 +195,6 @@ describe("MessageComposer", () => {
setting: "MessageComposerInput.showPollsButton",
buttonLabel: "Poll",
},
{
setting: Features.VoiceBroadcast,
buttonLabel: "Voice broadcast",
},
].forEach(({ setting, buttonLabel }) => {
[true, false].forEach((value: boolean) => {
describe(`when ${setting} = ${value}`, () => {
@@ -437,34 +416,6 @@ describe("MessageComposer", () => {
expectVoiceMessageRecordingTriggered();
});
});
describe("when recording a voice broadcast and trying to start a voice message", () => {
beforeEach(async () => {
setCurrentBroadcastRecording(room, VoiceBroadcastInfoState.Started);
wrapAndRender({ room });
await startVoiceMessage();
await waitEnoughCyclesForModal();
});
it("should not start a voice message and display the info dialog", async () => {
expect(screen.queryByLabelText("Stop recording")).not.toBeInTheDocument();
expect(screen.getByText("Can't start voice message")).toBeInTheDocument();
});
});
describe("when there is a stopped voice broadcast recording and trying to start a voice message", () => {
beforeEach(async () => {
setCurrentBroadcastRecording(room, VoiceBroadcastInfoState.Stopped);
wrapAndRender({ room });
await startVoiceMessage();
await waitEnoughCyclesForModal();
});
it("should try to start a voice message and should not display the info dialog", async () => {
expect(screen.queryByText("Can't start voice message")).not.toBeInTheDocument();
expectVoiceMessageRecordingTriggered();
});
});
});
describe("for a LocalRoom", () => {
@@ -512,9 +463,9 @@ function wrapAndRender(
const getRawComponent = (props = {}, context = roomContext, client = mockClient) => (
<MatrixClientContext.Provider value={client}>
<RoomContext.Provider value={context}>
<ScopedRoomContextProvider {...context}>
<MessageComposer {...defaultProps} {...props} />
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>
);
return {

View File

@@ -10,11 +10,11 @@ import React from "react";
import { render, screen, waitFor } from "jest-matrix-react";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
import RoomContext from "../../../../../src/contexts/RoomContext";
import { createTestClient, getRoomContext, mkStubRoom } from "../../../../test-utils";
import { IRoomState } from "../../../../../src/components/structures/RoomView";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import MessageComposerButtons from "../../../../../src/components/views/rooms/MessageComposerButtons";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
describe("MessageComposerButtons", () => {
// @ts-ignore - we're deliberately not implementing the whole interface here, but
@@ -54,7 +54,7 @@ describe("MessageComposerButtons", () => {
return render(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={defaultRoomContext}>{component}</RoomContext.Provider>
<ScopedRoomContextProvider {...defaultRoomContext}>{component}</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
}
@@ -168,27 +168,4 @@ describe("MessageComposerButtons", () => {
]);
});
});
describe("with showVoiceBroadcastButton = true", () => {
it("should render the »Voice broadcast« button", () => {
wrapAndRender(
<MessageComposerButtons
{...mockProps}
isMenuOpen={true}
showLocationButton={true}
showPollsButton={true}
showStickersButton={true}
showVoiceBroadcastButton={true}
/>,
false,
);
expect(getButtonLabels()).toEqual([
"Emoji",
"Attachment",
"More options",
["Sticker", "Voice Message", "Voice broadcast", "Poll", "Location"],
]);
});
});
});

View File

@@ -13,19 +13,19 @@ import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import { LocalRoom } from "../../../../../src/models/LocalRoom";
import { filterConsole, mkRoomMemberJoinEvent, mkThirdPartyInviteEvent, stubClient } from "../../../../test-utils";
import RoomContext from "../../../../../src/contexts/RoomContext";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
import NewRoomIntro from "../../../../../src/components/views/rooms/NewRoomIntro";
import { IRoomState } from "../../../../../src/components/structures/RoomView";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import { DirectoryMember } from "../../../../../src/utils/direct-messages";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
const renderNewRoomIntro = (client: MatrixClient, room: Room | LocalRoom) => {
render(
<MatrixClientContext.Provider value={client}>
<RoomContext.Provider value={{ room, roomId: room.roomId } as unknown as IRoomState}>
<ScopedRoomContextProvider {...({ room, roomId: room.roomId } as unknown as IRoomState)}>
<NewRoomIntro />
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
};

View File

@@ -165,7 +165,7 @@ describe("UnreadNotificationBadge", () => {
},
ts: 5,
});
room.addLiveEvents([event]);
room.addLiveEvents([event], { addToState: true });
const { container } = render(getComponent(THREAD_ID));
expect(container.querySelector(".mx_NotificationBadge_dot")).toBeTruthy();

View File

@@ -224,7 +224,7 @@ describe("<PinnedMessageBanner />", () => {
// The Right panel is opened on another card
jest.spyOn(RightPanelStore.instance, "isOpenForRoom").mockReturnValue(true);
jest.spyOn(RightPanelStore.instance, "currentCard", "get").mockReturnValue({
phase: RightPanelPhases.RoomMemberList,
phase: RightPanelPhases.MemberList,
});
renderBanner();

View File

@@ -158,7 +158,7 @@ describe("RoomHeader", () => {
fireEvent.click(facePile);
expect(setCardSpy).toHaveBeenCalledWith({ phase: RightPanelPhases.RoomMemberList });
expect(setCardSpy).toHaveBeenCalledWith({ phase: RightPanelPhases.MemberList });
});
it("has room info icon that opens the room info panel", async () => {
@@ -589,7 +589,7 @@ describe("RoomHeader", () => {
state_key: "",
room_id: room.roomId,
});
room.addLiveEvents([joinRuleEvent]);
room.addLiveEvents([joinRuleEvent], { addToState: true });
render(<RoomHeader room={room} />, getWrapper());

View File

@@ -19,7 +19,7 @@ import {
} from "../../../../../../src/components/views/rooms/RoomHeader/CallGuestLinkButton";
import Modal from "../../../../../../src/Modal";
import SdkConfig from "../../../../../../src/SdkConfig";
import ShareDialog from "../../../../../../src/components/views/dialogs/ShareDialog";
import { ShareDialog } from "../../../../../../src/components/views/dialogs/ShareDialog";
import { _t } from "../../../../../../src/languageHandler";
import SettingsStore from "../../../../../../src/settings/SettingsStore";

View File

@@ -9,14 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { render, screen, act, RenderResult } from "jest-matrix-react";
import { mocked, Mocked } from "jest-mock";
import {
MatrixClient,
PendingEventOrdering,
Room,
MatrixEvent,
RoomStateEvent,
Thread,
} from "matrix-js-sdk/src/matrix";
import { MatrixClient, PendingEventOrdering, Room, RoomStateEvent, Thread } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
import { Widget } from "matrix-widget-api";
@@ -40,8 +33,6 @@ import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import PlatformPeg from "../../../../../src/PlatformPeg";
import BasePlatform from "../../../../../src/BasePlatform";
import { WidgetMessagingStore } from "../../../../../src/stores/widgets/WidgetMessagingStore";
import { VoiceBroadcastInfoState } from "../../../../../src/voice-broadcast";
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
import { TestSdkContext } from "../../../TestSdkContext";
import { SDKContext } from "../../../../../src/contexts/SDKContext";
import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents";
@@ -61,20 +52,6 @@ describe("RoomTile", () => {
} as unknown as BasePlatform);
useMockedCalls();
const setUpVoiceBroadcast = async (state: VoiceBroadcastInfoState): Promise<void> => {
voiceBroadcastInfoEvent = mkVoiceBroadcastInfoStateEvent(
room.roomId,
state,
client.getSafeUserId(),
client.getDeviceId()!,
);
await act(async () => {
room.currentState.setStateEvents([voiceBroadcastInfoEvent]);
await flushPromises();
});
};
const renderRoomTile = (): RenderResult => {
return render(
<SDKContext.Provider value={sdkContext}>
@@ -89,7 +66,6 @@ describe("RoomTile", () => {
};
let client: Mocked<MatrixClient>;
let voiceBroadcastInfoEvent: MatrixEvent;
let room: Room;
let sdkContext: TestSdkContext;
let showMessagePreview = false;
@@ -303,49 +279,6 @@ describe("RoomTile", () => {
});
expect(screen.queryByLabelText(/participant/)).toBe(null);
});
describe("and a live broadcast starts", () => {
beforeEach(async () => {
renderRoomTile();
await setUpVoiceBroadcast(VoiceBroadcastInfoState.Started);
});
it("should still render the call subtitle", () => {
expect(screen.queryByText("Video")).toBeInTheDocument();
expect(screen.queryByText("Live")).not.toBeInTheDocument();
});
});
});
describe("when a live voice broadcast starts", () => {
beforeEach(async () => {
renderRoomTile();
await setUpVoiceBroadcast(VoiceBroadcastInfoState.Started);
});
it("should render the »Live« subtitle", () => {
expect(screen.queryByText("Live")).toBeInTheDocument();
});
describe("and the broadcast stops", () => {
beforeEach(async () => {
const stopEvent = mkVoiceBroadcastInfoStateEvent(
room.roomId,
VoiceBroadcastInfoState.Stopped,
client.getSafeUserId(),
client.getDeviceId()!,
voiceBroadcastInfoEvent,
);
await act(async () => {
room.currentState.setStateEvents([stopEvent]);
await flushPromises();
});
});
it("should not render the »Live« subtitle", () => {
expect(screen.queryByText("Live")).not.toBeInTheDocument();
});
});
});
});

View File

@@ -18,7 +18,7 @@ import SendMessageComposer, {
isQuickReaction,
} from "../../../../../src/components/views/rooms/SendMessageComposer";
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
import RoomContext, { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import { TimelineRenderingType } from "../../../../../src/contexts/RoomContext";
import EditorModel from "../../../../../src/editor/model";
import { createPartCreator } from "../../../editor/mock";
import { createTestClient, mkEvent, mkStubRoom, stubClient } from "../../../../test-utils";
@@ -30,6 +30,7 @@ import { IRoomState, MainSplitContentType } from "../../../../../src/components/
import { mockPlatformPeg } from "../../../../test-utils/platform";
import { doMaybeLocalRoomAction } from "../../../../../src/utils/local-room";
import { addTextToComposer } from "../../../../test-utils/composer";
import { ScopedRoomContextProvider } from "../../../../../src/contexts/ScopedRoomContext.tsx";
jest.mock("../../../../../src/utils/local-room", () => ({
doMaybeLocalRoomAction: jest.fn(),
@@ -77,6 +78,7 @@ describe("<SendMessageComposer/>", () => {
canAskToJoin: false,
promptAskToJoin: false,
viewRoomOpts: { buttons: [] },
isRoomEncrypted: false,
};
describe("createMessageContent", () => {
it("sends plaintext messages correctly", () => {
@@ -364,9 +366,9 @@ describe("<SendMessageComposer/>", () => {
};
const getRawComponent = (props = {}, roomContext = defaultRoomContext, client = mockClient) => (
<MatrixClientContext.Provider value={client}>
<RoomContext.Provider value={roomContext}>
<ScopedRoomContextProvider {...roomContext}>
<SendMessageComposer {...defaultProps} {...props} />
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>
);
const getComponent = (props = {}, roomContext = defaultRoomContext, client = mockClient) => {

View File

@@ -47,7 +47,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
>
<button
aria-labelledby=":r154:"
aria-labelledby=":r16c:"
class="_icon-button_bh2qc_17"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -73,7 +73,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
<button
aria-disabled="true"
aria-label="There's no one here to call"
aria-labelledby=":r159:"
aria-labelledby=":r16h:"
class="_icon-button_bh2qc_17"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -98,7 +98,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
</button>
<button
aria-label="Room info"
aria-labelledby=":r15e:"
aria-labelledby=":r16m:"
class="_icon-button_bh2qc_17"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -123,7 +123,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
</button>
<button
aria-label="Threads"
aria-labelledby=":r15j:"
aria-labelledby=":r16r:"
class="_icon-button_bh2qc_17"
role="button"
style="--cpd-icon-button-size: 32px;"

View File

@@ -11,7 +11,6 @@ import React from "react";
import { fireEvent, render, screen, waitFor } from "jest-matrix-react";
import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
import RoomContext from "../../../../../../src/contexts/RoomContext";
import defaultDispatcher from "../../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../../src/dispatcher/actions";
import { flushPromises, mkEvent } from "../../../../../test-utils";
@@ -23,6 +22,7 @@ import { ComposerInsertPayload, ComposerType } from "../../../../../../src/dispa
import { ActionPayload } from "../../../../../../src/dispatcher/payloads";
import * as EmojiButton from "../../../../../../src/components/views/rooms/EmojiButton";
import { createMocks } from "./utils";
import { ScopedRoomContextProvider } from "../../../../../../src/contexts/ScopedRoomContext.tsx";
describe("EditWysiwygComposer", () => {
afterEach(() => {
@@ -39,9 +39,9 @@ describe("EditWysiwygComposer", () => {
) => {
return render(
<MatrixClientContext.Provider value={client}>
<RoomContext.Provider value={roomContext}>
<ScopedRoomContextProvider {...roomContext}>
<EditWysiwygComposer disabled={disabled} editorStateTransfer={_editorStateTransfer} />
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
};
@@ -64,9 +64,9 @@ describe("EditWysiwygComposer", () => {
rerender(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={{ ...defaultRoomContext, room: undefined }}>
<ScopedRoomContextProvider {...defaultRoomContext} room={undefined}>
<EditWysiwygComposer disabled={false} editorStateTransfer={editorStateTransfer} />
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
@@ -196,9 +196,9 @@ describe("EditWysiwygComposer", () => {
// Then
screen.getByText("Save").click();
const expectedContent = {
"body": ` * foo bar`,
"body": `* foo bar`,
"format": "org.matrix.custom.html",
"formatted_body": ` * foo bar`,
"formatted_body": `* foo bar`,
"m.new_content": {
body: "foo bar",
format: "org.matrix.custom.html",
@@ -275,10 +275,10 @@ describe("EditWysiwygComposer", () => {
);
render(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={defaultRoomContext}>
<ScopedRoomContextProvider {...defaultRoomContext}>
<EditWysiwygComposer editorStateTransfer={editorStateTransfer} />
<Emoji menuPosition={{ chevronFace: ChevronFace.Top }} />
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
// Same behavior as in RoomView.tsx

View File

@@ -11,7 +11,6 @@ import React from "react";
import { act, fireEvent, render, screen, waitFor } from "jest-matrix-react";
import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
import RoomContext from "../../../../../../src/contexts/RoomContext";
import defaultDispatcher from "../../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../../src/dispatcher/actions";
import { flushPromises } from "../../../../../test-utils";
@@ -20,6 +19,7 @@ import { aboveLeftOf } from "../../../../../../src/components/structures/Context
import { ComposerInsertPayload, ComposerType } from "../../../../../../src/dispatcher/payloads/ComposerInsertPayload";
import { setSelection } from "../../../../../../src/components/views/rooms/wysiwyg_composer/utils/selection";
import { createMocks } from "./utils";
import { ScopedRoomContextProvider } from "../../../../../../src/contexts/ScopedRoomContext.tsx";
jest.mock("../../../../../../src/components/views/rooms/EmojiButton", () => ({
EmojiButton: ({ addEmoji }: { addEmoji: (emoji: string) => void }) => {
@@ -66,7 +66,7 @@ describe("SendWysiwygComposer", () => {
) => {
return render(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={defaultRoomContext}>
<ScopedRoomContextProvider {...defaultRoomContext}>
<SendWysiwygComposer
onChange={onChange}
onSend={onSend}
@@ -75,7 +75,7 @@ describe("SendWysiwygComposer", () => {
menuPosition={aboveLeftOf({ top: 0, bottom: 0, right: 0 })}
placeholder={placeholder}
/>
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
};

View File

@@ -14,7 +14,7 @@ import { PlainTextComposer } from "../../../../../../../src/components/views/roo
import * as mockUseSettingsHook from "../../../../../../../src/hooks/useSettings";
import * as mockKeyboard from "../../../../../../../src/Keyboard";
import { createMocks } from "../utils";
import RoomContext from "../../../../../../../src/contexts/RoomContext";
import { ScopedRoomContextProvider } from "../../../../../../../src/contexts/ScopedRoomContext.tsx";
describe("PlainTextComposer", () => {
const customRender = (
@@ -275,9 +275,9 @@ describe("PlainTextComposer", () => {
const { defaultRoomContext } = createMocks();
render(
<RoomContext.Provider value={defaultRoomContext}>
<ScopedRoomContextProvider {...defaultRoomContext}>
<PlainTextComposer onChange={jest.fn()} onSend={jest.fn()} disabled={false} initialContent="" />
</RoomContext.Provider>,
</ScopedRoomContextProvider>,
);
expect(screen.getByTestId("autocomplete-wrapper")).toBeInTheDocument();

View File

@@ -11,12 +11,12 @@ import React, { createRef } from "react";
import { render, screen, waitFor } from "jest-matrix-react";
import MatrixClientContext from "../../../../../../../src/contexts/MatrixClientContext";
import RoomContext from "../../../../../../../src/contexts/RoomContext";
import { WysiwygAutocomplete } from "../../../../../../../src/components/views/rooms/wysiwyg_composer/components/WysiwygAutocomplete";
import { getRoomContext, mkStubRoom, stubClient } from "../../../../../../test-utils";
import Autocomplete from "../../../../../../../src/components/views/rooms/Autocomplete";
import Autocompleter, { ICompletion } from "../../../../../../../src/autocomplete/Autocompleter";
import AutocompleteProvider from "../../../../../../../src/autocomplete/AutocompleteProvider";
import { ScopedRoomContextProvider } from "../../../../../../../src/contexts/ScopedRoomContext.tsx";
const mockCompletion: ICompletion[] = [
{
@@ -71,7 +71,7 @@ describe("WysiwygAutocomplete", () => {
return render(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={mockRoomContext}>
<ScopedRoomContextProvider {...mockRoomContext}>
<WysiwygAutocomplete
ref={autocompleteRef}
suggestion={null}
@@ -80,7 +80,7 @@ describe("WysiwygAutocomplete", () => {
handleAtRoomMention={mockHandleAtRoomMention}
{...props}
/>
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
};

View File

@@ -18,7 +18,6 @@ import defaultDispatcher from "../../../../../../../src/dispatcher/dispatcher";
import * as EventUtils from "../../../../../../../src/utils/EventUtils";
import { Action } from "../../../../../../../src/dispatcher/actions";
import MatrixClientContext from "../../../../../../../src/contexts/MatrixClientContext";
import RoomContext from "../../../../../../../src/contexts/RoomContext";
import {
ComposerContext,
getDefaultContextValue,
@@ -32,20 +31,21 @@ import Autocompleter, { ICompletion } from "../../../../../../../src/autocomplet
import AutocompleteProvider from "../../../../../../../src/autocomplete/AutocompleteProvider";
import * as Permalinks from "../../../../../../../src/utils/permalinks/Permalinks";
import { PermalinkParts } from "../../../../../../../src/utils/permalinks/PermalinkConstructor";
import { ScopedRoomContextProvider } from "../../../../../../../src/contexts/ScopedRoomContext.tsx";
describe("WysiwygComposer", () => {
const customRender = (onChange = jest.fn(), onSend = jest.fn(), disabled = false, initialContent?: string) => {
const { mockClient, defaultRoomContext } = createMocks();
return render(
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider value={defaultRoomContext}>
<ScopedRoomContextProvider {...defaultRoomContext}>
<WysiwygComposer
onChange={onChange}
onSend={onSend}
disabled={disabled}
initialContent={initialContent}
/>
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
};
@@ -523,7 +523,7 @@ describe("WysiwygComposer", () => {
) => {
return render(
<MatrixClientContext.Provider value={client}>
<RoomContext.Provider value={roomContext}>
<ScopedRoomContextProvider {...roomContext}>
<ComposerContext.Provider
value={getDefaultContextValue({ editorStateTransfer: _editorStateTransfer })}
>
@@ -537,7 +537,7 @@ describe("WysiwygComposer", () => {
}
/>
</ComposerContext.Provider>
</RoomContext.Provider>
</ScopedRoomContextProvider>
</MatrixClientContext.Provider>,
);
};

View File

@@ -88,9 +88,9 @@ describe("createMessageContent", () => {
// Then
expect(content).toEqual({
"body": " * *__hello__ world*",
"body": "* *__hello__ world*",
"format": "org.matrix.custom.html",
"formatted_body": ` * ${message}`,
"formatted_body": `* ${message}`,
"msgtype": "m.text",
"m.new_content": {
body: "*__hello__ world*",

View File

@@ -418,8 +418,8 @@ describe("message", () => {
// Then
const { msgtype, format } = mockEvent.getContent();
const expectedContent = {
"body": ` * ${newMessage}`,
"formatted_body": ` * ${newMessage}`,
"body": `* ${newMessage}`,
"formatted_body": `* ${newMessage}`,
"m.new_content": {
body: "Replying to this new content",
format: "org.matrix.custom.html",

View File

@@ -915,7 +915,7 @@ describe("<Notifications />", () => {
user: "@alice:example.org",
ts: 1,
});
await room.addLiveEvents([message]);
await room.addLiveEvents([message], { addToState: true });
const { container } = await getComponentAndWait();
const clearNotificationEl = getByTestId(container, "clear-notifications");

View File

@@ -56,7 +56,6 @@ describe("<LoginWithQRSection />", () => {
const defaultProps = {
onShowQr: () => {},
versions: makeVersions({ "org.matrix.msc4108": true }),
wellKnown: {},
};
const getComponent = (props = {}) => <LoginWithQRSection {...defaultProps} {...props} />;

View File

@@ -716,7 +716,7 @@ describe("<Notifications />", () => {
user: "@alice:example.org",
ts: 1,
});
room.addLiveEvents([message]);
room.addLiveEvents([message], { addToState: true });
room.setUnreadNotificationCount(NotificationCountType.Total, 1);
const user = userEvent.setup();

View File

@@ -17,7 +17,6 @@ import userEvent from "@testing-library/user-event";
import RolesRoomSettingsTab from "../../../../../../../src/components/views/settings/tabs/room/RolesRoomSettingsTab";
import { mkStubRoom, withClientContextRenderOptions, stubClient } from "../../../../../../test-utils";
import { MatrixClientPeg } from "../../../../../../../src/MatrixClientPeg";
import { VoiceBroadcastInfoEventType } from "../../../../../../../src/voice-broadcast";
import SettingsStore from "../../../../../../../src/settings/SettingsStore";
import { ElementCall } from "../../../../../../../src/models/Call";
@@ -34,14 +33,6 @@ describe("RolesRoomSettingsTab", () => {
return renderResult;
};
const getVoiceBroadcastsSelect = async (): Promise<Element> => {
return (await renderTab()).container.querySelector("select[label='Voice broadcasts']")!;
};
const getVoiceBroadcastsSelectedOption = async (): Promise<Element> => {
return (await renderTab()).container.querySelector("select[label='Voice broadcasts'] option:checked")!;
};
beforeEach(() => {
stubClient();
cli = MatrixClientPeg.safeGet();
@@ -76,26 +67,6 @@ describe("RolesRoomSettingsTab", () => {
expect(container.querySelector(`[placeholder="@admin:server"]`)).toBeDisabled();
});
it("should initially show »Moderator« permission for »Voice broadcasts«", async () => {
expect((await getVoiceBroadcastsSelectedOption()).textContent).toBe("Moderator");
});
describe("when setting »Default« permission for »Voice broadcasts«", () => {
beforeEach(async () => {
fireEvent.change(await getVoiceBroadcastsSelect(), {
target: { value: 0 },
});
});
it("should update the power levels", () => {
expect(cli.sendStateEvent).toHaveBeenCalledWith(roomId, EventType.RoomPowerLevels, {
events: {
[VoiceBroadcastInfoEventType]: 0,
},
});
});
});
describe("Element Call", () => {
const setGroupCallsEnabled = (val: boolean): void => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {

View File

@@ -75,7 +75,7 @@ describe("<SecurityRoomSettingsTab />", () => {
beforeEach(async () => {
client.sendStateEvent.mockReset().mockResolvedValue({ event_id: "test" });
client.isRoomEncrypted.mockReturnValue(false);
jest.spyOn(client.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(false);
client.getClientWellKnown.mockReturnValue(undefined);
jest.spyOn(SettingsStore, "getValue").mockRestore();
@@ -313,7 +313,7 @@ describe("<SecurityRoomSettingsTab />", () => {
setRoomStateEvents(room);
getComponent(room);
expect(screen.getByLabelText("Encrypted")).not.toBeChecked();
await waitFor(() => expect(screen.getByLabelText("Encrypted")).not.toBeChecked());
fireEvent.click(screen.getByLabelText("Encrypted"));
@@ -330,7 +330,7 @@ describe("<SecurityRoomSettingsTab />", () => {
setRoomStateEvents(room);
getComponent(room);
expect(screen.getByLabelText("Encrypted")).not.toBeChecked();
await waitFor(() => expect(screen.getByLabelText("Encrypted")).not.toBeChecked());
fireEvent.click(screen.getByLabelText("Encrypted"));
@@ -416,12 +416,12 @@ describe("<SecurityRoomSettingsTab />", () => {
expect(screen.getByText("Once enabled, encryption cannot be disabled.")).toBeInTheDocument();
});
it("displays unencrypted rooms with toggle disabled", () => {
it("displays unencrypted rooms with toggle disabled", async () => {
const room = new Room(roomId, client, userId);
setRoomStateEvents(room);
getComponent(room);
expect(screen.getByLabelText("Encrypted")).not.toBeChecked();
await waitFor(() => expect(screen.getByLabelText("Encrypted")).not.toBeChecked());
expect(screen.getByLabelText("Encrypted").getAttribute("aria-disabled")).toEqual("true");
expect(screen.queryByText("Once enabled, encryption cannot be disabled.")).not.toBeInTheDocument();
expect(screen.getByText("Your server requires encryption to be disabled.")).toBeInTheDocument();