mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-05 20:26:19 +02:00
* fix: soft crash of room list trying to get item vm * test: add test to check roomMap recovery and cleared when needed
609 lines
23 KiB
TypeScript
609 lines
23 KiB
TypeScript
/*
|
|
* Copyright 2025 New Vector 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 { type MatrixClient, type Room } from "matrix-js-sdk/src/matrix";
|
|
import { mocked } from "jest-mock";
|
|
|
|
import { createTestClient, flushPromises, mkStubRoom, stubClient } from "../../test-utils";
|
|
import RoomListStoreV3, { RoomListStoreV3Event } from "../../../src/stores/room-list-v3/RoomListStoreV3";
|
|
import SpaceStore from "../../../src/stores/spaces/SpaceStore";
|
|
import { FilterKey } from "../../../src/stores/room-list-v3/skip-list/filters";
|
|
import dispatcher from "../../../src/dispatcher/dispatcher";
|
|
import { Action } from "../../../src/dispatcher/actions";
|
|
import { SdkContextClass } from "../../../src/contexts/SDKContext";
|
|
import DMRoomMap from "../../../src/utils/DMRoomMap";
|
|
import { RoomListViewModel } from "../../../src/viewmodels/room-list/RoomListViewModel";
|
|
import { hasCreateRoomRights } from "../../../src/viewmodels/room-list/utils";
|
|
|
|
jest.mock("../../../src/viewmodels/room-list/utils", () => ({
|
|
hasCreateRoomRights: jest.fn().mockReturnValue(false),
|
|
hasAccessToOptionsMenu: jest.fn().mockReturnValue(true),
|
|
hasAccessToNotificationMenu: jest.fn().mockReturnValue(true),
|
|
}));
|
|
|
|
describe("RoomListViewModel", () => {
|
|
let matrixClient: MatrixClient;
|
|
let room1: Room;
|
|
let room2: Room;
|
|
let room3: Room;
|
|
let viewModel: RoomListViewModel;
|
|
|
|
beforeEach(() => {
|
|
matrixClient = createTestClient();
|
|
room1 = mkStubRoom("!room1:server", "Room 1", matrixClient);
|
|
room2 = mkStubRoom("!room2:server", "Room 2", matrixClient);
|
|
room3 = mkStubRoom("!room3:server", "Room 3", matrixClient);
|
|
|
|
// Setup DMRoomMap
|
|
const dmRoomMap = {
|
|
getUserIdForRoomId: jest.fn().mockReturnValue(null),
|
|
} as unknown as DMRoomMap;
|
|
DMRoomMap.setShared(dmRoomMap);
|
|
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "home",
|
|
rooms: [room1, room2, room3],
|
|
});
|
|
|
|
jest.spyOn(RoomListStoreV3.instance, "isLoadingRooms", "get").mockReturnValue(false);
|
|
jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(null);
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue(null);
|
|
|
|
mocked(hasCreateRoomRights).mockReturnValue(false);
|
|
});
|
|
|
|
afterEach(() => {
|
|
viewModel?.dispose();
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
describe("Initialization", () => {
|
|
it("should initialize with correct snapshot", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const snapshot = viewModel.getSnapshot();
|
|
expect(snapshot.sections[0].roomIds).toEqual(["!room1:server", "!room2:server", "!room3:server"]);
|
|
expect(snapshot.isRoomListEmpty).toBe(false);
|
|
expect(snapshot.isLoadingRooms).toBe(false);
|
|
expect(snapshot.roomListState.spaceId).toBe("home");
|
|
expect(snapshot.filterIds.length).toBeGreaterThan(0);
|
|
expect(snapshot.activeFilterId).toBeUndefined();
|
|
});
|
|
|
|
it("should initialize with empty room list", () => {
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "home",
|
|
rooms: [],
|
|
});
|
|
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
expect(viewModel.getSnapshot().sections[0].roomIds).toEqual([]);
|
|
expect(viewModel.getSnapshot().isRoomListEmpty).toBe(true);
|
|
});
|
|
|
|
it("should set canCreateRoom based on user rights", () => {
|
|
mocked(hasCreateRoomRights).mockReturnValue(true);
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
expect(viewModel.getSnapshot().canCreateRoom).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("Room list updates", () => {
|
|
it("should update room list when ListsUpdate event fires", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const newRoom = mkStubRoom("!room4:server", "Room 4", matrixClient);
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "home",
|
|
rooms: [room1, room2, room3, newRoom],
|
|
});
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsUpdate);
|
|
|
|
expect(viewModel.getSnapshot().sections[0].roomIds).toEqual([
|
|
"!room1:server",
|
|
"!room2:server",
|
|
"!room3:server",
|
|
"!room4:server",
|
|
]);
|
|
});
|
|
|
|
it("should update loading state when ListsLoaded event fires", () => {
|
|
jest.spyOn(RoomListStoreV3.instance, "isLoadingRooms", "get").mockReturnValue(true);
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
expect(viewModel.getSnapshot().isLoadingRooms).toBe(true);
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsLoaded);
|
|
|
|
expect(viewModel.getSnapshot().isLoadingRooms).toBe(false);
|
|
});
|
|
|
|
// This test ensures that the room list item vms are preserved when the room list is changing
|
|
it("should keep existing view model when ListsUpdate event fires", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
// Create view model for room1
|
|
const room1VM = viewModel.getRoomItemViewModel("!room1:server");
|
|
expect(room1VM).toBeDefined();
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsUpdate);
|
|
|
|
// View model should be still valid
|
|
expect(room1VM.isDisposed).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("Space switching", () => {
|
|
it("should update room list when space changes", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const spaceRoomList = [room1, room2];
|
|
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "!space:server",
|
|
rooms: spaceRoomList,
|
|
});
|
|
|
|
jest.spyOn(SpaceStore.instance, "getLastSelectedRoomIdForSpace").mockReturnValue("!room1:server");
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsUpdate);
|
|
|
|
expect(viewModel.getSnapshot().roomListState.spaceId).toBe("!space:server");
|
|
expect(viewModel.getSnapshot().sections[0].roomIds).toEqual(["!room1:server", "!room2:server"]);
|
|
});
|
|
|
|
it("should clear view models when space changes", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
// Get view models for visible rooms
|
|
const vm1 = viewModel.getRoomItemViewModel("!room1:server");
|
|
const vm2 = viewModel.getRoomItemViewModel("!room2:server");
|
|
|
|
const disposeSpy1 = jest.spyOn(vm1, "dispose");
|
|
const disposeSpy2 = jest.spyOn(vm2, "dispose");
|
|
|
|
// Change space
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "!space:server",
|
|
rooms: [room3],
|
|
});
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsUpdate);
|
|
|
|
expect(disposeSpy1).toHaveBeenCalled();
|
|
expect(disposeSpy2).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should clear roomsMap when space changes and repopulate with new rooms", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const newSpaceRoom = mkStubRoom("!spaceroom:server", "Space Room", matrixClient);
|
|
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "!space:server",
|
|
rooms: [newSpaceRoom],
|
|
});
|
|
jest.spyOn(SpaceStore.instance, "getLastSelectedRoomIdForSpace").mockReturnValue(null);
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsUpdate);
|
|
|
|
// New space room should be accessible
|
|
expect(() => viewModel.getRoomItemViewModel("!spaceroom:server")).not.toThrow();
|
|
// Old rooms from the home space should not be accessible
|
|
expect(() => viewModel.getRoomItemViewModel("!room1:server")).toThrow();
|
|
});
|
|
});
|
|
|
|
describe("Active room tracking", () => {
|
|
it("should update active room index when room is selected", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue("!room2:server");
|
|
|
|
dispatcher.dispatch({
|
|
action: Action.ActiveRoomChanged,
|
|
oldRoomId: "!room1:server",
|
|
newRoomId: "!room2:server",
|
|
});
|
|
|
|
// Use setTimeout to allow the dispatcher callback to run
|
|
await flushPromises();
|
|
expect(viewModel.getSnapshot().roomListState.activeRoomIndex).toBe(1);
|
|
});
|
|
|
|
it("should return undefined active room index when no room is selected", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue(null);
|
|
|
|
dispatcher.dispatch({
|
|
action: Action.ActiveRoomChanged,
|
|
oldRoomId: "!room1:server",
|
|
newRoomId: null,
|
|
});
|
|
|
|
// Use setTimeout to allow the dispatcher callback to run
|
|
await flushPromises();
|
|
expect(viewModel.getSnapshot().roomListState.activeRoomIndex).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe("Sticky room behavior", () => {
|
|
it("should keep selected room at same index when room list updates", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
// Select room at index 1
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue("!room2:server");
|
|
dispatcher.dispatch({
|
|
action: Action.ActiveRoomChanged,
|
|
newRoomId: "!room2:server",
|
|
});
|
|
|
|
await flushPromises();
|
|
expect(viewModel.getSnapshot().roomListState.activeRoomIndex).toBe(1);
|
|
|
|
// Simulate room list update that would move room2 to front
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "home",
|
|
rooms: [room2, room1, room3], // room2 moved to front
|
|
});
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsUpdate);
|
|
|
|
// Active room should still be at index 1 (sticky behavior)
|
|
expect(viewModel.getSnapshot().roomListState.activeRoomIndex).toBe(1);
|
|
expect(viewModel.getSnapshot().sections[0].roomIds[1]).toBe("!room2:server");
|
|
});
|
|
|
|
it("should not apply sticky behavior when user changes rooms", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
// Select room at index 1
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue("!room2:server");
|
|
dispatcher.dispatch({
|
|
action: Action.ActiveRoomChanged,
|
|
newRoomId: "!room2:server",
|
|
});
|
|
|
|
await flushPromises();
|
|
|
|
// User switches to room3
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue("!room3:server");
|
|
dispatcher.dispatch({
|
|
action: Action.ActiveRoomChanged,
|
|
oldRoomId: "!room2:server",
|
|
newRoomId: "!room3:server",
|
|
});
|
|
|
|
await flushPromises();
|
|
expect(viewModel.getSnapshot().roomListState.activeRoomIndex).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe("Filters", () => {
|
|
it("should toggle filter on", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
expect(viewModel.getSnapshot().activeFilterId).toBeUndefined();
|
|
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "home",
|
|
rooms: [room1],
|
|
filterKeys: [FilterKey.UnreadFilter],
|
|
});
|
|
|
|
viewModel.onToggleFilter("unread");
|
|
|
|
expect(viewModel.getSnapshot().activeFilterId).toBe("unread");
|
|
expect(viewModel.getSnapshot().sections[0].roomIds).toEqual(["!room1:server"]);
|
|
});
|
|
|
|
it("should toggle filter off", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
// Turn filter on
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "home",
|
|
rooms: [room1],
|
|
filterKeys: [FilterKey.UnreadFilter],
|
|
});
|
|
viewModel.onToggleFilter("unread");
|
|
|
|
expect(viewModel.getSnapshot().activeFilterId).toBe("unread");
|
|
|
|
// Turn filter off
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "home",
|
|
rooms: [room1, room2, room3],
|
|
});
|
|
viewModel.onToggleFilter("unread");
|
|
|
|
expect(viewModel.getSnapshot().activeFilterId).toBeUndefined();
|
|
expect(viewModel.getSnapshot().sections[0].roomIds).toEqual([
|
|
"!room1:server",
|
|
"!room2:server",
|
|
"!room3:server",
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("Room item view models", () => {
|
|
it("should create room item view model on demand", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const itemViewModel = viewModel.getRoomItemViewModel("!room1:server");
|
|
|
|
expect(itemViewModel).toBeDefined();
|
|
expect(itemViewModel.getSnapshot().room).toBe(room1);
|
|
});
|
|
|
|
it("should reuse existing room item view model", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const itemViewModel1 = viewModel.getRoomItemViewModel("!room1:server");
|
|
const itemViewModel2 = viewModel.getRoomItemViewModel("!room1:server");
|
|
|
|
expect(itemViewModel1).toBe(itemViewModel2);
|
|
});
|
|
|
|
it("should throw error when requesting view model for non-existent room", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
expect(() => {
|
|
viewModel.getRoomItemViewModel("!nonexistent:server");
|
|
}).toThrow();
|
|
});
|
|
|
|
it("should not throw when requesting view model for a room removed from the list but still in roomsMap", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
// Normal list update removes room2 from the list
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "home",
|
|
rooms: [room1, room3],
|
|
});
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsUpdate);
|
|
|
|
expect(() => viewModel.getRoomItemViewModel("!room2:server")).not.toThrow();
|
|
});
|
|
|
|
it("should throw when requesting view model for a room from old space after space change", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const spaceRoom = mkStubRoom("!newroom:server", "New Room", matrixClient);
|
|
|
|
// Space change: new space only has spaceRoom
|
|
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockReturnValue({
|
|
spaceId: "!space:server",
|
|
rooms: [spaceRoom],
|
|
});
|
|
jest.spyOn(SpaceStore.instance, "getLastSelectedRoomIdForSpace").mockReturnValue(null);
|
|
|
|
RoomListStoreV3.instance.emit(RoomListStoreV3Event.ListsUpdate);
|
|
|
|
expect(() => viewModel.getRoomItemViewModel("!room1:server")).toThrow(
|
|
"Room !room1:server not found in roomsMap",
|
|
);
|
|
});
|
|
|
|
it("should recover when roomsMap is stale but roomsResult has the room", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
// Manually clear roomsMap to simulate stale cache, but keep roomsResult intact
|
|
(viewModel as any).roomsMap.clear();
|
|
|
|
// getRoomItemViewModel should retry by re-populating roomsMap from roomsResult
|
|
expect(() => viewModel.getRoomItemViewModel("!room1:server")).not.toThrow();
|
|
});
|
|
|
|
it("should dispose view models for rooms no longer visible", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const vm1 = viewModel.getRoomItemViewModel("!room1:server");
|
|
const vm2 = viewModel.getRoomItemViewModel("!room2:server");
|
|
const vm3 = viewModel.getRoomItemViewModel("!room3:server");
|
|
|
|
const disposeSpy1 = jest.spyOn(vm1, "dispose");
|
|
const disposeSpy3 = jest.spyOn(vm3, "dispose");
|
|
|
|
// Update to show only middle room (index 1)
|
|
viewModel.updateVisibleRooms(1, 2);
|
|
|
|
expect(disposeSpy1).toHaveBeenCalled();
|
|
expect(disposeSpy3).toHaveBeenCalled();
|
|
|
|
// vm2 should still exist
|
|
const vm2Again = viewModel.getRoomItemViewModel("!room2:server");
|
|
expect(vm2Again).toBe(vm2);
|
|
});
|
|
});
|
|
|
|
describe("Room creation", () => {
|
|
it("should dispatch CreateChat action when createChatRoom is called", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "fire");
|
|
|
|
viewModel.createChatRoom();
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith(Action.CreateChat);
|
|
});
|
|
|
|
it("should dispatch CreateRoom action without parent space", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
|
|
viewModel.createRoom();
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith({
|
|
action: Action.CreateRoom,
|
|
});
|
|
});
|
|
|
|
it("should dispatch CreateRoom action with parent space", () => {
|
|
const spaceRoom = mkStubRoom("!space:server", "Space", matrixClient);
|
|
jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(spaceRoom);
|
|
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
|
|
viewModel.createRoom();
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith({
|
|
action: Action.CreateRoom,
|
|
parent_space: spaceRoom,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Keyboard navigation (ViewRoomDelta)", () => {
|
|
beforeEach(() => {
|
|
// stubClient sets up MatrixClientPeg which is needed when ViewRoom action is dispatched
|
|
stubClient();
|
|
});
|
|
|
|
it("should navigate to next room when delta is 1", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue("!room1:server");
|
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
|
|
dispatcher.dispatch({
|
|
action: Action.ViewRoomDelta,
|
|
delta: 1,
|
|
unread: false,
|
|
});
|
|
|
|
await flushPromises();
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
action: Action.ViewRoom,
|
|
room_id: "!room2:server",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("should navigate to previous room when delta is -1", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue("!room2:server");
|
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
|
|
dispatcher.dispatch({
|
|
action: Action.ViewRoomDelta,
|
|
delta: -1,
|
|
unread: false,
|
|
});
|
|
|
|
await flushPromises();
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
action: Action.ViewRoom,
|
|
room_id: "!room1:server",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("should wrap around to last room when navigating backwards from first room", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue("!room1:server");
|
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
|
|
dispatcher.dispatch({
|
|
action: Action.ViewRoomDelta,
|
|
delta: -1,
|
|
unread: false,
|
|
});
|
|
|
|
await flushPromises();
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
action: Action.ViewRoom,
|
|
room_id: "!room3:server",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("should not navigate when current room is not found", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue("!unknown:server");
|
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
dispatchSpy.mockClear();
|
|
|
|
dispatcher.dispatch({
|
|
action: Action.ViewRoomDelta,
|
|
delta: 1,
|
|
unread: false,
|
|
});
|
|
|
|
await flushPromises();
|
|
|
|
// Should not dispatch ViewRoom since current room wasn't found
|
|
expect(dispatchSpy).not.toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
action: Action.ViewRoom,
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("should not navigate when no room is selected", async () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue(null);
|
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
dispatchSpy.mockClear();
|
|
|
|
dispatcher.dispatch({
|
|
action: Action.ViewRoomDelta,
|
|
delta: 1,
|
|
unread: false,
|
|
});
|
|
|
|
await flushPromises();
|
|
|
|
expect(dispatchSpy).not.toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
action: Action.ViewRoom,
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Cleanup", () => {
|
|
it("should dispose all room item view models on dispose", () => {
|
|
viewModel = new RoomListViewModel({ client: matrixClient });
|
|
|
|
const vm1 = viewModel.getRoomItemViewModel("!room1:server");
|
|
const vm2 = viewModel.getRoomItemViewModel("!room2:server");
|
|
|
|
const disposeSpy1 = jest.spyOn(vm1, "dispose");
|
|
const disposeSpy2 = jest.spyOn(vm2, "dispose");
|
|
|
|
viewModel.dispose();
|
|
|
|
expect(disposeSpy1).toHaveBeenCalled();
|
|
expect(disposeSpy2).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|