Files
ThreadNet-Web/packages/shared-components/src/room-list/RoomListView/RoomListView.test.tsx
T
David LangleyandGitHub 6da1412de8 Migrate the room list view to shared components (#31921)
* Add NotificationDecoration component

Add the NotificationDecoration component to shared-components.
This is a leaf component that renders notification badges and indicators
for rooms/items including mentions, unread counts, call indicators, etc.

* Add RoomListItem component

Add the RoomListItem component to shared-components.
Includes context menu, hover menu, notification menu, and more options menu.

* Add RoomListPrimaryFilters component

Add filter chips component for filtering the room list by
unread, people, rooms, favourites, mentions, invites, and low priority.

* Update VirtualizedList component

Update VirtualizedList to support the room list virtualization requirements.

* Add RoomList component

Add RoomList component that renders a virtualized list of room items.
Includes story mocks for testing.

* Add RoomListView component

Add RoomListView component that composes RoomList with filters,
empty states, and loading skeleton.

* Export room-list components from shared-components

Add exports for RoomListView, RoomListItem, RoomListPrimaryFilters, and RoomList.
Include i18n strings for room list components.

* Add RoomListItemViewModel

Add view model for individual room list items.
Manages per-room subscriptions and updates only when specific room data changes.

* Add RoomListViewViewModel

Add view model for the room list view.
Manages room list state, filtering, keyboard navigation, and child view models.

* Integrate shared components into RoomListView

Update RoomListView to use the new ViewModels and shared components.
Includes i18n string updates for element-web.

* Remove old room list implementation

Remove old ViewModels, hooks, and view components that are now
replaced by the shared-components implementation.

* Update sliding-sync playwright test

Update test expectations for new room list implementation.

* Add figma links

* Move viewModels to the right folder

* Rename to RoomListEmptyStateView

* Update VirtualizedRoomListView naming

* Update screenshots and snapshots

* Move viewmodel tests to the right location and fix some imports

* lint

* Use unknown as an Opaque type rather than any. It discourages property access within shared components and can still be cast back in EW.

* Update screenshots for new shared component rendering params

* Make room order tests deterministic
2026-02-05 21:05:14 +00:00

178 lines
6.0 KiB
TypeScript

/*
* Copyright 2026 Element Creations 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 { render, screen } from "@test-utils";
import userEvent from "@testing-library/user-event";
import { VirtuosoMockContext } from "react-virtuoso";
import { composeStories } from "@storybook/react-vite";
import { describe, it, expect } from "vitest";
import * as stories from "./RoomListView.stories";
const {
Default,
Loading,
Empty,
EmptyWithoutCreatePermission,
WithActiveFilter,
SmallList,
LargeList,
EmptyFavouriteFilter,
EmptyPeopleFilter,
EmptyRoomsFilter,
EmptyUnreadFilter,
EmptyInvitesFilter,
EmptyMentionsFilter,
EmptyLowPriorityFilter,
} = composeStories(stories);
const renderWithMockContext = (component: React.ReactElement): ReturnType<typeof render> => {
return render(component, {
wrapper: ({ children }) => (
<VirtuosoMockContext.Provider value={{ viewportHeight: 600, itemHeight: 48 }}>
{children}
</VirtuosoMockContext.Provider>
),
});
};
describe("<RoomListView />", () => {
it("renders Default story", () => {
const { container } = renderWithMockContext(<Default />);
expect(container).toMatchSnapshot();
});
it("renders Loading story", () => {
const { container } = renderWithMockContext(<Loading />);
expect(container).toMatchSnapshot();
});
it("renders Empty story", () => {
const { container } = renderWithMockContext(<Empty />);
expect(container).toMatchSnapshot();
});
it("renders EmptyWithoutCreatePermission story", () => {
const { container } = renderWithMockContext(<EmptyWithoutCreatePermission />);
expect(container).toMatchSnapshot();
});
it("renders WithActiveFilter story", () => {
const { container } = renderWithMockContext(<WithActiveFilter />);
expect(container).toMatchSnapshot();
});
it("renders SmallList story", () => {
const { container } = renderWithMockContext(<SmallList />);
expect(container).toMatchSnapshot();
});
it("renders LargeList story", () => {
const { container } = renderWithMockContext(<LargeList />);
expect(container).toMatchSnapshot();
});
it("renders EmptyFavouriteFilter story", () => {
const { container } = renderWithMockContext(<EmptyFavouriteFilter />);
expect(container).toMatchSnapshot();
});
it("renders EmptyPeopleFilter story", () => {
const { container } = renderWithMockContext(<EmptyPeopleFilter />);
expect(container).toMatchSnapshot();
});
it("renders EmptyRoomsFilter story", () => {
const { container } = renderWithMockContext(<EmptyRoomsFilter />);
expect(container).toMatchSnapshot();
});
it("renders EmptyUnreadFilter story", () => {
const { container } = renderWithMockContext(<EmptyUnreadFilter />);
expect(container).toMatchSnapshot();
});
it("renders EmptyInvitesFilter story", () => {
const { container } = renderWithMockContext(<EmptyInvitesFilter />);
expect(container).toMatchSnapshot();
});
it("renders EmptyMentionsFilter story", () => {
const { container } = renderWithMockContext(<EmptyMentionsFilter />);
expect(container).toMatchSnapshot();
});
it("renders EmptyLowPriorityFilter story", () => {
const { container } = renderWithMockContext(<EmptyLowPriorityFilter />);
expect(container).toMatchSnapshot();
});
it("should call onToggleFilter when filter is clicked", async () => {
const user = userEvent.setup();
renderWithMockContext(<Default />);
await user.click(screen.getByRole("option", { name: "People" }));
expect(Default.args.onToggleFilter).toHaveBeenCalled();
});
it("should call createRoom when New room button is clicked", async () => {
const user = userEvent.setup();
renderWithMockContext(<Empty />);
await user.click(screen.getByRole("button", { name: "New room" }));
expect(Empty.args.createRoom).toHaveBeenCalled();
});
it("should call createChatRoom when Start chat button is clicked", async () => {
const user = userEvent.setup();
renderWithMockContext(<Empty />);
await user.click(screen.getByRole("button", { name: "Start chat" }));
expect(Empty.args.createChatRoom).toHaveBeenCalled();
});
it("should call onToggleFilter when Show all chats is clicked in unread empty state", async () => {
const user = userEvent.setup();
renderWithMockContext(<EmptyUnreadFilter />);
await user.click(screen.getByRole("button", { name: "Show all chats" }));
expect(EmptyUnreadFilter.args.onToggleFilter).toHaveBeenCalled();
});
it("should call onToggleFilter when See all activity is clicked in invites empty state", async () => {
const user = userEvent.setup();
renderWithMockContext(<EmptyInvitesFilter />);
await user.click(screen.getByRole("button", { name: "See all activity" }));
expect(EmptyInvitesFilter.args.onToggleFilter).toHaveBeenCalled();
});
it("should call onToggleFilter when See all activity is clicked in mentions empty state", async () => {
const user = userEvent.setup();
renderWithMockContext(<EmptyMentionsFilter />);
await user.click(screen.getByRole("button", { name: "See all activity" }));
expect(EmptyMentionsFilter.args.onToggleFilter).toHaveBeenCalled();
});
it("should call onToggleFilter when See all activity is clicked in low priority empty state", async () => {
const user = userEvent.setup();
renderWithMockContext(<EmptyLowPriorityFilter />);
await user.click(screen.getByRole("button", { name: "See all activity" }));
expect(EmptyLowPriorityFilter.args.onToggleFilter).toHaveBeenCalled();
});
});