diff --git a/src/components/views/dialogs/spotlight/RoomResultContextMenus.tsx b/src/components/views/dialogs/spotlight/RoomResultContextMenus.tsx index 096138e056f..f761c350997 100644 --- a/src/components/views/dialogs/spotlight/RoomResultContextMenus.tsx +++ b/src/components/views/dialogs/spotlight/RoomResultContextMenus.tsx @@ -27,6 +27,8 @@ import { RoomNotificationContextMenu } from "../../context_menus/RoomNotificatio import SpaceContextMenu from "../../context_menus/SpaceContextMenu"; import { ButtonEvent } from "../../elements/AccessibleButton"; import { contextMenuBelow } from "../../rooms/RoomTile"; +import { shouldShowComponent } from "../../../../customisations/helpers/UIComponents"; +import { UIComponent } from "../../../../settings/UIFeature"; interface Props { room: Room; @@ -80,18 +82,20 @@ export function RoomResultContextMenus({ room }: Props): JSX.Element { return ( - { - ev.preventDefault(); - ev.stopPropagation(); + {shouldShowComponent(UIComponent.RoomOptionsMenu) && ( + { + ev.preventDefault(); + ev.stopPropagation(); - const target = ev.target as HTMLElement; - setGeneralMenuPosition(target.getBoundingClientRect()); - }} - title={room.isSpaceRoom() ? _t("Space options") : _t("Room options")} - isExpanded={generalMenuPosition !== null} - /> + const target = ev.target as HTMLElement; + setGeneralMenuPosition(target.getBoundingClientRect()); + }} + title={room.isSpaceRoom() ? _t("Space options") : _t("Room options")} + isExpanded={generalMenuPosition !== null} + /> + )} {!room.isSpaceRoom() && ( { ); - if (this.props.enableRoomOptionsMenu) { + if (this.props.enableRoomOptionsMenu && shouldShowComponent(UIComponent.RoomOptionsMenu)) { return ( { }; private get showContextMenu(): boolean { - return this.props.tag !== DefaultTagID.Invite; + return this.props.tag !== DefaultTagID.Invite && shouldShowComponent(UIComponent.RoomOptionsMenu); } private get showMessagePreview(): boolean { diff --git a/src/settings/UIFeature.ts b/src/settings/UIFeature.ts index b9e290ffeca..a8d3f788ef5 100644 --- a/src/settings/UIFeature.ts +++ b/src/settings/UIFeature.ts @@ -70,4 +70,9 @@ export enum UIComponent { * Component that lead to the user being able to search, dial, explore rooms */ FilterContainer = "UIComponent.filterContainer", + + /** + * Components that lead the user to room options menu. + */ + RoomOptionsMenu = "UIComponent.roomOptionsMenu", } diff --git a/test/components/views/dialogs/spotlight/RoomResultContextMenus-test.tsx b/test/components/views/dialogs/spotlight/RoomResultContextMenus-test.tsx new file mode 100644 index 00000000000..0ead500a072 --- /dev/null +++ b/test/components/views/dialogs/spotlight/RoomResultContextMenus-test.tsx @@ -0,0 +1,66 @@ +/* +Copyright 2023 Mikhail Aheichyk +Copyright 2023 Nordeck IT + Consulting GmbH. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { render, screen, RenderResult } from "@testing-library/react"; +import { mocked } from "jest-mock"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { MatrixClient, PendingEventOrdering } from "matrix-js-sdk/src/client"; + +import { RoomResultContextMenus } from "../../../../../src/components/views/dialogs/spotlight/RoomResultContextMenus"; +import { filterConsole, stubClient } from "../../../../test-utils"; +import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents"; +import { UIComponent } from "../../../../../src/settings/UIFeature"; + +jest.mock("../../../../../src/customisations/helpers/UIComponents", () => ({ + shouldShowComponent: jest.fn(), +})); + +describe("RoomResultContextMenus", () => { + let client: MatrixClient; + let room: Room; + + const renderRoomResultContextMenus = (): RenderResult => { + return render(); + }; + + filterConsole( + // irrelevant for this test + "Room !1:example.org does not have an m.room.create event", + ); + + beforeEach(() => { + client = stubClient(); + room = new Room("!1:example.org", client, "@alice:example.org", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + }); + + it("does not render the room options context menu when UIComponent customisations disable room options", () => { + mocked(shouldShowComponent).mockReturnValue(false); + renderRoomResultContextMenus(); + expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.RoomOptionsMenu); + expect(screen.queryByRole("button", { name: "Room options" })).not.toBeInTheDocument(); + }); + + it("renders the room options context menu when UIComponent customisations enable room options", () => { + mocked(shouldShowComponent).mockReturnValue(true); + renderRoomResultContextMenus(); + expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.RoomOptionsMenu); + expect(screen.queryByRole("button", { name: "Room options" })).toBeInTheDocument(); + }); +}); diff --git a/test/components/views/rooms/RoomHeader-test.tsx b/test/components/views/rooms/RoomHeader-test.tsx index 3b8aa0d2d0e..ea920cf4d59 100644 --- a/test/components/views/rooms/RoomHeader-test.tsx +++ b/test/components/views/rooms/RoomHeader-test.tsx @@ -57,6 +57,12 @@ import { WidgetMessagingStore } from "../../../../src/stores/widgets/WidgetMessa import WidgetUtils from "../../../../src/utils/WidgetUtils"; import { ElementWidgetActions } from "../../../../src/stores/widgets/ElementWidgetActions"; import MediaDeviceHandler, { MediaDeviceKindEnum } from "../../../../src/MediaDeviceHandler"; +import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; +import { UIComponent } from "../../../../src/settings/UIFeature"; + +jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({ + shouldShowComponent: jest.fn(), +})); describe("RoomHeader", () => { let client: Mocked; @@ -729,17 +735,26 @@ describe("RoomHeader", () => { expect(wrapper.container.querySelector(".mx_RoomHeader_button")).toBeFalsy(); }); - it("should render the room options context menu if not passing enableRoomOptionsMenu (default true)", () => { + it("should render the room options context menu if not passing enableRoomOptionsMenu (default true) and UIComponent customisations room options enabled", () => { + mocked(shouldShowComponent).mockReturnValue(true); const room = createRoom({ name: "Room", isDm: false, userIds: [] }); const wrapper = mountHeader(room); + expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.RoomOptionsMenu); expect(wrapper.container.querySelector(".mx_RoomHeader_name.mx_AccessibleButton")).toBeDefined(); }); - it("should not render the room options context menu if passing enableRoomOptionsMenu = false", () => { - const room = createRoom({ name: "Room", isDm: false, userIds: [] }); - const wrapper = mountHeader(room, { enableRoomOptionsMenu: false }); - expect(wrapper.container.querySelector(".mx_RoomHeader_name.mx_AccessibleButton")).toBeFalsy(); - }); + it.each([ + [false, true], + [true, false], + ])( + "should not render the room options context menu if passing enableRoomOptionsMenu = %s and UIComponent customisations room options enable = %s", + (enableRoomOptionsMenu, showRoomOptionsMenu) => { + mocked(shouldShowComponent).mockReturnValue(showRoomOptionsMenu); + const room = createRoom({ name: "Room", isDm: false, userIds: [] }); + const wrapper = mountHeader(room, { enableRoomOptionsMenu }); + expect(wrapper.container.querySelector(".mx_RoomHeader_name.mx_AccessibleButton")).toBeFalsy(); + }, + ); }); interface IRoomCreationInfo { diff --git a/test/components/views/rooms/RoomTile-test.tsx b/test/components/views/rooms/RoomTile-test.tsx index 11df23f97fb..51f06f00058 100644 --- a/test/components/views/rooms/RoomTile-test.tsx +++ b/test/components/views/rooms/RoomTile-test.tsx @@ -47,8 +47,14 @@ 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"; +import { UIComponent } from "../../../../src/settings/UIFeature"; import { MessagePreviewStore } from "../../../../src/stores/room-list/MessagePreviewStore"; +jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({ + shouldShowComponent: jest.fn(), +})); + describe("RoomTile", () => { jest.spyOn(PlatformPeg, "get").mockReturnValue({ overrideBrowserShortcuts: () => false, @@ -69,8 +75,8 @@ describe("RoomTile", () => { }); }; - const renderRoomTile = (): void => { - renderResult = render( + const renderRoomTile = (): RenderResult => { + return render( { let client: Mocked; let voiceBroadcastInfoEvent: MatrixEvent; let room: Room; - let renderResult: RenderResult; let sdkContext: TestSdkContext; let showMessagePreview = false; @@ -148,12 +153,24 @@ describe("RoomTile", () => { }); describe("when message previews are not enabled", () => { - beforeEach(() => { + it("should render the room", () => { + mocked(shouldShowComponent).mockReturnValue(true); + const renderResult = renderRoomTile(); + expect(renderResult.container).toMatchSnapshot(); + }); + + it("does not render the room options context menu when UIComponent customisations disable room options", () => { + mocked(shouldShowComponent).mockReturnValue(false); renderRoomTile(); + expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.RoomOptionsMenu); + expect(screen.queryByRole("button", { name: "Room options" })).not.toBeInTheDocument(); }); - it("should render the room", () => { - expect(renderResult.container).toMatchSnapshot(); + it("renders the room options context menu when UIComponent customisations enable room options", () => { + mocked(shouldShowComponent).mockReturnValue(true); + renderRoomTile(); + expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.RoomOptionsMenu); + expect(screen.queryByRole("button", { name: "Room options" })).toBeInTheDocument(); }); describe("when a call starts", () => { @@ -176,13 +193,13 @@ describe("RoomTile", () => { }); afterEach(() => { - renderResult.unmount(); call.destroy(); client.reEmitter.stopReEmitting(room, [RoomStateEvent.Events]); WidgetMessagingStore.instance.stopMessaging(widget, room.roomId); }); it("tracks connection state", async () => { + renderRoomTile(); screen.getByText("Video"); // Insert an await point in the connection method so we can inspect @@ -205,6 +222,7 @@ describe("RoomTile", () => { }); it("tracks participants", () => { + renderRoomTile(); const alice: [RoomMember, Set] = [ mkRoomMember(room.roomId, "@alice:example.org"), new Set(["a"]), @@ -238,6 +256,7 @@ describe("RoomTile", () => { describe("and a live broadcast starts", () => { beforeEach(async () => { + renderRoomTile(); await setUpVoiceBroadcast(VoiceBroadcastInfoState.Started); }); @@ -250,6 +269,7 @@ describe("RoomTile", () => { describe("when a live voice broadcast starts", () => { beforeEach(async () => { + renderRoomTile(); await setUpVoiceBroadcast(VoiceBroadcastInfoState.Started); }); @@ -285,7 +305,7 @@ describe("RoomTile", () => { }); it("should render a room without a message as expected", async () => { - renderRoomTile(); + const renderResult = renderRoomTile(); // flush promises here because the preview is created asynchronously await flushPromises(); expect(renderResult.asFragment()).toMatchSnapshot(); @@ -297,7 +317,7 @@ describe("RoomTile", () => { }); it("should render as expected", async () => { - renderRoomTile(); + const renderResult = renderRoomTile(); expect(await screen.findByText("test message")).toBeInTheDocument(); expect(renderResult.asFragment()).toMatchSnapshot(); }); @@ -309,7 +329,7 @@ describe("RoomTile", () => { }); it("should render as expected", async () => { - renderRoomTile(); + const renderResult = renderRoomTile(); expect(await screen.findByText("test thread reply")).toBeInTheDocument(); expect(renderResult.asFragment()).toMatchSnapshot(); });