From f95218e2b7e38c78fed3ff199a339f0080f2b69f Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Tue, 25 Feb 2025 15:06:01 +0100 Subject: [PATCH] New room list: add space menu in room header (#29352) * feat(new room list): add space menu in view model * test(new room list): add space menu in view model * feat(new room list): add space menu in room list header * chore: update i18n * test(new room list): add tests for space menu * test(new room list): update room list tests * test(e2e): add tests for space menu --- .../room-list-view/room-list-header.spec.ts | 31 ++- .../room-list-header-space-menu-linux.png | Bin 0 -> 11343 bytes .../room-list-space-header-linux.png | Bin 0 -> 3186 bytes .../RoomListView/_RoomListHeaderView.pcss | 12 + .../roomlist/RoomListHeaderViewModel.tsx | 82 ++++++- .../rooms/RoomListView/RoomListHeaderView.tsx | 51 +++- src/i18n/strings/en_EN.json | 5 + .../roomlist/RoomListHeaderViewModel-test.tsx | 103 +++++++- .../RoomListView/RoomListHeaderView-test.tsx | 153 ++++++++---- .../RoomListHeaderView-test.tsx.snap | 228 +++++++++++++++++- .../__snapshots__/RoomListView-test.tsx.snap | 22 +- 11 files changed, 611 insertions(+), 76 deletions(-) create mode 100644 playwright/snapshots/left-panel/room-list-view/room-list-header.spec.ts/room-list-header-space-menu-linux.png create mode 100644 playwright/snapshots/left-panel/room-list-view/room-list-header.spec.ts/room-list-space-header-linux.png diff --git a/playwright/e2e/left-panel/room-list-view/room-list-header.spec.ts b/playwright/e2e/left-panel/room-list-view/room-list-header.spec.ts index 2f4ef6f001..daa8d3869f 100644 --- a/playwright/e2e/left-panel/room-list-view/room-list-header.spec.ts +++ b/playwright/e2e/left-panel/room-list-view/room-list-header.spec.ts @@ -47,12 +47,41 @@ test.describe("Header section of the room list", () => { await app.closeDialog(); }); - test("should render the header section for a space", async ({ page, app, user }) => { + test("should render the header section for a space", { tag: "@screenshot" }, async ({ page, app, user }) => { await app.client.createSpace({ name: "MySpace" }); await page.getByRole("button", { name: "MySpace" }).click(); const roomListHeader = getHeaderSection(page); + await expect(roomListHeader).toMatchScreenshot("room-list-space-header.png"); + await expect(roomListHeader.getByRole("heading", { name: "MySpace" })).toBeVisible(); await expect(roomListHeader.getByRole("button", { name: "Add" })).toBeVisible(); + + const spaceMenu = roomListHeader.getByRole("button", { name: "Open space menu" }); + await spaceMenu.click(); + + await expect(page.getByRole("menu")).toMatchScreenshot("room-list-header-space-menu.png"); + + // It should open the space home + await page.getByRole("menuitem", { name: "Space home" }).click(); + await expect(page.getByRole("main").getByRole("heading", { name: "MySpace" })).toBeVisible(); + + // It should open the invite dialog + await spaceMenu.click(); + await page.getByRole("menuitem", { name: "Invite" }).click(); + await expect(page.getByRole("heading", { name: "Invite to MySpace" })).toBeVisible(); + await app.closeDialog(); + + // It should open the space preferences + await spaceMenu.click(); + await page.getByRole("menuitem", { name: "Preferences" }).click(); + await expect(page.getByRole("heading", { name: "Preferences" })).toBeVisible(); + await app.closeDialog(); + + // It should open the space settings + await spaceMenu.click(); + await page.getByRole("menuitem", { name: "Space Settings" }).click(); + await expect(page.getByRole("heading", { name: "Settings" })).toBeVisible(); + await app.closeDialog(); }); }); diff --git a/playwright/snapshots/left-panel/room-list-view/room-list-header.spec.ts/room-list-header-space-menu-linux.png b/playwright/snapshots/left-panel/room-list-view/room-list-header.spec.ts/room-list-header-space-menu-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..d2934c2a7695a9031a69ceee4d8a25f2a124e28d GIT binary patch literal 11343 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 Gum1+lz$GyN literal 0 HcmV?d00001 diff --git a/playwright/snapshots/left-panel/room-list-view/room-list-header.spec.ts/room-list-space-header-linux.png b/playwright/snapshots/left-panel/room-list-view/room-list-header.spec.ts/room-list-space-header-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..bdb7f8fa2a499d7c0ffc4767c405d1b0945c0d5c GIT binary patch literal 3186 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 void; + /** + * Open the active space home + */ + openSpaceHome: () => void; + /** + * Display the space invite dialog + */ + inviteInSpace: () => void; + /** + * Open the space preferences + */ + openSpacePreferences: () => void; + /** + * Open the space settings + */ + openSpaceSettings: () => void; } /** * View model for the RoomListHeader. */ export function useRoomListHeaderViewModel(): RoomListHeaderViewState { + const matrixClient = useMatrixClientContext(); const { activeSpace, title } = useSpace(); const canCreateRoom = shouldShowComponent(UIComponent.CreateRooms); const canCreateVideoRoom = useFeatureEnabled("feature_video_rooms"); const displayComposeMenu = canCreateRoom; + const displaySpaceMenu = Boolean(activeSpace); + const canInviteInSpace = Boolean( + activeSpace?.getJoinRule() === JoinRule.Public || activeSpace?.canInvite(matrixClient.getSafeUserId()), + ); + const canAccessSpaceSettings = Boolean(activeSpace && shouldShowSpaceSettings(activeSpace)); /* Actions */ @@ -125,13 +168,48 @@ export function useRoomListHeaderViewModel(): RoomListHeaderViewState { } }, [activeSpace, elementCallVideoRoomsEnabled]); + const openSpaceHome = useCallback(() => { + // openSpaceHome is only available when there is an active space + if (!activeSpace) return; + defaultDispatcher.dispatch({ + action: Action.ViewRoom, + room_id: activeSpace.roomId, + metricsTrigger: undefined, + }); + }, [activeSpace]); + + const inviteInSpace = useCallback(() => { + // inviteInSpace is only available when there is an active space + if (!activeSpace) return; + showSpaceInvite(activeSpace); + }, [activeSpace]); + + const openSpacePreferences = useCallback(() => { + // openSpacePreferences is only available when there is an active space + if (!activeSpace) return; + showSpacePreferences(activeSpace); + }, [activeSpace]); + + const openSpaceSettings = useCallback(() => { + // openSpaceSettings is only available when there is an active space + if (!activeSpace) return; + showSpaceSettings(activeSpace); + }, [activeSpace]); + return { title, displayComposeMenu, + displaySpaceMenu, canCreateRoom, canCreateVideoRoom, + canInviteInSpace, + canAccessSpaceSettings, createChatRoom, createRoom, createVideoRoom, + openSpaceHome, + inviteInSpace, + openSpacePreferences, + openSpaceSettings, }; } diff --git a/src/components/views/rooms/RoomListView/RoomListHeaderView.tsx b/src/components/views/rooms/RoomListView/RoomListHeaderView.tsx index 478b9b7e70..7c82dabc2a 100644 --- a/src/components/views/rooms/RoomListView/RoomListHeaderView.tsx +++ b/src/components/views/rooms/RoomListView/RoomListHeaderView.tsx @@ -8,7 +8,11 @@ import React, { type JSX, useState } from "react"; import { IconButton, Menu, MenuItem } from "@vector-im/compound-web"; import ComposeIcon from "@vector-im/compound-design-tokens/assets/web/icons/compose"; import UserAddIcon from "@vector-im/compound-design-tokens/assets/web/icons/user-add"; +import ChevronDownIcon from "@vector-im/compound-design-tokens/assets/web/icons/chevron-down"; import RoomIcon from "@vector-im/compound-design-tokens/assets/web/icons/room"; +import HomeIcon from "@vector-im/compound-design-tokens/assets/web/icons/home"; +import PreferencesIcon from "@vector-im/compound-design-tokens/assets/web/icons/preferences"; +import SettingsIcon from "@vector-im/compound-design-tokens/assets/web/icons/settings"; import VideoCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call"; import { _t } from "../../../../languageHandler"; @@ -34,12 +38,57 @@ export function RoomListHeaderView(): JSX.Element { align="center" data-testid="room-list-header" > -

{vm.title}

+ +

{vm.title}

+ {vm.displaySpaceMenu && } +
{vm.displayComposeMenu && } ); } +interface SpaceMenuProps { + /** + * The view model for the room list header + */ + vm: RoomListHeaderViewState; +} + +/** + * The space menu for the room list header + */ +function SpaceMenu({ vm }: SpaceMenuProps): JSX.Element { + const [open, setOpen] = useState(false); + + return ( + + + + } + > + + {vm.canInviteInSpace && ( + + )} + + {vm.canAccessSpaceSettings && ( + + )} + + ); +} + interface ComposeMenuProps { /** * The view model for the room list header diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d4ab22771e..624beab0b8 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2098,6 +2098,7 @@ "other": "Currently joining %(count)s rooms" }, "notification_options": "Notification options", + "open_space_menu": "Open space menu", "redacting_messages_status": { "one": "Currently removing messages in %(count)s room", "other": "Currently removing messages in %(count)s rooms" @@ -2112,6 +2113,10 @@ "sort_by_activity": "Activity", "sort_by_alphabet": "A-Z", "sort_unread_first": "Show rooms with unread messages first", + "space_menu": { + "home": "Space home", + "space_settings": "Space Settings" + }, "space_menu_label": "%(spaceName)s menu", "sublist_options": "List options", "suggested_rooms_heading": "Suggested Rooms" diff --git a/test/unit-tests/components/viewmodels/roomlist/RoomListHeaderViewModel-test.tsx b/test/unit-tests/components/viewmodels/roomlist/RoomListHeaderViewModel-test.tsx index fe96e26861..43b7cb2b7d 100644 --- a/test/unit-tests/components/viewmodels/roomlist/RoomListHeaderViewModel-test.tsx +++ b/test/unit-tests/components/viewmodels/roomlist/RoomListHeaderViewModel-test.tsx @@ -6,24 +6,34 @@ */ import { renderHook } from "jest-matrix-react"; -import { type MatrixClient, type Room, RoomType } from "matrix-js-sdk/src/matrix"; +import { JoinRule, type MatrixClient, type Room, RoomType } from "matrix-js-sdk/src/matrix"; import { mocked } from "jest-mock"; import { useRoomListHeaderViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListHeaderViewModel"; import SpaceStore from "../../../../../src/stores/spaces/SpaceStore"; -import { mkStubRoom, stubClient } from "../../../../test-utils"; +import { mkStubRoom, stubClient, withClientContextRenderOptions } from "../../../../test-utils"; import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents"; import SettingsStore from "../../../../../src/settings/SettingsStore"; import defaultDispatcher from "../../../../../src/dispatcher/dispatcher"; import { Action } from "../../../../../src/dispatcher/actions"; -import { showCreateNewRoom } from "../../../../../src/utils/space"; +import { + shouldShowSpaceSettings, + showCreateNewRoom, + showSpaceInvite, + showSpacePreferences, + showSpaceSettings, +} from "../../../../../src/utils/space"; jest.mock("../../../../../src/customisations/helpers/UIComponents", () => ({ shouldShowComponent: jest.fn(), })); jest.mock("../../../../../src/utils/space", () => ({ + shouldShowSpaceSettings: jest.fn(), showCreateNewRoom: jest.fn(), + showSpaceInvite: jest.fn(), + showSpacePreferences: jest.fn(), + showSpaceSettings: jest.fn(), })); describe("useRoomListHeaderViewModel", () => { @@ -39,15 +49,19 @@ describe("useRoomListHeaderViewModel", () => { jest.resetAllMocks(); }); + function render() { + return renderHook(() => useRoomListHeaderViewModel(), withClientContextRenderOptions(matrixClient)); + } + describe("title", () => { it("should return Home as title", () => { - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); expect(result.current.title).toStrictEqual("Home"); }); it("should return the current space name as title", () => { jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); expect(result.current.title).toStrictEqual("spaceName"); }); @@ -55,7 +69,7 @@ describe("useRoomListHeaderViewModel", () => { it("should be displayComposeMenu=true and canCreateRoom=true if the user can creates room", () => { mocked(shouldShowComponent).mockReturnValue(false); - const { result, rerender } = renderHook(() => useRoomListHeaderViewModel()); + const { result, rerender } = render(); expect(result.current.displayComposeMenu).toBe(false); expect(result.current.canCreateRoom).toBe(false); @@ -65,15 +79,45 @@ describe("useRoomListHeaderViewModel", () => { expect(result.current.canCreateRoom).toBe(true); }); + it("should be displaySpaceMenu=true if the user is in a space", () => { + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + const { result } = render(); + expect(result.current.displaySpaceMenu).toBe(true); + }); + + it("should be canInviteInSpace=true if the space join rule is public", () => { + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + jest.spyOn(space, "getJoinRule").mockReturnValue(JoinRule.Public); + + const { result } = render(); + expect(result.current.displaySpaceMenu).toBe(true); + }); + + it("should be canInviteInSpace=true if the user has the right", () => { + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + jest.spyOn(space, "canInvite").mockReturnValue(true); + + const { result } = render(); + expect(result.current.displaySpaceMenu).toBe(true); + }); + + it("should be canAccessSpaceSettings=true if the user has the right", () => { + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + mocked(shouldShowSpaceSettings).mockReturnValue(true); + + const { result } = render(); + expect(result.current.canAccessSpaceSettings).toBe(true); + }); + it("should be canCreateVideoRoom=true if feature_video_rooms is enabled", () => { jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); expect(result.current.canCreateVideoRoom).toBe(true); }); it("should fire Action.CreateChat when createChatRoom is called", () => { const spy = jest.spyOn(defaultDispatcher, "fire"); - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); result.current.createChatRoom(new Event("click")); expect(spy).toHaveBeenCalledWith(Action.CreateChat); @@ -81,7 +125,7 @@ describe("useRoomListHeaderViewModel", () => { it("should fire Action.CreateRoom when createRoom is called", () => { const spy = jest.spyOn(defaultDispatcher, "fire"); - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); result.current.createRoom(new Event("click")); expect(spy).toHaveBeenCalledWith(Action.CreateRoom); @@ -89,7 +133,7 @@ describe("useRoomListHeaderViewModel", () => { it("should call showCreateNewRoom when createRoom is called in a space", () => { jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); result.current.createRoom(new Event("click")); expect(showCreateNewRoom).toHaveBeenCalledWith(space); @@ -98,7 +142,7 @@ describe("useRoomListHeaderViewModel", () => { it("should fire Action.CreateRoom with RoomType.UnstableCall when createVideoRoom is called and feature_element_call_video_rooms is enabled", () => { jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); const spy = jest.spyOn(defaultDispatcher, "dispatch"); - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); result.current.createVideoRoom(); expect(spy).toHaveBeenCalledWith({ action: Action.CreateRoom, type: RoomType.UnstableCall }); @@ -107,7 +151,7 @@ describe("useRoomListHeaderViewModel", () => { it("should fire Action.CreateRoom with RoomType.ElementVideo when createVideoRoom is called and feature_element_call_video_rooms is disabled", () => { jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); const spy = jest.spyOn(defaultDispatcher, "dispatch"); - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); result.current.createVideoRoom(); expect(spy).toHaveBeenCalledWith({ action: Action.CreateRoom, type: RoomType.ElementVideo }); @@ -115,9 +159,42 @@ describe("useRoomListHeaderViewModel", () => { it("should call showCreateNewRoom when createVideoRoom is called in a space", () => { jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); - const { result } = renderHook(() => useRoomListHeaderViewModel()); + const { result } = render(); result.current.createVideoRoom(); expect(showCreateNewRoom).toHaveBeenCalledWith(space, RoomType.ElementVideo); }); + + it("should fire Action.ViewRoom when openSpaceHome is called in a space", () => { + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + const spy = jest.spyOn(defaultDispatcher, "dispatch"); + const { result } = render(); + result.current.openSpaceHome(); + + expect(spy).toHaveBeenCalledWith({ action: Action.ViewRoom, room_id: space.roomId, metricsTrigger: undefined }); + }); + + it("should call showSpaceInvite when inviteInSpace is called in a space", () => { + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + const { result } = render(); + result.current.inviteInSpace(); + + expect(showSpaceInvite).toHaveBeenCalledWith(space); + }); + + it("should call showSpacePreferences when openSpacePreferences is called in a space", () => { + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + const { result } = render(); + result.current.openSpacePreferences(); + + expect(showSpacePreferences).toHaveBeenCalledWith(space); + }); + + it("should call showSpaceSettings when openSpaceSettings is called in a space", () => { + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + const { result } = render(); + result.current.openSpaceSettings(); + + expect(showSpaceSettings).toHaveBeenCalledWith(space); + }); }); diff --git a/test/unit-tests/components/views/rooms/RoomListView/RoomListHeaderView-test.tsx b/test/unit-tests/components/views/rooms/RoomListView/RoomListHeaderView-test.tsx index fa81db04b0..97195556c3 100644 --- a/test/unit-tests/components/views/rooms/RoomListView/RoomListHeaderView-test.tsx +++ b/test/unit-tests/components/views/rooms/RoomListView/RoomListHeaderView-test.tsx @@ -24,64 +24,129 @@ describe("", () => { const defaultValue: RoomListHeaderViewState = { title: "title", displayComposeMenu: true, + displaySpaceMenu: true, canCreateRoom: true, canCreateVideoRoom: true, + canInviteInSpace: true, + canAccessSpaceSettings: true, createRoom: jest.fn(), createVideoRoom: jest.fn(), createChatRoom: jest.fn(), + openSpaceHome: jest.fn(), + inviteInSpace: jest.fn(), + openSpacePreferences: jest.fn(), + openSpaceSettings: jest.fn(), }; afterEach(() => { jest.resetAllMocks(); }); - it("should display the compose menu", () => { - mocked(useRoomListHeaderViewModel).mockReturnValue(defaultValue); + describe("compose menu", () => { + it("should display the compose menu", () => { + mocked(useRoomListHeaderViewModel).mockReturnValue(defaultValue); - const { asFragment } = render(); - expect(screen.queryByRole("button", { name: "Add" })).toBeInTheDocument(); - expect(asFragment()).toMatchSnapshot(); - }); - - it("should not display the compose menu", () => { - mocked(useRoomListHeaderViewModel).mockReturnValue({ ...defaultValue, displayComposeMenu: false }); - - const { asFragment } = render(); - expect(screen.queryByRole("button", { name: "Add" })).toBeNull(); - expect(asFragment()).toMatchSnapshot(); - }); - - it("should display all the buttons when the menu is opened", async () => { - const user = userEvent.setup(); - mocked(useRoomListHeaderViewModel).mockReturnValue(defaultValue); - render(); - const openMenu = screen.getByRole("button", { name: "Add" }); - await user.click(openMenu); - - await user.click(screen.getByRole("menuitem", { name: "New message" })); - expect(defaultValue.createChatRoom).toHaveBeenCalled(); - - await user.click(openMenu); - await user.click(screen.getByRole("menuitem", { name: "New room" })); - expect(defaultValue.createRoom).toHaveBeenCalled(); - - await user.click(openMenu); - await user.click(screen.getByRole("menuitem", { name: "New video room" })); - expect(defaultValue.createVideoRoom).toHaveBeenCalled(); - }); - - it("should display only the new message button", async () => { - const user = userEvent.setup(); - mocked(useRoomListHeaderViewModel).mockReturnValue({ - ...defaultValue, - canCreateRoom: false, - canCreateVideoRoom: false, + const { asFragment } = render(); + expect(screen.queryByRole("button", { name: "Add" })).toBeInTheDocument(); + expect(asFragment()).toMatchSnapshot(); }); - render(); - await user.click(screen.getByRole("button", { name: "Add" })); + it("should not display the compose menu", () => { + mocked(useRoomListHeaderViewModel).mockReturnValue({ ...defaultValue, displayComposeMenu: false }); - expect(screen.queryByRole("menuitem", { name: "New room" })).toBeNull(); - expect(screen.queryByRole("menuitem", { name: "New video room" })).toBeNull(); + const { asFragment } = render(); + expect(screen.queryByRole("button", { name: "Add" })).toBeNull(); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should display all the buttons when the menu is opened", async () => { + const user = userEvent.setup(); + mocked(useRoomListHeaderViewModel).mockReturnValue(defaultValue); + render(); + const openMenu = screen.getByRole("button", { name: "Add" }); + await user.click(openMenu); + + await user.click(screen.getByRole("menuitem", { name: "New message" })); + expect(defaultValue.createChatRoom).toHaveBeenCalled(); + + await user.click(openMenu); + await user.click(screen.getByRole("menuitem", { name: "New room" })); + expect(defaultValue.createRoom).toHaveBeenCalled(); + + await user.click(openMenu); + await user.click(screen.getByRole("menuitem", { name: "New video room" })); + expect(defaultValue.createVideoRoom).toHaveBeenCalled(); + }); + + it("should display only the new message button", async () => { + const user = userEvent.setup(); + mocked(useRoomListHeaderViewModel).mockReturnValue({ + ...defaultValue, + canCreateRoom: false, + canCreateVideoRoom: false, + }); + + render(); + await user.click(screen.getByRole("button", { name: "Add" })); + + expect(screen.queryByRole("menuitem", { name: "New room" })).toBeNull(); + expect(screen.queryByRole("menuitem", { name: "New video room" })).toBeNull(); + }); + }); + + describe("space menu", () => { + it("should display the space menu", () => { + mocked(useRoomListHeaderViewModel).mockReturnValue(defaultValue); + + const { asFragment } = render(); + expect(screen.queryByRole("button", { name: "Open space menu" })).toBeInTheDocument(); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should not display the space menu", () => { + mocked(useRoomListHeaderViewModel).mockReturnValue({ ...defaultValue, displaySpaceMenu: false }); + + const { asFragment } = render(); + expect(screen.queryByRole("button", { name: "Open space menu" })).toBeNull(); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should display all the buttons when the space menu is opened", async () => { + const user = userEvent.setup(); + mocked(useRoomListHeaderViewModel).mockReturnValue(defaultValue); + render(); + const openMenu = screen.getByRole("button", { name: "Open space menu" }); + await user.click(openMenu); + + await user.click(screen.getByRole("menuitem", { name: "Space home" })); + expect(defaultValue.openSpaceHome).toHaveBeenCalled(); + + await user.click(openMenu); + await user.click(screen.getByRole("menuitem", { name: "Invite" })); + expect(defaultValue.inviteInSpace).toHaveBeenCalled(); + + await user.click(openMenu); + await user.click(screen.getByRole("menuitem", { name: "Preferences" })); + expect(defaultValue.openSpacePreferences).toHaveBeenCalled(); + + await user.click(openMenu); + await user.click(screen.getByRole("menuitem", { name: "Space Settings" })); + expect(defaultValue.openSpaceSettings).toHaveBeenCalled(); + }); + + it("should display only the home and preference buttons", async () => { + const user = userEvent.setup(); + mocked(useRoomListHeaderViewModel).mockReturnValue({ + ...defaultValue, + canInviteInSpace: false, + canAccessSpaceSettings: false, + }); + + render(); + await user.click(screen.getByRole("button", { name: "Add" })); + + expect(screen.queryByRole("menuitem", { name: "Invite" })).toBeNull(); + expect(screen.queryByRole("menuitem", { name: "Space Setting" })).toBeNull(); + }); }); }); diff --git a/test/unit-tests/components/views/rooms/RoomListView/__snapshots__/RoomListHeaderView-test.tsx.snap b/test/unit-tests/components/views/rooms/RoomListView/__snapshots__/RoomListHeaderView-test.tsx.snap index 36ae6d2b10..eee7df2dd7 100644 --- a/test/unit-tests/components/views/rooms/RoomListView/__snapshots__/RoomListHeaderView-test.tsx.snap +++ b/test/unit-tests/components/views/rooms/RoomListView/__snapshots__/RoomListHeaderView-test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` should display the compose menu 1`] = ` +exports[` compose menu should display the compose menu 1`] = `
should display the compose menu 1`] = ` data-testid="room-list-header" style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: 0;" > -

- title -

+
+

+ title +

+ +
+ +
+
+`; + +exports[` space menu should display the space menu 1`] = ` + +
+
+

+ title +

+ +
+ +
+
+`; + +exports[` space menu should not display the space menu 1`] = ` + +
+
+

+ title +

+
+
`; diff --git a/test/unit-tests/components/views/rooms/RoomListView/__snapshots__/RoomListView-test.tsx.snap b/test/unit-tests/components/views/rooms/RoomListView/__snapshots__/RoomListView-test.tsx.snap index 79bf67b0aa..90e1454f50 100644 --- a/test/unit-tests/components/views/rooms/RoomListView/__snapshots__/RoomListView-test.tsx.snap +++ b/test/unit-tests/components/views/rooms/RoomListView/__snapshots__/RoomListView-test.tsx.snap @@ -12,9 +12,14 @@ exports[` should not render the RoomListSearch component when UI data-testid="room-list-header" style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: 0;" > -

- Home -

+
+

+ Home +

+
@@ -88,9 +93,14 @@ exports[` should render the RoomListSearch component when UIComp data-testid="room-list-header" style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: space-between; --mx-flex-gap: 0;" > -

- Home -

+
+

+ Home +

+