Merge matrix-react-sdk into element-web

Merge remote-tracking branch 'repomerge/t3chguy/repomerge' into t3chguy/repo-merge

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2024-10-15 14:57:26 +01:00
3265 changed files with 484599 additions and 699 deletions

View File

@@ -0,0 +1,99 @@
/*
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 { render, waitFor } from "jest-matrix-react";
import { mocked } from "jest-mock";
import { JoinRule, MatrixClient, PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix";
import React from "react";
import userEvent from "@testing-library/user-event";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import { stubClient } from "../../../../test-utils";
import DecoratedRoomAvatar from "../../../../../src/components/views/avatars/DecoratedRoomAvatar";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
jest.mock("../../../../../src/utils/presence", () => ({ isPresenceEnabled: jest.fn().mockReturnValue(true) }));
jest.mock("../../../../../src/utils/room/getJoinedNonFunctionalMembers", () => ({
getJoinedNonFunctionalMembers: jest.fn().mockReturnValue([0, 1]),
}));
describe("DecoratedRoomAvatar", () => {
const ROOM_ID = "roomId";
let mockClient: MatrixClient;
let room: Room;
function renderComponent() {
return render(<DecoratedRoomAvatar room={room} size="32px" />);
}
beforeEach(() => {
stubClient();
mockClient = mocked(MatrixClientPeg.safeGet());
room = new Room(ROOM_ID, mockClient, mockClient.getUserId() ?? "", {
pendingEventOrdering: PendingEventOrdering.Detached,
});
});
afterEach(() => {
jest.restoreAllMocks();
});
it("shows an avatar with globe icon and tooltip for public room", async () => {
const dmRoomMap = {
getUserIdForRoomId: jest.fn(),
} as unknown as DMRoomMap;
jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap);
room.getJoinRule = jest.fn().mockReturnValue(JoinRule.Public);
const { container, asFragment } = renderComponent();
const globe = container.querySelector(".mx_DecoratedRoomAvatar_icon_globe")!;
expect(globe).toBeVisible();
await userEvent.hover(globe!);
// wait for the tooltip to open
const tooltip = await waitFor(() => {
const tooltip = document.getElementById(globe.getAttribute("aria-labelledby")!);
expect(tooltip).toBeVisible();
return tooltip;
});
expect(tooltip).toHaveTextContent("This room is public");
expect(asFragment()).toMatchSnapshot();
});
it("shows the presence indicator in a DM room that also has functional members", async () => {
const DM_USER_ID = "@bob:foo.bar";
const dmRoomMap = {
getUserIdForRoomId: () => {
return DM_USER_ID;
},
} as unknown as DMRoomMap;
jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap);
jest.spyOn(DecoratedRoomAvatar.prototype as any, "getPresenceIcon").mockImplementation(() => "ONLINE");
const { container, asFragment } = renderComponent();
const presence = container.querySelector(".mx_DecoratedRoomAvatar_icon")!;
expect(presence).toBeVisible();
await userEvent.hover(presence!);
// wait for the tooltip to open
const tooltip = await waitFor(() => {
const tooltip = document.getElementById(presence.getAttribute("aria-labelledby")!);
expect(tooltip).toBeVisible();
return tooltip;
});
expect(tooltip).toHaveTextContent("Online");
expect(asFragment()).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,66 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { getByTestId, render, waitFor } from "jest-matrix-react";
import { mocked } from "jest-mock";
import { MatrixClient, PendingEventOrdering, Room, RoomMember } from "matrix-js-sdk/src/matrix";
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";
describe("MemberAvatar", () => {
const ROOM_ID = "roomId";
let mockClient: MatrixClient;
let room: Room;
let member: RoomMember;
function getComponent(props: Partial<ComponentProps<typeof MemberAvatar>>) {
return (
<RoomContext.Provider value={getRoomContext(room, {})}>
<MemberAvatar member={null} size="35px" {...props} />
</RoomContext.Provider>
);
}
beforeEach(() => {
jest.clearAllMocks();
stubClient();
mockClient = mocked(MatrixClientPeg.safeGet());
room = new Room(ROOM_ID, mockClient, mockClient.getUserId() ?? "", {
pendingEventOrdering: PendingEventOrdering.Detached,
});
member = new RoomMember(ROOM_ID, "@bob:example.org");
jest.spyOn(room, "getMember").mockReturnValue(member);
jest.spyOn(member, "getMxcAvatarUrl").mockReturnValue("http://placekitten.com/400/400");
});
it("shows an avatar for useOnlyCurrentProfiles", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
return settingName === "useOnlyCurrentProfiles";
});
const { container } = render(getComponent({}));
let avatar: HTMLElement;
await waitFor(() => {
avatar = getByTestId(container, "avatar-img");
expect(avatar).toBeInTheDocument();
});
expect(avatar!.getAttribute("src")).not.toBe("");
});
});

View File

@@ -0,0 +1,67 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { render } from "jest-matrix-react";
import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import { mocked } from "jest-mock";
import RoomAvatar from "../../../../../src/components/views/avatars/RoomAvatar";
import { filterConsole, stubClient } from "../../../../test-utils";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import { LocalRoom } from "../../../../../src/models/LocalRoom";
import * as AvatarModule from "../../../../../src/Avatar";
import { DirectoryMember } from "../../../../../src/utils/direct-messages";
describe("RoomAvatar", () => {
let client: MatrixClient;
filterConsole(
// unrelated for this test
"Room !room:example.com does not have an m.room.create event",
);
beforeAll(() => {
client = stubClient();
const dmRoomMap = new DMRoomMap(client);
jest.spyOn(dmRoomMap, "getUserIdForRoomId");
jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap);
jest.spyOn(AvatarModule, "defaultAvatarUrlForString");
});
afterAll(() => {
jest.restoreAllMocks();
});
afterEach(() => {
mocked(DMRoomMap.shared().getUserIdForRoomId).mockReset();
mocked(AvatarModule.defaultAvatarUrlForString).mockClear();
});
it("should render as expected for a Room", () => {
const room = new Room("!room:example.com", client, client.getSafeUserId());
room.name = "test room";
expect(render(<RoomAvatar room={room} />).container).toMatchSnapshot();
});
it("should render as expected for a DM room", () => {
const userId = "@dm_user@example.com";
const room = new Room("!room:example.com", client, client.getSafeUserId());
room.name = "DM room";
mocked(DMRoomMap.shared().getUserIdForRoomId).mockReturnValue(userId);
expect(render(<RoomAvatar room={room} />).container).toMatchSnapshot();
});
it("should render as expected for a LocalRoom", () => {
const userId = "@local_room_user@example.com";
const localRoom = new LocalRoom("!room:example.com", client, client.getSafeUserId());
localRoom.name = "local test room";
localRoom.targets.push(new DirectoryMember({ user_id: userId }));
expect(render(<RoomAvatar room={localRoom} />).container).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,102 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2024 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { render, waitFor } from "jest-matrix-react";
import { mocked } from "jest-mock";
import { MatrixClient, PendingEventOrdering, Room, RoomMember, User } from "matrix-js-sdk/src/matrix";
import React from "react";
import userEvent from "@testing-library/user-event";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import { stubClient } from "../../../../test-utils";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import WithPresenceIndicator from "../../../../../src/components/views/avatars/WithPresenceIndicator";
import { isPresenceEnabled } from "../../../../../src/utils/presence";
jest.mock("../../../../../src/utils/presence");
jest.mock("../../../../../src/utils/room/getJoinedNonFunctionalMembers", () => ({
getJoinedNonFunctionalMembers: jest.fn().mockReturnValue([1, 2]),
}));
describe("WithPresenceIndicator", () => {
const ROOM_ID = "roomId";
let mockClient: MatrixClient;
let room: Room;
function renderComponent() {
return render(
<WithPresenceIndicator room={room} size="32px">
<span />
</WithPresenceIndicator>,
);
}
beforeEach(() => {
stubClient();
mockClient = mocked(MatrixClientPeg.safeGet());
room = new Room(ROOM_ID, mockClient, mockClient.getUserId() ?? "", {
pendingEventOrdering: PendingEventOrdering.Detached,
});
const dmRoomMap = {
getUserIdForRoomId: jest.fn(),
} as unknown as DMRoomMap;
jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap);
});
afterEach(() => {
jest.restoreAllMocks();
});
it("renders only child if presence is disabled", async () => {
mocked(isPresenceEnabled).mockReturnValue(false);
const { container } = renderComponent();
expect(container.children).toHaveLength(1);
expect(container.children[0].tagName).toBe("SPAN");
});
it.each([
["online", "Online"],
["offline", "Offline"],
["unavailable", "Away"],
])("renders presence indicator with tooltip for DM rooms", async (presenceStr, renderedStr) => {
mocked(isPresenceEnabled).mockReturnValue(true);
const DM_USER_ID = "@bob:foo.bar";
const dmRoomMap = {
getUserIdForRoomId: () => {
return DM_USER_ID;
},
} as unknown as DMRoomMap;
jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap);
room.getMember = jest.fn((userId) => {
const member = new RoomMember(room.roomId, userId);
member.user = new User(userId);
member.user.presence = presenceStr;
return member;
});
const { container, asFragment } = renderComponent();
const presence = container.querySelector(".mx_WithPresenceIndicator_icon")!;
expect(presence).toBeVisible();
await userEvent.hover(presence!);
// wait for the tooltip to open
const tooltip = await waitFor(() => {
const tooltip = document.getElementById(presence.getAttribute("aria-labelledby")!);
expect(tooltip).toBeVisible();
return tooltip;
});
expect(tooltip).toHaveTextContent(renderedStr);
expect(asFragment()).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DecoratedRoomAvatar shows an avatar with globe icon and tooltip for public room 1`] = `
<DocumentFragment>
<div
class="mx_DecoratedRoomAvatar mx_DecoratedRoomAvatar_cutout"
>
<span
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
data-color="1"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 32px;"
>
r
</span>
<div
aria-labelledby="floating-ui-1"
class="mx_DecoratedRoomAvatar_icon mx_DecoratedRoomAvatar_icon_globe"
tabindex="0"
/>
</div>
</DocumentFragment>
`;
exports[`DecoratedRoomAvatar shows the presence indicator in a DM room that also has functional members 1`] = `
<DocumentFragment>
<div
class="mx_DecoratedRoomAvatar mx_DecoratedRoomAvatar_cutout"
>
<span
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
data-color="5"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 32px;"
>
r
</span>
<div
aria-labelledby="floating-ui-6"
class="mx_DecoratedRoomAvatar_icon mx_DecoratedRoomAvatar_icon_online"
tabindex="0"
/>
</div>
</DocumentFragment>
`;

View File

@@ -0,0 +1,46 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`RoomAvatar should render as expected for a DM room 1`] = `
<div>
<span
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
data-color="1"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 36px;"
>
D
</span>
</div>
`;
exports[`RoomAvatar should render as expected for a LocalRoom 1`] = `
<div>
<span
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
data-color="3"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 36px;"
>
l
</span>
</div>
`;
exports[`RoomAvatar should render as expected for a Room 1`] = `
<div>
<span
class="_avatar_mcap2_17 mx_BaseAvatar _avatar-imageless_mcap2_61"
data-color="6"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 36px;"
>
t
</span>
</div>
`;

View File

@@ -0,0 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`WithPresenceIndicator renders presence indicator with tooltip for DM rooms 1`] = `
<DocumentFragment>
<div
class="mx_WithPresenceIndicator"
>
<span />
<div
aria-labelledby="floating-ui-1"
class="mx_WithPresenceIndicator_icon mx_WithPresenceIndicator_icon_online"
style="width: 32px; height: 32px;"
tabindex="0"
/>
</div>
</DocumentFragment>
`;
exports[`WithPresenceIndicator renders presence indicator with tooltip for DM rooms 2`] = `
<DocumentFragment>
<div
class="mx_WithPresenceIndicator"
>
<span />
<div
aria-labelledby="floating-ui-6"
class="mx_WithPresenceIndicator_icon mx_WithPresenceIndicator_icon_offline"
style="width: 32px; height: 32px;"
tabindex="0"
/>
</div>
</DocumentFragment>
`;
exports[`WithPresenceIndicator renders presence indicator with tooltip for DM rooms 3`] = `
<DocumentFragment>
<div
class="mx_WithPresenceIndicator"
>
<span />
<div
aria-labelledby="floating-ui-12"
class="mx_WithPresenceIndicator_icon mx_WithPresenceIndicator_icon_away"
style="width: 32px; height: 32px;"
tabindex="0"
/>
</div>
</DocumentFragment>
`;