element-web/test/unit-tests/components/views/rooms/RoomList-test.tsx

275 lines
13 KiB
TypeScript

/*
Copyright 2024 New Vector Ltd.
Copyright 2023 Mikhail Aheichyk
Copyright 2023 Nordeck IT + Consulting GmbH.
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 { cleanup, queryByRole, render, screen, within } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { mocked } from "jest-mock";
import { Room } from "matrix-js-sdk/src/matrix";
import RoomList from "../../../../../src/components/views/rooms/RoomList";
import ResizeNotifier from "../../../../../src/utils/ResizeNotifier";
import { MetaSpace } from "../../../../../src/stores/spaces";
import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents";
import { UIComponent } from "../../../../../src/settings/UIFeature";
import dis from "../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../src/dispatcher/actions";
import * as testUtils from "../../../../test-utils";
import { mkSpace, stubClient } from "../../../../test-utils";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import SpaceStore from "../../../../../src/stores/spaces/SpaceStore";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import RoomListStore from "../../../../../src/stores/room-list/RoomListStore";
import { ITagMap } from "../../../../../src/stores/room-list/algorithms/models";
import { DefaultTagID } from "../../../../../src/stores/room-list/models";
jest.mock("../../../../../src/customisations/helpers/UIComponents", () => ({
shouldShowComponent: jest.fn(),
}));
jest.mock("../../../../../src/dispatcher/dispatcher");
const getUserIdForRoomId = jest.fn();
const getDMRoomsForUserId = jest.fn();
// @ts-ignore
DMRoomMap.sharedInstance = { getUserIdForRoomId, getDMRoomsForUserId };
describe("RoomList", () => {
stubClient();
const client = MatrixClientPeg.safeGet();
const store = SpaceStore.instance;
function getComponent(props: Partial<RoomList["props"]> = {}): JSX.Element {
return (
<RoomList
onKeyDown={jest.fn()}
onFocus={jest.fn()}
onBlur={jest.fn()}
onResize={jest.fn()}
resizeNotifier={new ResizeNotifier()}
isMinimized={false}
activeSpace={MetaSpace.Home}
{...props}
/>
);
}
describe("Rooms", () => {
describe("when meta space is active", () => {
beforeEach(() => {
store.setActiveSpace(MetaSpace.Home);
});
it("does not render add room button when UIComponent customisation disables CreateRooms and ExploreRooms", () => {
const disabled: UIComponent[] = [UIComponent.CreateRooms, UIComponent.ExploreRooms];
mocked(shouldShowComponent).mockImplementation((feature) => !disabled.includes(feature));
render(getComponent());
const roomsList = screen.getByRole("group", { name: "Rooms" });
expect(within(roomsList).queryByRole("button", { name: "Add room" })).not.toBeInTheDocument();
});
it("renders add room button with menu when UIComponent customisation allows CreateRooms or ExploreRooms", async () => {
let disabled: UIComponent[] = [];
mocked(shouldShowComponent).mockImplementation((feature) => !disabled.includes(feature));
const { rerender } = render(getComponent());
const roomsList = screen.getByRole("group", { name: "Rooms" });
const addRoomButton = within(roomsList).getByRole("button", { name: "Add room" });
expect(screen.queryByRole("menu")).not.toBeInTheDocument();
await userEvent.click(addRoomButton);
const menu = screen.getByRole("menu");
expect(within(menu).getByRole("menuitem", { name: "New room" })).toBeInTheDocument();
expect(within(menu).getByRole("menuitem", { name: "Explore public rooms" })).toBeInTheDocument();
disabled = [UIComponent.CreateRooms];
rerender(getComponent());
expect(addRoomButton).toBeInTheDocument();
expect(menu).toBeInTheDocument();
expect(within(menu).queryByRole("menuitem", { name: "New room" })).not.toBeInTheDocument();
expect(within(menu).getByRole("menuitem", { name: "Explore public rooms" })).toBeInTheDocument();
disabled = [UIComponent.ExploreRooms];
rerender(getComponent());
expect(addRoomButton).toBeInTheDocument();
expect(menu).toBeInTheDocument();
expect(within(menu).getByRole("menuitem", { name: "New room" })).toBeInTheDocument();
expect(within(menu).queryByRole("menuitem", { name: "Explore public rooms" })).not.toBeInTheDocument();
});
it("renders add room button and clicks explore public rooms", async () => {
mocked(shouldShowComponent).mockReturnValue(true);
render(getComponent());
const roomsList = screen.getByRole("group", { name: "Rooms" });
await userEvent.click(within(roomsList).getByRole("button", { name: "Add room" }));
const menu = screen.getByRole("menu");
await userEvent.click(within(menu).getByRole("menuitem", { name: "Explore public rooms" }));
expect(dis.fire).toHaveBeenCalledWith(Action.ViewRoomDirectory);
});
});
describe("when room space is active", () => {
let rooms: Room[];
const mkSpaceForRooms = (spaceId: string, children: string[] = []) =>
mkSpace(client, spaceId, rooms, children);
const space1 = "!space1:server";
beforeEach(async () => {
rooms = [];
mkSpaceForRooms(space1);
mocked(client).getRoom.mockImplementation(
(roomId) => rooms.find((room) => room.roomId === roomId) || null,
);
await testUtils.setupAsyncStoreWithClient(store, client);
store.setActiveSpace(space1);
});
it("does not render add room button when UIComponent customisation disables CreateRooms and ExploreRooms", () => {
const disabled: UIComponent[] = [UIComponent.CreateRooms, UIComponent.ExploreRooms];
mocked(shouldShowComponent).mockImplementation((feature) => !disabled.includes(feature));
render(getComponent());
const roomsList = screen.getByRole("group", { name: "Rooms" });
expect(within(roomsList).queryByRole("button", { name: "Add room" })).not.toBeInTheDocument();
});
it("renders add room button with menu when UIComponent customisation allows CreateRooms or ExploreRooms", async () => {
let disabled: UIComponent[] = [];
mocked(shouldShowComponent).mockImplementation((feature) => !disabled.includes(feature));
const { rerender } = render(getComponent());
const roomsList = screen.getByRole("group", { name: "Rooms" });
const addRoomButton = within(roomsList).getByRole("button", { name: "Add room" });
expect(screen.queryByRole("menu")).not.toBeInTheDocument();
await userEvent.click(addRoomButton);
const menu = screen.getByRole("menu");
expect(within(menu).getByRole("menuitem", { name: "Explore rooms" })).toBeInTheDocument();
expect(within(menu).getByRole("menuitem", { name: "New room" })).toBeInTheDocument();
expect(within(menu).getByRole("menuitem", { name: "Add existing room" })).toBeInTheDocument();
disabled = [UIComponent.CreateRooms];
rerender(getComponent());
expect(addRoomButton).toBeInTheDocument();
expect(menu).toBeInTheDocument();
expect(within(menu).getByRole("menuitem", { name: "Explore rooms" })).toBeInTheDocument();
expect(within(menu).queryByRole("menuitem", { name: "New room" })).not.toBeInTheDocument();
expect(within(menu).queryByRole("menuitem", { name: "Add existing room" })).not.toBeInTheDocument();
disabled = [UIComponent.ExploreRooms];
rerender(getComponent());
expect(addRoomButton).toBeInTheDocument();
expect(menu).toBeInTheDocument();
expect(within(menu).queryByRole("menuitem", { name: "Explore rooms" })).toBeInTheDocument();
expect(within(menu).getByRole("menuitem", { name: "New room" })).toBeInTheDocument();
expect(within(menu).getByRole("menuitem", { name: "Add existing room" })).toBeInTheDocument();
});
it("renders add room button and clicks explore rooms", async () => {
mocked(shouldShowComponent).mockReturnValue(true);
render(getComponent());
const roomsList = screen.getByRole("group", { name: "Rooms" });
await userEvent.click(within(roomsList).getByRole("button", { name: "Add room" }));
const menu = screen.getByRole("menu");
await userEvent.click(within(menu).getByRole("menuitem", { name: "Explore rooms" }));
expect(dis.dispatch).toHaveBeenCalledWith({
action: Action.ViewRoom,
room_id: space1,
});
});
});
describe("when video meta space is active", () => {
const videoRoomPrivate = "!videoRoomPrivate_server";
const videoRoomPublic = "!videoRoomPublic_server";
const videoRoomKnock = "!videoRoomKnock_server";
beforeEach(async () => {
cleanup();
const rooms: Room[] = [];
RoomListStore.instance;
testUtils.mkRoom(client, videoRoomPrivate, rooms);
testUtils.mkRoom(client, videoRoomPublic, rooms);
testUtils.mkRoom(client, videoRoomKnock, rooms);
mocked(client).getRoom.mockImplementation(
(roomId) => rooms.find((room) => room.roomId === roomId) || null,
);
mocked(client).getRooms.mockImplementation(() => rooms);
const videoRoomKnockRoom = client.getRoom(videoRoomKnock)!;
const videoRoomPrivateRoom = client.getRoom(videoRoomPrivate)!;
const videoRoomPublicRoom = client.getRoom(videoRoomPublic)!;
[videoRoomPrivateRoom, videoRoomPublicRoom, videoRoomKnockRoom].forEach((room) => {
(room.isCallRoom as jest.Mock).mockReturnValue(true);
});
const roomLists: ITagMap = {};
roomLists[DefaultTagID.Conference] = [videoRoomKnockRoom, videoRoomPublicRoom];
roomLists[DefaultTagID.Untagged] = [videoRoomPrivateRoom];
jest.spyOn(RoomListStore.instance, "orderedLists", "get").mockReturnValue(roomLists);
await testUtils.setupAsyncStoreWithClient(store, client);
store.setActiveSpace(MetaSpace.VideoRooms);
});
it("renders Conferences and Room but no People section", () => {
const renderResult = render(getComponent({ activeSpace: MetaSpace.VideoRooms }));
const roomsEl = renderResult.getByRole("treeitem", { name: "Rooms" });
const conferenceEl = renderResult.getByRole("treeitem", { name: "Conferences" });
const noInvites = screen.queryByRole("treeitem", { name: "Invites" });
const noFavourites = screen.queryByRole("treeitem", { name: "Favourites" });
const noPeople = screen.queryByRole("treeitem", { name: "People" });
const noLowPriority = screen.queryByRole("treeitem", { name: "Low priority" });
const noHistorical = screen.queryByRole("treeitem", { name: "Historical" });
expect(roomsEl).toBeVisible();
expect(conferenceEl).toBeVisible();
expect(noInvites).toBeFalsy();
expect(noFavourites).toBeFalsy();
expect(noPeople).toBeFalsy();
expect(noLowPriority).toBeFalsy();
expect(noHistorical).toBeFalsy();
});
it("renders Public and Knock rooms in Conferences section", () => {
const renderResult = render(getComponent({ activeSpace: MetaSpace.VideoRooms }));
const conferenceList = renderResult.getByRole("group", { name: "Conferences" });
expect(queryByRole(conferenceList, "treeitem", { name: videoRoomPublic })).toBeVisible();
expect(queryByRole(conferenceList, "treeitem", { name: videoRoomKnock })).toBeVisible();
expect(queryByRole(conferenceList, "treeitem", { name: videoRoomPrivate })).toBeFalsy();
const roomsList = renderResult.getByRole("group", { name: "Rooms" });
expect(queryByRole(roomsList, "treeitem", { name: videoRoomPrivate })).toBeVisible();
expect(queryByRole(roomsList, "treeitem", { name: videoRoomPublic })).toBeFalsy();
expect(queryByRole(roomsList, "treeitem", { name: videoRoomKnock })).toBeFalsy();
});
});
});
});