You've already forked matrix-react-sdk
mirror of
https://github.com/matrix-org/matrix-react-sdk.git
synced 2025-08-07 21:23:00 +03:00
Don't aggregate rooms and users in SpaceStore (#7723)
* add direct child maps * track rooms, users and space children in flat hierarchy in spacestore Signed-off-by: Kerry Archibald <kerrya@element.io> * update spacefiltercondition to use new spacestore * remove unused code Signed-off-by: Kerry Archibald <kerrya@element.io> * typos Signed-off-by: Kerry Archibald <kerrya@element.io> * only build flattened rooms set once per space when updating notifs * copyright Signed-off-by: Kerry Archibald <kerrya@element.io> * remove unnecessary currying Signed-off-by: Kerry Archibald <kerrya@element.io> * rename SpaceStore spaceFilteredRooms => roomsIdsBySpace, spaceFilteredUsers => userIdsBySpace Signed-off-by: Kerry Archibald <kerrya@element.io> * cache aggregates rooms and users by space Signed-off-by: Kerry Archibald <kerrya@element.io> * emit events recursively up parent spaces on changes Signed-off-by: Kerry Archibald <kerrya@element.io> * exclude meta spaces from aggregate cache Signed-off-by: Kerry Archibald <kerrya@element.io> * stray log * fix emit on member update Signed-off-by: Kerry Archibald <kerrya@element.io> * call order Signed-off-by: Kerry Archibald <kerrya@element.io> * extend existing getKnownParents fn Signed-off-by: Kerry Archibald <kerrya@element.io> * refine types and comments Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
@@ -18,6 +18,7 @@ import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
|
||||
import "../skinned-sdk"; // Must be first for skinning to work
|
||||
|
||||
import SpaceStore from "../../src/stores/spaces/SpaceStore";
|
||||
import {
|
||||
MetaSpace,
|
||||
@@ -58,9 +59,11 @@ const invite2 = "!invite2:server";
|
||||
const room1 = "!room1:server";
|
||||
const room2 = "!room2:server";
|
||||
const room3 = "!room3:server";
|
||||
const room4 = "!room4:server";
|
||||
const space1 = "!space1:server";
|
||||
const space2 = "!space2:server";
|
||||
const space3 = "!space3:server";
|
||||
const space4 = "!space4:server";
|
||||
|
||||
const getUserIdForRoomId = jest.fn(roomId => {
|
||||
return {
|
||||
@@ -303,11 +306,13 @@ describe("SpaceStore", () => {
|
||||
|
||||
describe("test fixture 1", () => {
|
||||
beforeEach(async () => {
|
||||
[fav1, fav2, fav3, dm1, dm2, dm3, orphan1, orphan2, invite1, invite2, room1, room2, room3]
|
||||
[fav1, fav2, fav3, dm1, dm2, dm3, orphan1, orphan2, invite1, invite2, room1, room2, room3, room4]
|
||||
.forEach(mkRoom);
|
||||
mkSpace(space1, [fav1, room1]);
|
||||
mkSpace(space2, [fav1, fav2, fav3, room1]);
|
||||
mkSpace(space3, [invite2]);
|
||||
mkSpace(space4, [room4, fav2, space2, space3]);
|
||||
|
||||
client.getRoom.mockImplementation(roomId => rooms.find(room => room.roomId === roomId));
|
||||
|
||||
[fav1, fav2, fav3].forEach(roomId => {
|
||||
@@ -383,85 +388,144 @@ describe("SpaceStore", () => {
|
||||
await run();
|
||||
});
|
||||
|
||||
it("home space contains orphaned rooms", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, orphan1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, orphan2)).toBeTruthy();
|
||||
});
|
||||
describe('isRoomInSpace()', () => {
|
||||
it("home space contains orphaned rooms", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, orphan1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, orphan2)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("home space does not contain all favourites", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, fav1)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, fav2)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, fav3)).toBeFalsy();
|
||||
});
|
||||
it("home space does not contain all favourites", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, fav1)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, fav2)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, fav3)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("home space contains dm rooms", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, dm1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, dm2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, dm3)).toBeTruthy();
|
||||
});
|
||||
it("home space contains dm rooms", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, dm1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, dm2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, dm3)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("home space contains invites", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, invite1)).toBeTruthy();
|
||||
});
|
||||
it("home space contains invites", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, invite1)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("home space contains invites even if they are also shown in a space", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, invite2)).toBeTruthy();
|
||||
});
|
||||
it("home space contains invites even if they are also shown in a space", () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, invite2)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("all rooms space does contain rooms/low priority even if they are also shown in a space", async () => {
|
||||
await setShowAllRooms(true);
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, room1)).toBeTruthy();
|
||||
});
|
||||
it(
|
||||
"all rooms space does contain rooms/low priority even if they are also shown in a space",
|
||||
async () => {
|
||||
await setShowAllRooms(true);
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, room1)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("favourites space does contain favourites even if they are also shown in a space", async () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Favourites, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Favourites, fav2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Favourites, fav3)).toBeTruthy();
|
||||
});
|
||||
it("favourites space does contain favourites even if they are also shown in a space", async () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.Favourites, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Favourites, fav2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Favourites, fav3)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("people space does contain people even if they are also shown in a space", async () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.People, dm1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.People, dm2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.People, dm3)).toBeTruthy();
|
||||
});
|
||||
it("people space does contain people even if they are also shown in a space", async () => {
|
||||
expect(store.isRoomInSpace(MetaSpace.People, dm1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.People, dm2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.People, dm3)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("orphans space does contain orphans even if they are also shown in all rooms", async () => {
|
||||
await setShowAllRooms(true);
|
||||
expect(store.isRoomInSpace(MetaSpace.Orphans, orphan1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Orphans, orphan2)).toBeTruthy();
|
||||
});
|
||||
it("orphans space does contain orphans even if they are also shown in all rooms", async () => {
|
||||
await setShowAllRooms(true);
|
||||
expect(store.isRoomInSpace(MetaSpace.Orphans, orphan1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Orphans, orphan2)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("home space doesn't contain rooms/low priority if they are also shown in a space", async () => {
|
||||
await setShowAllRooms(false);
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, room1)).toBeFalsy();
|
||||
});
|
||||
it("home space doesn't contain rooms/low priority if they are also shown in a space", async () => {
|
||||
await setShowAllRooms(false);
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, room1)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("space contains child rooms", () => {
|
||||
expect(store.isRoomInSpace(space1, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space1, room1)).toBeTruthy();
|
||||
});
|
||||
it("space contains child rooms", () => {
|
||||
expect(store.isRoomInSpace(space1, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space1, room1)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("space contains child favourites", () => {
|
||||
expect(store.isRoomInSpace(space2, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space2, fav2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space2, fav3)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space2, room1)).toBeTruthy();
|
||||
});
|
||||
it("returns true for all sub-space child rooms when includeSubSpaceRooms is undefined", () => {
|
||||
expect(store.isRoomInSpace(space4, room4)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, fav2)).toBeTruthy();
|
||||
// space2's rooms
|
||||
expect(store.isRoomInSpace(space4, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, fav3)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, room1)).toBeTruthy();
|
||||
// space3's rooms
|
||||
expect(store.isRoomInSpace(space4, invite2)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("space contains child invites", () => {
|
||||
expect(store.isRoomInSpace(space3, invite2)).toBeTruthy();
|
||||
});
|
||||
it("returns true for all sub-space child rooms when includeSubSpaceRooms is true", () => {
|
||||
expect(store.isRoomInSpace(space4, room4, true)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, fav2, true)).toBeTruthy();
|
||||
// space2's rooms
|
||||
expect(store.isRoomInSpace(space4, fav1, true)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, fav3, true)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, room1, true)).toBeTruthy();
|
||||
// space3's rooms
|
||||
expect(store.isRoomInSpace(space4, invite2, true)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("spaces contain dms which you have with members of that space", () => {
|
||||
expect(store.isRoomInSpace(space1, dm1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space2, dm1)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space3, dm1)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space1, dm2)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space2, dm2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space3, dm2)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space1, dm3)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space2, dm3)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space3, dm3)).toBeFalsy();
|
||||
it("returns false for all sub-space child rooms when includeSubSpaceRooms is false", () => {
|
||||
// direct children
|
||||
expect(store.isRoomInSpace(space4, room4, false)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, fav2, false)).toBeTruthy();
|
||||
// space2's rooms
|
||||
expect(store.isRoomInSpace(space4, fav1, false)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space4, fav3, false)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space4, room1, false)).toBeFalsy();
|
||||
// space3's rooms
|
||||
expect(store.isRoomInSpace(space4, invite2, false)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("space contains all sub-space's child rooms", () => {
|
||||
expect(store.isRoomInSpace(space4, room4)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, fav2)).toBeTruthy();
|
||||
// space2's rooms
|
||||
expect(store.isRoomInSpace(space4, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, fav3)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, room1)).toBeTruthy();
|
||||
// space3's rooms
|
||||
expect(store.isRoomInSpace(space4, invite2)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("space contains child favourites", () => {
|
||||
expect(store.isRoomInSpace(space2, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space2, fav2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space2, fav3)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space2, room1)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("space contains child invites", () => {
|
||||
expect(store.isRoomInSpace(space3, invite2)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("spaces contain dms which you have with members of that space", () => {
|
||||
expect(store.isRoomInSpace(space1, dm1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space2, dm1)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space3, dm1)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space1, dm2)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space2, dm2)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space3, dm2)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space1, dm3)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space2, dm3)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space3, dm3)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('uses cached aggregated rooms', () => {
|
||||
const rooms = store.getSpaceFilteredRoomIds(space4, true);
|
||||
expect(store.isRoomInSpace(space4, fav1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, fav3)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(space4, room1)).toBeTruthy();
|
||||
|
||||
// isRoomInSpace calls didn't rebuild room set
|
||||
expect(rooms).toStrictEqual(store.getSpaceFilteredRoomIds(space4, true));
|
||||
});
|
||||
});
|
||||
|
||||
it("dms are only added to Notification States for only the People Space", async () => {
|
||||
@@ -614,6 +678,115 @@ describe("SpaceStore", () => {
|
||||
expect(store.isRoomInSpace(space1, invite1)).toBeTruthy();
|
||||
expect(store.isRoomInSpace(MetaSpace.Home, invite1)).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('onRoomsUpdate()', () => {
|
||||
beforeEach(() => {
|
||||
[fav1, fav2, fav3, dm1, dm2, dm3, orphan1, orphan2, invite1, invite2, room1, room2, room3, room4]
|
||||
.forEach(mkRoom);
|
||||
mkSpace(space2, [fav1, fav2, fav3, room1]);
|
||||
mkSpace(space3, [invite2]);
|
||||
mkSpace(space4, [room4, fav2, space2, space3]);
|
||||
mkSpace(space1, [fav1, room1, space4]);
|
||||
});
|
||||
|
||||
const addChildRoom = (spaceId, childId) => {
|
||||
const childEvent = mkEvent({
|
||||
event: true,
|
||||
type: EventType.SpaceChild,
|
||||
room: spaceId,
|
||||
user: client.getUserId(),
|
||||
skey: childId,
|
||||
content: { via: [], canonical: true },
|
||||
ts: Date.now(),
|
||||
});
|
||||
const spaceRoom = client.getRoom(spaceId);
|
||||
spaceRoom.currentState.getStateEvents.mockImplementation(
|
||||
testUtils.mockStateEventImplementation([childEvent]),
|
||||
);
|
||||
|
||||
client.emit("RoomState.events", childEvent);
|
||||
};
|
||||
|
||||
const addMember = (spaceId, user: RoomMember) => {
|
||||
const memberEvent = mkEvent({
|
||||
event: true,
|
||||
type: EventType.RoomMember,
|
||||
room: spaceId,
|
||||
user: client.getUserId(),
|
||||
skey: user.userId,
|
||||
content: { membership: 'join' },
|
||||
ts: Date.now(),
|
||||
});
|
||||
const spaceRoom = client.getRoom(spaceId);
|
||||
spaceRoom.currentState.getStateEvents.mockImplementation(
|
||||
testUtils.mockStateEventImplementation([memberEvent]),
|
||||
);
|
||||
spaceRoom.getMember.mockReturnValue(user);
|
||||
|
||||
client.emit("RoomState.members", memberEvent);
|
||||
};
|
||||
|
||||
it('emits events for parent spaces when child room is added', async () => {
|
||||
await run();
|
||||
|
||||
const room5 = mkRoom('!room5:server');
|
||||
const emitSpy = jest.spyOn(store, 'emit').mockClear();
|
||||
// add room5 into space2
|
||||
addChildRoom(space2, room5.roomId);
|
||||
|
||||
expect(emitSpy).toHaveBeenCalledWith(space2);
|
||||
// space2 is subspace of space4
|
||||
expect(emitSpy).toHaveBeenCalledWith(space4);
|
||||
// space4 is a subspace of space1
|
||||
expect(emitSpy).toHaveBeenCalledWith(space1);
|
||||
expect(emitSpy).not.toHaveBeenCalledWith(space3);
|
||||
});
|
||||
|
||||
it('updates rooms state when a child room is added', async () => {
|
||||
await run();
|
||||
const room5 = mkRoom('!room5:server');
|
||||
|
||||
expect(store.isRoomInSpace(space2, room5.roomId)).toBeFalsy();
|
||||
expect(store.isRoomInSpace(space4, room5.roomId)).toBeFalsy();
|
||||
|
||||
// add room5 into space2
|
||||
addChildRoom(space2, room5.roomId);
|
||||
|
||||
expect(store.isRoomInSpace(space2, room5.roomId)).toBeTruthy();
|
||||
// space2 is subspace of space4
|
||||
expect(store.isRoomInSpace(space4, room5.roomId)).toBeTruthy();
|
||||
// space4 is subspace of space1
|
||||
expect(store.isRoomInSpace(space1, room5.roomId)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('emits events for parent spaces when a member is added', async () => {
|
||||
await run();
|
||||
|
||||
const emitSpy = jest.spyOn(store, 'emit').mockClear();
|
||||
// add into space2
|
||||
addMember(space2, dm1Partner);
|
||||
|
||||
expect(emitSpy).toHaveBeenCalledWith(space2);
|
||||
// space2 is subspace of space4
|
||||
expect(emitSpy).toHaveBeenCalledWith(space4);
|
||||
// space4 is a subspace of space1
|
||||
expect(emitSpy).toHaveBeenCalledWith(space1);
|
||||
expect(emitSpy).not.toHaveBeenCalledWith(space3);
|
||||
});
|
||||
|
||||
it('updates users state when a member is added', async () => {
|
||||
await run();
|
||||
|
||||
expect(store.getSpaceFilteredUserIds(space2)).toEqual(new Set([]));
|
||||
|
||||
// add into space2
|
||||
addMember(space2, dm1Partner);
|
||||
|
||||
expect(store.getSpaceFilteredUserIds(space2)).toEqual(new Set([dm1Partner.userId]));
|
||||
expect(store.getSpaceFilteredUserIds(space4)).toEqual(new Set([dm1Partner.userId]));
|
||||
expect(store.getSpaceFilteredUserIds(space1)).toEqual(new Set([dm1Partner.userId]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("active space switching tests", () => {
|
||||
|
196
test/stores/room-list/filters/SpaceFilterCondition-test.ts
Normal file
196
test/stores/room-list/filters/SpaceFilterCondition-test.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 { mocked } from 'jest-mock';
|
||||
|
||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { FILTER_CHANGED } from "../../../../src/stores/room-list/filters/IFilterCondition";
|
||||
import { SpaceFilterCondition } from "../../../../src/stores/room-list/filters/SpaceFilterCondition";
|
||||
import { MetaSpace } from "../../../../src/stores/spaces";
|
||||
import SpaceStore from "../../../../src/stores/spaces/SpaceStore";
|
||||
|
||||
jest.mock("../../../../src/settings/SettingsStore");
|
||||
jest.mock("../../../../src/stores/spaces/SpaceStore", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const EventEmitter = require('events');
|
||||
class MockSpaceStore extends EventEmitter {
|
||||
isRoomInSpace = jest.fn();
|
||||
getSpaceFilteredUserIds = jest.fn().mockReturnValue(new Set<string>([]));
|
||||
getSpaceFilteredRoomIds = jest.fn().mockReturnValue(new Set<string>([]));
|
||||
}
|
||||
return { instance: new MockSpaceStore() };
|
||||
});
|
||||
|
||||
const SettingsStoreMock = mocked(SettingsStore);
|
||||
const SpaceStoreInstanceMock = mocked(SpaceStore.instance);
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe('SpaceFilterCondition', () => {
|
||||
const space1 = '!space1:server';
|
||||
const space2 = '!space2:server';
|
||||
const room1Id = '!r1:server';
|
||||
const room2Id = '!r2:server';
|
||||
const room3Id = '!r3:server';
|
||||
const user1Id = '@u1:server';
|
||||
const user2Id = '@u2:server';
|
||||
const user3Id = '@u3:server';
|
||||
const makeMockGetValue = (settings = {}) => (settingName, space) => settings[settingName]?.[space] || false;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
SettingsStoreMock.getValue.mockClear().mockImplementation(makeMockGetValue());
|
||||
SpaceStoreInstanceMock.getSpaceFilteredUserIds.mockReturnValue(new Set([]));
|
||||
SpaceStoreInstanceMock.isRoomInSpace.mockReturnValue(true);
|
||||
});
|
||||
|
||||
const initFilter = (space): SpaceFilterCondition => {
|
||||
const filter = new SpaceFilterCondition();
|
||||
filter.updateSpace(space);
|
||||
jest.runOnlyPendingTimers();
|
||||
return filter;
|
||||
};
|
||||
|
||||
describe('isVisible', () => {
|
||||
const room1 = { roomId: room1Id } as unknown as Room;
|
||||
it('calls isRoomInSpace correctly', () => {
|
||||
const filter = initFilter(space1);
|
||||
|
||||
expect(filter.isVisible(room1)).toEqual(true);
|
||||
expect(SpaceStoreInstanceMock.isRoomInSpace).toHaveBeenCalledWith(space1, room1Id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onStoreUpdate', () => {
|
||||
it('emits filter changed event when updateSpace is called even without changes', async () => {
|
||||
const filter = new SpaceFilterCondition();
|
||||
const emitSpy = jest.spyOn(filter, 'emit');
|
||||
filter.updateSpace(space1);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(emitSpy).toHaveBeenCalledWith(FILTER_CHANGED);
|
||||
});
|
||||
|
||||
describe('showPeopleInSpace setting', () => {
|
||||
it('emits filter changed event when setting changes', async () => {
|
||||
// init filter with setting true for space1
|
||||
SettingsStoreMock.getValue.mockImplementation(makeMockGetValue({
|
||||
["Spaces.showPeopleInSpace"]: { [space1]: true },
|
||||
}));
|
||||
const filter = initFilter(space1);
|
||||
const emitSpy = jest.spyOn(filter, 'emit');
|
||||
|
||||
SettingsStoreMock.getValue.mockClear().mockImplementation(makeMockGetValue({
|
||||
["Spaces.showPeopleInSpace"]: { [space1]: false },
|
||||
}));
|
||||
|
||||
SpaceStoreInstanceMock.emit(space1);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(emitSpy).toHaveBeenCalledWith(FILTER_CHANGED);
|
||||
});
|
||||
|
||||
it('emits filter changed event when setting is false and space changes to a meta space', async () => {
|
||||
// init filter with setting true for space1
|
||||
SettingsStoreMock.getValue.mockImplementation(makeMockGetValue({
|
||||
["Spaces.showPeopleInSpace"]: { [space1]: false },
|
||||
}));
|
||||
const filter = initFilter(space1);
|
||||
const emitSpy = jest.spyOn(filter, 'emit');
|
||||
|
||||
filter.updateSpace(MetaSpace.Home);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(emitSpy).toHaveBeenCalledWith(FILTER_CHANGED);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not emit filter changed event on store update when nothing changed', async () => {
|
||||
const filter = initFilter(space1);
|
||||
const emitSpy = jest.spyOn(filter, 'emit');
|
||||
SpaceStoreInstanceMock.emit(space1);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(emitSpy).not.toHaveBeenCalledWith(FILTER_CHANGED);
|
||||
});
|
||||
|
||||
it('removes listener when updateSpace is called', async () => {
|
||||
const filter = initFilter(space1);
|
||||
filter.updateSpace(space2);
|
||||
jest.runOnlyPendingTimers();
|
||||
const emitSpy = jest.spyOn(filter, 'emit');
|
||||
|
||||
// update mock so filter would emit change if it was listening to space1
|
||||
SpaceStoreInstanceMock.getSpaceFilteredRoomIds.mockReturnValue(new Set([room1Id]));
|
||||
SpaceStoreInstanceMock.emit(space1);
|
||||
jest.runOnlyPendingTimers();
|
||||
// no filter changed event
|
||||
expect(emitSpy).not.toHaveBeenCalledWith(FILTER_CHANGED);
|
||||
});
|
||||
|
||||
it('removes listener when destroy is called', async () => {
|
||||
const filter = initFilter(space1);
|
||||
filter.destroy();
|
||||
jest.runOnlyPendingTimers();
|
||||
const emitSpy = jest.spyOn(filter, 'emit');
|
||||
|
||||
// update mock so filter would emit change if it was listening to space1
|
||||
SpaceStoreInstanceMock.getSpaceFilteredRoomIds.mockReturnValue(new Set([room1Id]));
|
||||
SpaceStoreInstanceMock.emit(space1);
|
||||
jest.runOnlyPendingTimers();
|
||||
// no filter changed event
|
||||
expect(emitSpy).not.toHaveBeenCalledWith(FILTER_CHANGED);
|
||||
});
|
||||
|
||||
describe('when directChildRoomIds change', () => {
|
||||
beforeEach(() => {
|
||||
SpaceStoreInstanceMock.getSpaceFilteredRoomIds.mockReturnValue(new Set([room1Id, room2Id]));
|
||||
});
|
||||
const filterChangedCases = [
|
||||
['room added', [room1Id, room2Id, room3Id]],
|
||||
['room removed', [room1Id]],
|
||||
['room swapped', [room1Id, room3Id]], // same number of rooms with changes
|
||||
];
|
||||
|
||||
it.each(filterChangedCases)('%s', (_d, rooms) => {
|
||||
const filter = initFilter(space1);
|
||||
const emitSpy = jest.spyOn(filter, 'emit');
|
||||
|
||||
SpaceStoreInstanceMock.getSpaceFilteredRoomIds.mockReturnValue(new Set(rooms));
|
||||
SpaceStoreInstanceMock.emit(space1);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(emitSpy).toHaveBeenCalledWith(FILTER_CHANGED);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user ids change', () => {
|
||||
beforeEach(() => {
|
||||
SpaceStoreInstanceMock.getSpaceFilteredUserIds.mockReturnValue(new Set([user1Id, user2Id]));
|
||||
});
|
||||
const filterChangedCases = [
|
||||
['user added', [user1Id, user2Id, user3Id]],
|
||||
['user removed', [user1Id]],
|
||||
['user swapped', [user1Id, user3Id]], // same number of rooms with changes
|
||||
];
|
||||
|
||||
it.each(filterChangedCases)('%s', (_d, rooms) => {
|
||||
const filter = initFilter(space1);
|
||||
const emitSpy = jest.spyOn(filter, 'emit');
|
||||
|
||||
SpaceStoreInstanceMock.getSpaceFilteredUserIds.mockReturnValue(new Set(rooms));
|
||||
SpaceStoreInstanceMock.emit(space1);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(emitSpy).toHaveBeenCalledWith(FILTER_CHANGED);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user