New room list: add more options menu on room list item (#29445)
* refactor(room list item): rename `RoomListCell` into `RoomListItemView` * refactor(room list item): move open room action to new room list item view model * feat(hover menu): add `hasAccessToOptionsMenu` * feat(hover menu): add to `RoomListItemViewModel` the condition to display or not the hover menu * feat(hover menu): add view model for the hover menu * feat(hover menu): add hover menu view * feat(hover menu): add hover menu to room list item * feat(hover menu): update i18n * test(view model list item): update test and add test to `showHoverMenu` * test(room list): update snapshot * test(room list item menu): add tests for view model * test(room list item menu): add tests for view * test(room list item): add tests * test(e2e): add tests for more options menu * chore: update compound web * test(e2e): fix typo
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { renderHook } from "jest-matrix-react";
|
||||
import { mocked } from "jest-mock";
|
||||
import { type MatrixClient, type Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { mkStubRoom, stubClient, withClientContextRenderOptions } from "../../../../test-utils";
|
||||
import { useRoomListItemMenuViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListItemMenuViewModel";
|
||||
import { hasAccessToOptionsMenu } from "../../../../../src/components/viewmodels/roomlist/utils";
|
||||
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
|
||||
import { DefaultTagID } from "../../../../../src/stores/room-list/models";
|
||||
import { useUnreadNotifications } from "../../../../../src/hooks/useUnreadNotifications";
|
||||
import { NotificationLevel } from "../../../../../src/stores/notifications/NotificationLevel";
|
||||
import { clearRoomNotification, setMarkedUnreadState } from "../../../../../src/utils/notifications";
|
||||
import { tagRoom } from "../../../../../src/utils/room/tagRoom";
|
||||
import dispatcher from "../../../../../src/dispatcher/dispatcher";
|
||||
|
||||
jest.mock("../../../../../src/components/viewmodels/roomlist/utils", () => ({
|
||||
hasAccessToOptionsMenu: jest.fn().mockReturnValue(false),
|
||||
}));
|
||||
|
||||
jest.mock("../../../../../src/hooks/useUnreadNotifications", () => ({
|
||||
useUnreadNotifications: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../../../../../src/utils/notifications", () => ({
|
||||
clearRoomNotification: jest.fn(),
|
||||
setMarkedUnreadState: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../../../../../src/utils/room/tagRoom", () => ({
|
||||
tagRoom: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("RoomListItemMenuViewModel", () => {
|
||||
let matrixClient: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
matrixClient = stubClient();
|
||||
room = mkStubRoom("roomId", "roomName", matrixClient);
|
||||
|
||||
DMRoomMap.makeShared(matrixClient);
|
||||
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(null);
|
||||
|
||||
mocked(useUnreadNotifications).mockReturnValue({ symbol: null, count: 0, level: NotificationLevel.None });
|
||||
jest.spyOn(dispatcher, "dispatch");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
function render() {
|
||||
return renderHook(() => useRoomListItemMenuViewModel(room), withClientContextRenderOptions(matrixClient));
|
||||
}
|
||||
|
||||
it("default", () => {
|
||||
const { result } = render();
|
||||
expect(result.current.showMoreOptionsMenu).toBe(false);
|
||||
expect(result.current.canInvite).toBe(false);
|
||||
expect(result.current.isFavourite).toBe(false);
|
||||
expect(result.current.canCopyRoomLink).toBe(true);
|
||||
expect(result.current.canMarkAsRead).toBe(false);
|
||||
expect(result.current.canMarkAsUnread).toBe(true);
|
||||
});
|
||||
|
||||
it("should has showMoreOptionsMenu to be true", () => {
|
||||
mocked(hasAccessToOptionsMenu).mockReturnValue(true);
|
||||
const { result } = render();
|
||||
expect(result.current.showMoreOptionsMenu).toBe(true);
|
||||
});
|
||||
|
||||
it("should be able to invite", () => {
|
||||
jest.spyOn(room, "canInvite").mockReturnValue(true);
|
||||
const { result } = render();
|
||||
expect(result.current.canInvite).toBe(true);
|
||||
});
|
||||
|
||||
it("should be a favourite", () => {
|
||||
room.tags = { [DefaultTagID.Favourite]: { order: 0 } };
|
||||
const { result } = render();
|
||||
expect(result.current.isFavourite).toBe(true);
|
||||
});
|
||||
|
||||
it("should not be able to copy the room link", () => {
|
||||
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue("userId");
|
||||
const { result } = render();
|
||||
expect(result.current.canCopyRoomLink).toBe(false);
|
||||
});
|
||||
|
||||
it("should be able to mark as read", () => {
|
||||
// Add a notification
|
||||
mocked(useUnreadNotifications).mockReturnValue({
|
||||
symbol: null,
|
||||
count: 1,
|
||||
level: NotificationLevel.Notification,
|
||||
});
|
||||
const { result } = render();
|
||||
expect(result.current.canMarkAsRead).toBe(true);
|
||||
expect(result.current.canMarkAsUnread).toBe(false);
|
||||
});
|
||||
|
||||
// Actions
|
||||
|
||||
it("should mark as read", () => {
|
||||
const { result } = render();
|
||||
result.current.markAsRead(new Event("click"));
|
||||
expect(mocked(clearRoomNotification)).toHaveBeenCalledWith(room, matrixClient);
|
||||
});
|
||||
|
||||
it("should mark as unread", () => {
|
||||
const { result } = render();
|
||||
result.current.markAsUnread(new Event("click"));
|
||||
expect(mocked(setMarkedUnreadState)).toHaveBeenCalledWith(room, matrixClient, true);
|
||||
});
|
||||
|
||||
it("should tag a room as favourite", () => {
|
||||
const { result } = render();
|
||||
result.current.toggleFavorite(new Event("click"));
|
||||
expect(mocked(tagRoom)).toHaveBeenCalledWith(room, DefaultTagID.Favourite);
|
||||
});
|
||||
|
||||
it("should tag a room as low priority", () => {
|
||||
const { result } = render();
|
||||
result.current.toggleLowPriority();
|
||||
expect(mocked(tagRoom)).toHaveBeenCalledWith(room, DefaultTagID.LowPriority);
|
||||
});
|
||||
|
||||
it("should dispatch invite action", () => {
|
||||
const { result } = render();
|
||||
result.current.invite(new Event("click"));
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
action: "view_invite",
|
||||
roomId: room.roomId,
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch a copy room action", () => {
|
||||
const { result } = render();
|
||||
result.current.copyRoomLink(new Event("click"));
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
action: "copy_room",
|
||||
room_id: room.roomId,
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch forget room action", () => {
|
||||
// forget room is only available for archived rooms
|
||||
room.tags = { [DefaultTagID.Archived]: { order: 0 } };
|
||||
|
||||
const { result } = render();
|
||||
result.current.leaveRoom(new Event("click"));
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
action: "forget_room",
|
||||
room_id: room.roomId,
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch leave room action", () => {
|
||||
const { result } = render();
|
||||
result.current.leaveRoom(new Event("click"));
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
action: "leave_room",
|
||||
room_id: room.roomId,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { renderHook } from "jest-matrix-react";
|
||||
import { type Room } from "matrix-js-sdk/src/matrix";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import dispatcher from "../../../../../src/dispatcher/dispatcher";
|
||||
import { Action } from "../../../../../src/dispatcher/actions";
|
||||
import { useRoomListItemViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListItemViewModel";
|
||||
import { createTestClient, mkStubRoom } from "../../../../test-utils";
|
||||
import { hasAccessToOptionsMenu } from "../../../../../src/components/viewmodels/roomlist/utils";
|
||||
|
||||
jest.mock("../../../../../src/components/viewmodels/roomlist/utils", () => ({
|
||||
hasAccessToOptionsMenu: jest.fn().mockReturnValue(false),
|
||||
}));
|
||||
|
||||
describe("RoomListItemViewModel", () => {
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
const matrixClient = createTestClient();
|
||||
room = mkStubRoom("roomId", "roomName", matrixClient);
|
||||
});
|
||||
|
||||
it("should dispatch view room action on openRoom", async () => {
|
||||
const { result: vm } = renderHook(() => useRoomListItemViewModel(room));
|
||||
|
||||
const fn = jest.spyOn(dispatcher, "dispatch");
|
||||
vm.current.openRoom();
|
||||
expect(fn).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
metricsTrigger: "RoomList",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("should show hover menu if user has access to options menu", async () => {
|
||||
mocked(hasAccessToOptionsMenu).mockReturnValue(true);
|
||||
const { result: vm } = renderHook(() => useRoomListItemViewModel(room));
|
||||
expect(vm.current.showHoverMenu).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -12,8 +12,6 @@ import RoomListStoreV3 from "../../../../../src/stores/room-list-v3/RoomListStor
|
||||
import { mkStubRoom } from "../../../../test-utils";
|
||||
import { LISTS_UPDATE_EVENT } from "../../../../../src/stores/room-list/SlidingRoomListStore";
|
||||
import { useRoomListViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
|
||||
import dispatcher from "../../../../../src/dispatcher/dispatcher";
|
||||
import { Action } from "../../../../../src/dispatcher/actions";
|
||||
import { FilterKey } from "../../../../../src/stores/room-list-v3/skip-list/filters";
|
||||
import { SecondaryFilters } from "../../../../../src/components/viewmodels/roomlist/useFilteredRooms";
|
||||
import { SortingAlgorithm } from "../../../../../src/stores/room-list-v3/skip-list/sorters";
|
||||
@@ -56,21 +54,6 @@ describe("RoomListViewModel", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch view room action on openRoom", async () => {
|
||||
const { rooms } = mockAndCreateRooms();
|
||||
const { result: vm } = renderHook(() => useRoomListViewModel());
|
||||
|
||||
const fn = jest.spyOn(dispatcher, "dispatch");
|
||||
act(() => vm.current.openRoom(rooms[7].roomId));
|
||||
expect(fn).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
action: Action.ViewRoom,
|
||||
room_id: rooms[7].roomId,
|
||||
metricsTrigger: "RoomList",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
describe("Filters", () => {
|
||||
it("should provide list of available filters", () => {
|
||||
mockAndCreateRooms();
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
import React from "react";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { render, screen, waitFor } from "jest-matrix-react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { render } from "jest-matrix-react";
|
||||
|
||||
import { mkRoom, stubClient } from "../../../../../test-utils";
|
||||
import { type RoomListViewState } from "../../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
|
||||
@@ -31,7 +30,6 @@ describe("<RoomList />", () => {
|
||||
const rooms = Array.from({ length: 10 }, (_, i) => mkRoom(matrixClient, `room${i}`));
|
||||
vm = {
|
||||
rooms,
|
||||
openRoom: jest.fn(),
|
||||
primaryFilters: [],
|
||||
activateSecondaryFilter: () => {},
|
||||
activeSecondaryFilter: SecondaryFilters.AllActivity,
|
||||
@@ -48,15 +46,4 @@ describe("<RoomList />", () => {
|
||||
const { asFragment } = render(<RoomList vm={vm} />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should open the room", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(<RoomList vm={vm} />);
|
||||
await waitFor(async () => {
|
||||
expect(screen.getByRole("gridcell", { name: "Open room room9" })).toBeVisible();
|
||||
await user.click(screen.getByRole("gridcell", { name: "Open room room9" }));
|
||||
});
|
||||
expect(vm.openRoom).toHaveBeenCalledWith(vm.rooms[9].roomId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { type MatrixClient, type Room } from "matrix-js-sdk/src/matrix";
|
||||
import { render, screen } from "jest-matrix-react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import { mkRoom, stubClient } from "../../../../../test-utils";
|
||||
import { RoomListCell } from "../../../../../../src/components/views/rooms/RoomListPanel/RoomListCell";
|
||||
import DMRoomMap from "../../../../../../src/utils/DMRoomMap";
|
||||
|
||||
describe("<RoomListCell />", () => {
|
||||
let matrixClient: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
matrixClient = stubClient();
|
||||
room = mkRoom(matrixClient, "room1");
|
||||
|
||||
DMRoomMap.makeShared(matrixClient);
|
||||
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(null);
|
||||
});
|
||||
|
||||
test("should render a room cell", () => {
|
||||
const onClick = jest.fn();
|
||||
const { asFragment } = render(<RoomListCell room={room} onClick={onClick} />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("should call onClick when clicked", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
const onClick = jest.fn();
|
||||
render(<RoomListCell room={room} onClick={onClick} />);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: `Open room ${room.name}` }));
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { mocked } from "jest-mock";
|
||||
import { render, screen } from "jest-matrix-react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import {
|
||||
type RoomListItemMenuViewState,
|
||||
useRoomListItemMenuViewModel,
|
||||
} from "../../../../../../src/components/viewmodels/roomlist/RoomListItemMenuViewModel";
|
||||
import type { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { mkRoom, stubClient } from "../../../../../test-utils";
|
||||
import { RoomListItemMenuView } from "../../../../../../src/components/views/rooms/RoomListPanel/RoomListItemMenuView";
|
||||
|
||||
jest.mock("../../../../../../src/components/viewmodels/roomlist/RoomListItemMenuViewModel", () => ({
|
||||
useRoomListItemMenuViewModel: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("<RoomListItemMenuView />", () => {
|
||||
const defaultValue: RoomListItemMenuViewState = {
|
||||
showMoreOptionsMenu: true,
|
||||
isFavourite: true,
|
||||
canInvite: true,
|
||||
canMarkAsUnread: true,
|
||||
canMarkAsRead: true,
|
||||
canCopyRoomLink: true,
|
||||
copyRoomLink: jest.fn(),
|
||||
markAsUnread: jest.fn(),
|
||||
markAsRead: jest.fn(),
|
||||
leaveRoom: jest.fn(),
|
||||
toggleLowPriority: jest.fn(),
|
||||
toggleFavorite: jest.fn(),
|
||||
invite: jest.fn(),
|
||||
};
|
||||
|
||||
let matrixClient: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
mocked(useRoomListItemMenuViewModel).mockReturnValue(defaultValue);
|
||||
matrixClient = stubClient();
|
||||
room = mkRoom(matrixClient, "room1");
|
||||
});
|
||||
|
||||
function renderMenu(setMenuOpen = jest.fn()) {
|
||||
return render(<RoomListItemMenuView room={room} setMenuOpen={setMenuOpen} />);
|
||||
}
|
||||
|
||||
it("should render the more options menu", () => {
|
||||
const { asFragment } = renderMenu();
|
||||
expect(screen.getByRole("button", { name: "More Options" })).toBeInTheDocument();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should not render the more options menu when showMoreOptionsMenu is false", () => {
|
||||
mocked(useRoomListItemMenuViewModel).mockReturnValue({ ...defaultValue, showMoreOptionsMenu: false });
|
||||
renderMenu();
|
||||
expect(screen.queryByRole("button", { name: "More Options" })).toBeNull();
|
||||
});
|
||||
|
||||
it("should call setMenuOpen when the menu is opened", async () => {
|
||||
const user = userEvent.setup();
|
||||
const setMenuOpen = jest.fn();
|
||||
renderMenu(setMenuOpen);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "More Options" }));
|
||||
expect(setMenuOpen).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it("should display all the buttons and have the actions linked", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderMenu();
|
||||
|
||||
const openMenu = screen.getByRole("button", { name: "More Options" });
|
||||
await user.click(openMenu);
|
||||
|
||||
await user.click(screen.getByRole("menuitem", { name: "Mark as read" }));
|
||||
expect(defaultValue.markAsRead).toHaveBeenCalled();
|
||||
|
||||
await user.click(openMenu);
|
||||
await user.click(screen.getByRole("menuitem", { name: "Mark as unread" }));
|
||||
expect(defaultValue.markAsUnread).toHaveBeenCalled();
|
||||
|
||||
await user.click(openMenu);
|
||||
await user.click(screen.getByRole("menuitemcheckbox", { name: "Favourited" }));
|
||||
expect(defaultValue.toggleFavorite).toHaveBeenCalled();
|
||||
|
||||
await user.click(openMenu);
|
||||
await user.click(screen.getByRole("menuitem", { name: "Low priority" }));
|
||||
expect(defaultValue.toggleLowPriority).toHaveBeenCalled();
|
||||
|
||||
await user.click(openMenu);
|
||||
await user.click(screen.getByRole("menuitem", { name: "Invite" }));
|
||||
expect(defaultValue.invite).toHaveBeenCalled();
|
||||
|
||||
await user.click(openMenu);
|
||||
await user.click(screen.getByRole("menuitem", { name: "Copy room link" }));
|
||||
expect(defaultValue.copyRoomLink).toHaveBeenCalled();
|
||||
|
||||
await user.click(openMenu);
|
||||
await user.click(screen.getByRole("menuitem", { name: "Leave room" }));
|
||||
expect(defaultValue.leaveRoom).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { type MatrixClient, type Room } from "matrix-js-sdk/src/matrix";
|
||||
import { render, screen, waitFor } from "jest-matrix-react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import { mkRoom, stubClient, withClientContextRenderOptions } from "../../../../../test-utils";
|
||||
import { RoomListItemView } from "../../../../../../src/components/views/rooms/RoomListPanel/RoomListItemView";
|
||||
import DMRoomMap from "../../../../../../src/utils/DMRoomMap";
|
||||
import {
|
||||
type RoomListItemViewState,
|
||||
useRoomListItemViewModel,
|
||||
} from "../../../../../../src/components/viewmodels/roomlist/RoomListItemViewModel";
|
||||
|
||||
jest.mock("../../../../../../src/components/viewmodels/roomlist/RoomListItemViewModel", () => ({
|
||||
useRoomListItemViewModel: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("<RoomListItemView />", () => {
|
||||
const defaultValue: RoomListItemViewState = {
|
||||
openRoom: jest.fn(),
|
||||
showHoverMenu: false,
|
||||
};
|
||||
let matrixClient: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
mocked(useRoomListItemViewModel).mockReturnValue(defaultValue);
|
||||
matrixClient = stubClient();
|
||||
room = mkRoom(matrixClient, "room1");
|
||||
|
||||
DMRoomMap.makeShared(matrixClient);
|
||||
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(null);
|
||||
});
|
||||
|
||||
test("should render a room item", () => {
|
||||
const onClick = jest.fn();
|
||||
const { asFragment } = render(<RoomListItemView room={room} onClick={onClick} />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("should call openRoom when clicked", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<RoomListItemView room={room} />);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: `Open room ${room.name}` }));
|
||||
expect(defaultValue.openRoom).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should hover decoration if hovered", async () => {
|
||||
mocked(useRoomListItemViewModel).mockReturnValue({ ...defaultValue, showHoverMenu: true });
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<RoomListItemView room={room} />, withClientContextRenderOptions(matrixClient));
|
||||
const listItem = screen.getByRole("button", { name: `Open room ${room.name}` });
|
||||
expect(screen.queryByRole("button", { name: "More Options" })).toBeNull();
|
||||
|
||||
await user.hover(listItem);
|
||||
await waitFor(() => expect(screen.getByRole("button", { name: "More Options" })).toBeInTheDocument());
|
||||
});
|
||||
});
|
||||
@@ -20,7 +20,6 @@ describe("<RoomListPrimaryFilters />", () => {
|
||||
beforeEach(() => {
|
||||
vm = {
|
||||
rooms: [],
|
||||
openRoom: jest.fn(),
|
||||
primaryFilters: [
|
||||
{ name: "People", active: false, toggle: jest.fn() },
|
||||
{ name: "Rooms", active: true, toggle: jest.fn() },
|
||||
|
||||
@@ -24,13 +24,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-label="Open room room0"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 0px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -57,8 +57,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room0"
|
||||
@@ -70,13 +70,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room1"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 48px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -103,8 +103,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room1"
|
||||
@@ -116,13 +116,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room2"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 96px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -149,8 +149,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room2"
|
||||
@@ -162,13 +162,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room3"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 144px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -195,8 +195,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room3"
|
||||
@@ -208,13 +208,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room4"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 192px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -241,8 +241,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room4"
|
||||
@@ -254,13 +254,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room5"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 240px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -287,8 +287,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room5"
|
||||
@@ -300,13 +300,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room6"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 288px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -333,8 +333,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room6"
|
||||
@@ -346,13 +346,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room7"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 336px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -379,8 +379,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room7"
|
||||
@@ -392,13 +392,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room8"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 384px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -425,8 +425,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room8"
|
||||
@@ -438,13 +438,13 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-label="Open room room9"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
role="gridcell"
|
||||
style="height: 48px; left: 0px; position: absolute; top: 432px; width: 100%;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -471,8 +471,8 @@ exports[`<RoomList /> should render a room list 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room9"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<RoomListItemMenuView /> should render the more options menu 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListItemMenuView"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-1x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="menu"
|
||||
aria-label="More Options"
|
||||
aria-labelledby=":r2:"
|
||||
class="_icon-button_m2erp_8"
|
||||
data-state="closed"
|
||||
id="radix-:r0:"
|
||||
role="button"
|
||||
style="--cpd-icon-button-size: 32px;"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="_indicator-icon_zr2a0_17"
|
||||
style="--cpd-icon-button-size: 100%;"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 14q-.824 0-1.412-.588A1.93 1.93 0 0 1 4 12q0-.825.588-1.412A1.93 1.93 0 0 1 6 10q.824 0 1.412.588Q8 11.175 8 12t-.588 1.412A1.93 1.93 0 0 1 6 14m6 0q-.825 0-1.412-.588A1.93 1.93 0 0 1 10 12q0-.825.588-1.412A1.93 1.93 0 0 1 12 10q.825 0 1.412.588Q14 11.175 14 12t-.588 1.412A1.93 1.93 0 0 1 12 14m6 0q-.824 0-1.413-.588A1.93 1.93 0 0 1 16 12q0-.825.587-1.412A1.93 1.93 0 0 1 18 10q.824 0 1.413.588Q20 11.175 20 12t-.587 1.412A1.93 1.93 0 0 1 18 14"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -1,14 +1,14 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<RoomListCell /> should render a room cell 1`] = `
|
||||
exports[`<RoomListItemView /> should render a room item 1`] = `
|
||||
<DocumentFragment>
|
||||
<button
|
||||
aria-label="Open room room1"
|
||||
class="mx_RoomListCell"
|
||||
class="mx_RoomListItemView"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_container"
|
||||
class="mx_Flex mx_RoomListItemView_container"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
@@ -35,8 +35,8 @@ exports[`<RoomListCell /> should render a room cell 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_Flex mx_RoomListCell_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 0; --mx-flex-wrap: nowrap;"
|
||||
class="mx_Flex mx_RoomListItemView_content"
|
||||
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
|
||||
>
|
||||
<span
|
||||
title="room1"
|
||||
Reference in New Issue
Block a user