element-web/test/SlidingSyncManager-test.ts
kegsay acdcda78f0
sliding sync: add lazy-loading member support (#9530)
* sliding sync: add lazy-loading member support

Also swap to `$ME` constants when referring to our own member event.

* Hook into existing LL logic when showing the MemberList

* Linting

* Use consts in js sdk not react sdk

* Add jest tests

* linting

* Store the room in the test

* Fix up getRoom impl

* Add MemberListStore

* Use the right context in MemberList tests

* Fix RightPanel-test

* Always return members even if we lazy load

* Add MemberListStore tests

* Additional tests
2022-11-18 19:05:00 +00:00

158 lines
6.7 KiB
TypeScript

/*
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 { SlidingSync } from 'matrix-js-sdk/src/sliding-sync';
import { mocked } from 'jest-mock';
import { MatrixClient, MatrixEvent, Room } from 'matrix-js-sdk/src/matrix';
import { SlidingSyncManager } from '../src/SlidingSyncManager';
import { stubClient } from './test-utils';
jest.mock('matrix-js-sdk/src/sliding-sync');
const MockSlidingSync = <jest.Mock<SlidingSync>><unknown>SlidingSync;
describe('SlidingSyncManager', () => {
let manager: SlidingSyncManager;
let slidingSync: SlidingSync;
let client: MatrixClient;
beforeEach(() => {
slidingSync = new MockSlidingSync();
manager = new SlidingSyncManager();
client = stubClient();
// by default the client has no rooms: stubClient magically makes rooms annoyingly.
mocked(client.getRoom).mockReturnValue(null);
manager.configure(client, "invalid");
manager.slidingSync = slidingSync;
});
describe("setRoomVisible", () => {
it("adds a subscription for the room", async () => {
const roomId = "!room:id";
const subs = new Set<string>();
mocked(slidingSync.getRoomSubscriptions).mockReturnValue(subs);
mocked(slidingSync.modifyRoomSubscriptions).mockResolvedValue("yep");
await manager.setRoomVisible(roomId, true);
expect(slidingSync.modifyRoomSubscriptions).toBeCalledWith(new Set<string>([roomId]));
});
it("adds a custom subscription for a lazy-loadable room", async () => {
const roomId = "!lazy:id";
const room = new Room(roomId, client, client.getUserId());
room.getLiveTimeline().initialiseState([
new MatrixEvent({
type: "m.room.create",
state_key: "",
event_id: "$abc123",
sender: client.getUserId(),
content: {
creator: client.getUserId(),
},
}),
]);
mocked(client.getRoom).mockImplementation((r: string): Room => {
if (roomId === r) {
return room;
}
return null;
});
const subs = new Set<string>();
mocked(slidingSync.getRoomSubscriptions).mockReturnValue(subs);
mocked(slidingSync.modifyRoomSubscriptions).mockResolvedValue("yep");
await manager.setRoomVisible(roomId, true);
expect(slidingSync.modifyRoomSubscriptions).toBeCalledWith(new Set<string>([roomId]));
// we aren't prescriptive about what the sub name is.
expect(slidingSync.useCustomSubscription).toBeCalledWith(roomId, expect.anything());
});
});
describe("startSpidering", () => {
it("requests in batchSizes", async () => {
const gapMs = 1;
const batchSize = 10;
mocked(slidingSync.setList).mockResolvedValue("yep");
mocked(slidingSync.setListRanges).mockResolvedValue("yep");
mocked(slidingSync.getListData).mockImplementation((i) => {
return {
joinedCount: 64,
roomIndexToRoomId: {},
};
});
await manager.startSpidering(batchSize, gapMs);
// we expect calls for 10,19 -> 20,29 -> 30,39 -> 40,49 -> 50,59 -> 60,69
const wantWindows = [
[10, 19], [20, 29], [30, 39], [40, 49], [50, 59], [60, 69],
];
expect(slidingSync.getListData).toBeCalledTimes(wantWindows.length);
expect(slidingSync.setList).toBeCalledTimes(1);
expect(slidingSync.setListRanges).toBeCalledTimes(wantWindows.length-1);
wantWindows.forEach((range, i) => {
if (i === 0) {
expect(slidingSync.setList).toBeCalledWith(
manager.getOrAllocateListIndex(SlidingSyncManager.ListSearch),
expect.objectContaining({
ranges: [[0, batchSize-1], range],
}),
);
return;
}
expect(slidingSync.setListRanges).toBeCalledWith(
manager.getOrAllocateListIndex(SlidingSyncManager.ListSearch),
[[0, batchSize-1], range],
);
});
});
it("handles accounts with zero rooms", async () => {
const gapMs = 1;
const batchSize = 10;
mocked(slidingSync.setList).mockResolvedValue("yep");
mocked(slidingSync.getListData).mockImplementation((i) => {
return {
joinedCount: 0,
roomIndexToRoomId: {},
};
});
await manager.startSpidering(batchSize, gapMs);
expect(slidingSync.getListData).toBeCalledTimes(1);
expect(slidingSync.setList).toBeCalledTimes(1);
expect(slidingSync.setList).toBeCalledWith(
manager.getOrAllocateListIndex(SlidingSyncManager.ListSearch),
expect.objectContaining({
ranges: [[0, batchSize-1], [batchSize, batchSize+batchSize-1]],
}),
);
});
it("continues even when setList rejects", async () => {
const gapMs = 1;
const batchSize = 10;
mocked(slidingSync.setList).mockRejectedValue("narp");
mocked(slidingSync.getListData).mockImplementation((i) => {
return {
joinedCount: 0,
roomIndexToRoomId: {},
};
});
await manager.startSpidering(batchSize, gapMs);
expect(slidingSync.getListData).toBeCalledTimes(1);
expect(slidingSync.setList).toBeCalledTimes(1);
expect(slidingSync.setList).toBeCalledWith(
manager.getOrAllocateListIndex(SlidingSyncManager.ListSearch),
expect.objectContaining({
ranges: [[0, batchSize-1], [batchSize, batchSize+batchSize-1]],
}),
);
});
});
});