Files
element-web/test/unit-tests/components/views/rooms/memberlist/MemberListHeaderView-test.tsx
David Langley c842b615db Move the room list to the new ListView(backed by react-virtuoso) (#30515)
* Move Room List to ListView

- Also remove Space/Enter handing from keyboard navigation we can just leave the default behaviour of those keys and handle via onClick

* Update rooms when the primary filter changes

Otherwise when changing spaces, the filter does not reset until the next update to the RVS is made.

* Fix stickyRow/scrollIntoView when switiching space or changing filters

- Also remove the rest of space/enter keyboard handling use

* Remove the rest of space/enter keyboard handling use

* Remove useCombinedRef and add @radix-ui/react-compose-refs as we already depend on it

- Also remove eact-virtualized dep

* Update RoomList unit test

* Update snapshots and unit tests

* Fix e2e tests

* Remove react-virtualized from tests

* Fix e2e flake

* Update more screenshots

* Fix e2e test case where were should scroll to the top when the active room is no longer in the list

* Move from gitpkg to package-patch

* Update to latest react virtuoso release/api.

Also pass spaceId to the room list and scroll the activeIndex into view when spaceId or primaryFilter change.

* Use listbox/option roles to improve ScreenReader experience

* Change onKeyDown e.stopPropogation to cover context menu

* lint

* Remove unneeded exposure of the listView ref

Also move scrollIntoViewOnChange to useCallback

* Update unit test and snapshot

* Fix e2e tests and update screenshots

* Fix unit test and snapshot

* Update more unit tests

* Fix keyboard shortcuts and e2e test

* Fix another e2e and unit test

* lint

* Improve the naming for RoomResult and the documentation on it's fields meaning.

Also update the login in RoomList to check for any change in filters, this is a bit more future proof for when we introduce multi select than using activePrimaryFilter.

* Put back and fix landmark tests

* Fix test import

* Add comment regarding context object getting rendered.

* onKeyDown should be optional

* Use SpaceKey type on RoomResult

* lint
2025-08-21 14:43:40 +00:00

112 lines
4.9 KiB
TypeScript

/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
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 { act, fireEvent, screen, waitFor } from "jest-matrix-react";
import { RoomMember, User, RoomEvent } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
import { mocked } from "jest-mock";
import { shouldShowComponent } from "../../../../../../src/customisations/helpers/UIComponents";
import defaultDispatcher from "../../../../../../src/dispatcher/dispatcher";
import { type Rendered, renderMemberList } from "./common";
jest.mock("../../../../../../src/customisations/helpers/UIComponents", () => ({
shouldShowComponent: jest.fn(),
}));
jest.spyOn(HTMLElement.prototype, "offsetHeight", "get").mockReturnValue(1500);
jest.spyOn(HTMLElement.prototype, "offsetWidth", "get").mockReturnValue(1500);
describe("Does not render invite button in memberlist header", () => {
it("when user is not a member", async () => {
await renderMemberList(true, (room) => room.updateMyMembership(KnownMembership.Leave));
expect(screen.queryByRole("button", { name: "Invite" })).toBeNull();
});
it("when UI customisation hides invites", async () => {
mocked(shouldShowComponent).mockReturnValue(false);
const { client, memberListRoom } = await renderMemberList(true);
// Needs this specific event...
act(() => {
client.emit(RoomEvent.MyMembership, memberListRoom, KnownMembership.Join, KnownMembership.Invite);
});
await waitFor(() => expect(screen.queryByRole("button", { name: "Invite" })).toBeNull());
});
});
describe("MemberListHeaderView", () => {
let rendered: Rendered;
beforeEach(async function () {
mocked(shouldShowComponent).mockReturnValue(true);
rendered = await renderMemberList(true);
});
it("Shows the correct member count", async () => {
expect(await screen.findByText("6 Members")).toBeVisible();
});
it("Does not show search box when there's less than 20 members", async () => {
expect(screen.queryByPlaceholderText("Search room members")).toBeNull();
});
it("Shows search box when there's more than 20 members", async () => {
const { memberListRoom, client, reRender } = rendered;
// Memberlist already has 6 members, add 14 more to make the total 20
for (let i = 0; i < 14; ++i) {
const newMember = new RoomMember(memberListRoom.roomId, `@new${i}:localhost`);
newMember.membership = KnownMembership.Join;
newMember.powerLevel = 0;
newMember.user = User.createUser(newMember.userId, client);
newMember.user.currentlyActive = true;
newMember.user.presence = "online";
newMember.user.lastPresenceTs = 1000;
newMember.user.lastActiveAgo = 10;
memberListRoom.currentState.members[newMember.userId] = newMember;
}
await reRender();
expect(screen.queryByPlaceholderText("Search room members")).toBeVisible();
});
describe("Invite button functionality", () => {
afterEach(() => {
jest.restoreAllMocks();
});
it("Renders disabled invite button when current user is a member but does not have rights to invite", async () => {
const { memberListRoom, reRender } = rendered;
jest.spyOn(memberListRoom, "getMyMembership").mockReturnValue(KnownMembership.Join);
jest.spyOn(memberListRoom, "canInvite").mockReturnValue(false);
await reRender();
expect(screen.getByRole("button", { name: "Invite" })).toHaveAttribute("aria-disabled", "true");
});
it("Renders enabled invite button when current user is a member and has rights to invite", async () => {
const { memberListRoom, reRender } = rendered;
jest.spyOn(memberListRoom, "getMyMembership").mockReturnValue(KnownMembership.Join);
jest.spyOn(memberListRoom, "canInvite").mockReturnValue(true);
await reRender();
expect(screen.getByRole("button", { name: "Invite" })).not.toHaveAttribute("aria-disabled", "true");
});
it("Opens room inviter on button click", async () => {
const { memberListRoom, reRender } = rendered;
jest.spyOn(defaultDispatcher, "dispatch");
jest.spyOn(memberListRoom, "canInvite").mockReturnValue(true);
await reRender();
fireEvent.click(screen.getByRole("button", { name: "Invite" }));
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
action: "view_invite",
roomId: memberListRoom.roomId,
});
});
});
});