Room list: assign room to custom section (#33238)
* feat(sc): add new toast type for room list * feat(sc): add section entries in room list item menu * feat(rls): expose util functions * feat: allows to tag room with custom sections * feat(vm): add new Chat moved toast to room list vm * feat(vm): add section selection to room list item vm * feat(e2e): add tests for adding room in a custom section * test(e2e): update existing screenshots * chore: fix lint after merge * chore: remove outline in test
This commit is contained in:
@@ -21,7 +21,7 @@ import { RoomNotificationState } from "../../../src/stores/notifications/RoomNot
|
||||
import { RoomNotificationStateStore } from "../../../src/stores/notifications/RoomNotificationStateStore";
|
||||
import { NotificationStateEvents } from "../../../src/stores/notifications/NotificationState";
|
||||
import { type MessagePreview, MessagePreviewStore } from "../../../src/stores/message-preview";
|
||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||
import SettingsStore, { type CallbackFn } from "../../../src/settings/SettingsStore";
|
||||
import DMRoomMap from "../../../src/utils/DMRoomMap";
|
||||
import { DefaultTagID } from "../../../src/stores/room-list-v3/skip-list/tag";
|
||||
import dispatcher from "../../../src/dispatcher/dispatcher";
|
||||
@@ -29,7 +29,8 @@ import { Action } from "../../../src/dispatcher/actions";
|
||||
import { CallStore } from "../../../src/stores/CallStore";
|
||||
import { CallEvent, type Call } from "../../../src/models/Call";
|
||||
import { RoomListItemViewModel } from "../../../src/viewmodels/room-list/RoomListItemViewModel";
|
||||
import RoomListStoreV3 from "../../../src/stores/room-list-v3/RoomListStoreV3";
|
||||
import RoomListStoreV3, { CHATS_TAG } from "../../../src/stores/room-list-v3/RoomListStoreV3";
|
||||
import * as tagRoomModule from "../../../src/utils/room/tagRoom";
|
||||
|
||||
jest.mock("../../../src/viewmodels/room-list/utils", () => ({
|
||||
hasAccessToOptionsMenu: jest.fn().mockReturnValue(true),
|
||||
@@ -83,6 +84,7 @@ describe("RoomListItemViewModel", () => {
|
||||
|
||||
jest.spyOn(MessagePreviewStore.instance, "getPreviewForRoom").mockResolvedValue(null);
|
||||
jest.spyOn(CallStore.instance, "getCall").mockReturnValue(null);
|
||||
jest.spyOn(RoomListStoreV3.instance, "orderedSectionTags", "get").mockReturnValue([]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -213,8 +215,8 @@ describe("RoomListItemViewModel", () => {
|
||||
let watchCallback: any;
|
||||
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(() => showPreview);
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((_setting, _room, callback) => {
|
||||
watchCallback = callback;
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((setting, _room, callback) => {
|
||||
if (setting === "RoomList.showMessagePreview") watchCallback = callback;
|
||||
return "watcher-id";
|
||||
});
|
||||
jest.spyOn(MessagePreviewStore.instance, "getPreviewForRoom").mockResolvedValue({
|
||||
@@ -595,6 +597,93 @@ describe("RoomListItemViewModel", () => {
|
||||
viewModel.onCreateSection();
|
||||
expect(createSectionSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should call tagRoom when onToggleSection is called", () => {
|
||||
const tagRoomSpy = jest.spyOn(tagRoomModule, "tagRoom").mockImplementation(() => {});
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
|
||||
viewModel.onToggleSection(DefaultTagID.Favourite);
|
||||
|
||||
expect(tagRoomSpy).toHaveBeenCalledWith(room, DefaultTagID.Favourite);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Sections", () => {
|
||||
const customTag = "element.io.section.custom1";
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(RoomListStoreV3.instance, "orderedSectionTags", "get").mockReturnValue([
|
||||
DefaultTagID.Favourite,
|
||||
customTag,
|
||||
CHATS_TAG,
|
||||
DefaultTagID.LowPriority,
|
||||
]);
|
||||
});
|
||||
|
||||
it("should include sections from orderedSectionTags excluding CHATS_TAG", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "feature_room_list_sections") return true;
|
||||
return false;
|
||||
});
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
|
||||
const sections = viewModel.getSnapshot().sections;
|
||||
expect(sections.map((s) => s.tag)).toEqual([DefaultTagID.Favourite, customTag, DefaultTagID.LowPriority]);
|
||||
});
|
||||
|
||||
it("should mark the room current section as selected", () => {
|
||||
room.tags = { [DefaultTagID.Favourite]: { order: 0 } };
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "feature_room_list_sections") return true;
|
||||
return false;
|
||||
});
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
|
||||
const sections = viewModel.getSnapshot().sections;
|
||||
expect(sections.find((s) => s.tag === DefaultTagID.Favourite)?.isSelected).toBe(true);
|
||||
expect(sections.find((s) => s.tag === DefaultTagID.LowPriority)?.isSelected).toBe(false);
|
||||
});
|
||||
|
||||
it("should use custom section name from CustomSectionData", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "feature_room_list_sections") return true;
|
||||
if (setting === "RoomList.CustomSectionData")
|
||||
return { [customTag]: { name: "My Custom Section", tag: customTag } };
|
||||
return false;
|
||||
});
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
|
||||
const section = viewModel.getSnapshot().sections.find((s) => s.tag === customTag);
|
||||
expect(section?.name).toBe("My Custom Section");
|
||||
});
|
||||
|
||||
it("should update sections when OrderedCustomSections setting changes", () => {
|
||||
let watchCallback: CallbackFn = () => {};
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((setting, _room, callback) => {
|
||||
if (setting === "RoomList.OrderedCustomSections") watchCallback = callback;
|
||||
return "watcher-id";
|
||||
});
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "feature_room_list_sections") return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
expect(viewModel.getSnapshot().sections).toHaveLength(3); // Favourite, custom, LowPriority
|
||||
|
||||
// Simulate reordering: custom section removed
|
||||
jest.spyOn(RoomListStoreV3.instance, "orderedSectionTags", "get").mockReturnValue([
|
||||
DefaultTagID.Favourite,
|
||||
CHATS_TAG,
|
||||
DefaultTagID.LowPriority,
|
||||
]);
|
||||
watchCallback("RoomList.OrderedCustomSections", null, null as any, null, null);
|
||||
|
||||
expect(viewModel.getSnapshot().sections.map((s) => s.tag)).toEqual([
|
||||
DefaultTagID.Favourite,
|
||||
DefaultTagID.LowPriority,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Cleanup", () => {
|
||||
|
||||
@@ -619,6 +619,12 @@ describe("RoomListViewModel", () => {
|
||||
expect(viewModel.getSnapshot().toast).toBe("section_created");
|
||||
});
|
||||
|
||||
it("should show toast when RoomTagged event fires", () => {
|
||||
viewModel = new RoomListViewModel({ client: matrixClient });
|
||||
RoomListStoreV3.instance.emit(RoomListStoreV3Event.RoomTagged);
|
||||
expect(viewModel.getSnapshot().toast).toBe("chat_moved");
|
||||
});
|
||||
|
||||
it("should clear toast when closeToast is called", () => {
|
||||
viewModel = new RoomListViewModel({ client: matrixClient });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user