You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-09 10:22:46 +03:00
test typescriptification - timeline-window, scheduler, etc (#2539)
* spec/unit/user.spec.js -> spec/unit/user.spec.ts * fix ts in user.spec * renamed: spec/unit/timeline-window.spec.js -> spec/unit/timeline-window.spec.ts * overdo it fixing types in timeline-window.spec * renamed spec/unit/sync-accumulator.spec.js spec/unit/sync-accumulator.spec.ts * fix ts in sync-accumalator.spec * spec/unit/scheduler.spec.js -> spec/unit/scheduler.spec.ts * fix ts in scheduler.spec * missed types in timeline-window spec
This commit is contained in:
@@ -45,8 +45,8 @@ describe("MatrixScheduler", function() {
|
|||||||
queueFn = function() {
|
queueFn = function() {
|
||||||
return "one_big_queue";
|
return "one_big_queue";
|
||||||
};
|
};
|
||||||
const deferA = defer();
|
const deferA = defer<Record<string, boolean>>();
|
||||||
const deferB = defer();
|
const deferB = defer<Record<string, boolean>>();
|
||||||
let yieldedA = false;
|
let yieldedA = false;
|
||||||
scheduler.setProcessFunction(function(event) {
|
scheduler.setProcessFunction(function(event) {
|
||||||
if (yieldedA) {
|
if (yieldedA) {
|
||||||
@@ -89,7 +89,7 @@ describe("MatrixScheduler", function() {
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
} else if (procCount === 2) {
|
} else if (procCount === 2) {
|
||||||
// don't care about this deferred
|
// don't care about this deferred
|
||||||
return new Promise();
|
return new Promise(() => {});
|
||||||
}
|
}
|
||||||
expect(procCount).toBeLessThan(3);
|
expect(procCount).toBeLessThan(3);
|
||||||
});
|
});
|
||||||
@@ -175,7 +175,7 @@ describe("MatrixScheduler", function() {
|
|||||||
const expectOrder = [
|
const expectOrder = [
|
||||||
eventA.getId(), eventB.getId(), eventD.getId(),
|
eventA.getId(), eventB.getId(), eventD.getId(),
|
||||||
];
|
];
|
||||||
const deferA = defer();
|
const deferA = defer<void>();
|
||||||
scheduler.setProcessFunction(function(event) {
|
scheduler.setProcessFunction(function(event) {
|
||||||
const id = expectOrder.shift();
|
const id = expectOrder.shift();
|
||||||
expect(id).toEqual(event.getId());
|
expect(id).toEqual(event.getId());
|
||||||
@@ -191,7 +191,7 @@ describe("MatrixScheduler", function() {
|
|||||||
|
|
||||||
// wait a bit then resolve A and we should get D (not C) next.
|
// wait a bit then resolve A and we should get D (not C) next.
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
deferA.resolve({});
|
deferA.resolve();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
jest.advanceTimersByTime(1000);
|
jest.advanceTimersByTime(1000);
|
||||||
});
|
});
|
||||||
@@ -336,28 +336,29 @@ describe("MatrixScheduler", function() {
|
|||||||
errcode: "M_LIMIT_EXCEEDED", retry_after_ms: 5000,
|
errcode: "M_LIMIT_EXCEEDED", retry_after_ms: 5000,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
expect(res >= 500).toBe(true, "Didn't wait long enough.");
|
expect(res >= 500).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should give up after 5 attempts", function() {
|
it("should give up after 5 attempts", function() {
|
||||||
const res = MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
const res = MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
||||||
eventA, 5, {},
|
eventA, 5, new MatrixError({}),
|
||||||
);
|
);
|
||||||
expect(res).toBe(-1, "Didn't give up.");
|
expect(res).toBe(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should do exponential backoff", function() {
|
it("should do exponential backoff", function() {
|
||||||
|
const error = new MatrixError({});
|
||||||
expect(MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
expect(MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
||||||
eventA, 1, {},
|
eventA, 1, error,
|
||||||
)).toEqual(2000);
|
)).toEqual(2000);
|
||||||
expect(MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
expect(MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
||||||
eventA, 2, {},
|
eventA, 2, error,
|
||||||
)).toEqual(4000);
|
)).toEqual(4000);
|
||||||
expect(MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
expect(MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
||||||
eventA, 3, {},
|
eventA, 3, error,
|
||||||
)).toEqual(8000);
|
)).toEqual(8000);
|
||||||
expect(MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
expect(MatrixScheduler.RETRY_BACKOFF_RATELIMIT(
|
||||||
eventA, 4, {},
|
eventA, 4, error,
|
||||||
)).toEqual(16000);
|
)).toEqual(16000);
|
||||||
});
|
});
|
||||||
});
|
});
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2017 Vector Creations Ltd
|
Copyright 2017 Vector Creations Ltd
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
Copyright 2019, 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -384,6 +384,10 @@ describe("SyncAccumulator", function() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.spyOn(global.Date, 'now').mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
it("should copy summary properties", function() {
|
it("should copy summary properties", function() {
|
||||||
sa.accumulate(createSyncResponseWithSummary({
|
sa.accumulate(createSyncResponseWithSummary({
|
||||||
"m.heroes": ["@alice:bar"],
|
"m.heroes": ["@alice:bar"],
|
||||||
@@ -413,14 +417,11 @@ describe("SyncAccumulator", function() {
|
|||||||
const delta = 1000;
|
const delta = 1000;
|
||||||
const startingTs = 1000;
|
const startingTs = 1000;
|
||||||
|
|
||||||
const oldDateNow = Date.now;
|
jest.spyOn(global.Date, 'now').mockReturnValue(startingTs);
|
||||||
try {
|
|
||||||
Date.now = jest.fn();
|
|
||||||
Date.now.mockReturnValue(startingTs);
|
|
||||||
|
|
||||||
sa.accumulate(RES_WITH_AGE);
|
sa.accumulate(RES_WITH_AGE);
|
||||||
|
|
||||||
Date.now.mockReturnValue(startingTs + delta);
|
jest.spyOn(global.Date, 'now').mockReturnValue(startingTs + delta);
|
||||||
|
|
||||||
const output = sa.getJSON();
|
const output = sa.getJSON();
|
||||||
expect(output.roomsData.join["!foo:bar"].timeline.events[0].unsigned.age).toEqual(
|
expect(output.roomsData.join["!foo:bar"].timeline.events[0].unsigned.age).toEqual(
|
||||||
@@ -429,9 +430,6 @@ describe("SyncAccumulator", function() {
|
|||||||
expect(Object.keys(output.roomsData.join["!foo:bar"].timeline.events[0])).toEqual(
|
expect(Object.keys(output.roomsData.join["!foo:bar"].timeline.events[0])).toEqual(
|
||||||
Object.keys(RES_WITH_AGE.rooms.join["!foo:bar"].timeline.events[0]),
|
Object.keys(RES_WITH_AGE.rooms.join["!foo:bar"].timeline.events[0]),
|
||||||
);
|
);
|
||||||
} finally {
|
|
||||||
Date.now = oldDateNow;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should mangle age without adding extra keys", () => {
|
it("should mangle age without adding extra keys", () => {
|
@@ -1,456 +0,0 @@
|
|||||||
import { EventTimeline } from "../../src/models/event-timeline";
|
|
||||||
import { TimelineIndex, TimelineWindow } from "../../src/timeline-window";
|
|
||||||
import * as utils from "../test-utils/test-utils";
|
|
||||||
|
|
||||||
const ROOM_ID = "roomId";
|
|
||||||
const USER_ID = "userId";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create a timeline with a bunch (default 3) events.
|
|
||||||
* baseIndex is 1 by default.
|
|
||||||
*/
|
|
||||||
function createTimeline(numEvents, baseIndex) {
|
|
||||||
if (numEvents === undefined) {
|
|
||||||
numEvents = 3;
|
|
||||||
}
|
|
||||||
if (baseIndex === undefined) {
|
|
||||||
baseIndex = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: this is a horrid hack
|
|
||||||
const timelineSet = { room: { roomId: ROOM_ID } };
|
|
||||||
timelineSet.room.getUnfilteredTimelineSet = function() {
|
|
||||||
return timelineSet;
|
|
||||||
};
|
|
||||||
|
|
||||||
const timeline = new EventTimeline(timelineSet);
|
|
||||||
|
|
||||||
// add the events after the baseIndex first
|
|
||||||
addEventsToTimeline(timeline, numEvents - baseIndex, false);
|
|
||||||
|
|
||||||
// then add those before the baseIndex
|
|
||||||
addEventsToTimeline(timeline, baseIndex, true);
|
|
||||||
|
|
||||||
expect(timeline.getBaseIndex()).toEqual(baseIndex);
|
|
||||||
return timeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addEventsToTimeline(timeline, numEvents, toStartOfTimeline) {
|
|
||||||
for (let i = 0; i < numEvents; i++) {
|
|
||||||
timeline.addEvent(
|
|
||||||
utils.mkMessage({
|
|
||||||
room: ROOM_ID, user: USER_ID,
|
|
||||||
event: true,
|
|
||||||
}),
|
|
||||||
{ toStartOfTimeline },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create a pair of linked timelines
|
|
||||||
*/
|
|
||||||
function createLinkedTimelines() {
|
|
||||||
const tl1 = createTimeline();
|
|
||||||
const tl2 = createTimeline();
|
|
||||||
tl1.setNeighbouringTimeline(tl2, EventTimeline.FORWARDS);
|
|
||||||
tl2.setNeighbouringTimeline(tl1, EventTimeline.BACKWARDS);
|
|
||||||
return [tl1, tl2];
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("TimelineIndex", function() {
|
|
||||||
describe("minIndex", function() {
|
|
||||||
it("should return the min index relative to BaseIndex", function() {
|
|
||||||
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
|
||||||
expect(timelineIndex.minIndex()).toEqual(-1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("maxIndex", function() {
|
|
||||||
it("should return the max index relative to BaseIndex", function() {
|
|
||||||
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
|
||||||
expect(timelineIndex.maxIndex()).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("advance", function() {
|
|
||||||
it("should advance up to the end of the timeline", function() {
|
|
||||||
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
|
||||||
const result = timelineIndex.advance(3);
|
|
||||||
expect(result).toEqual(2);
|
|
||||||
expect(timelineIndex.index).toEqual(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should retreat back to the start of the timeline", function() {
|
|
||||||
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
|
||||||
const result = timelineIndex.advance(-2);
|
|
||||||
expect(result).toEqual(-1);
|
|
||||||
expect(timelineIndex.index).toEqual(-1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should advance into the next timeline", function() {
|
|
||||||
const timelines = createLinkedTimelines();
|
|
||||||
const tl1 = timelines[0];
|
|
||||||
const tl2 = timelines[1];
|
|
||||||
|
|
||||||
// initialise the index pointing at the end of the first timeline
|
|
||||||
const timelineIndex = new TimelineIndex(tl1, 2);
|
|
||||||
|
|
||||||
const result = timelineIndex.advance(1);
|
|
||||||
expect(result).toEqual(1);
|
|
||||||
expect(timelineIndex.timeline).toBe(tl2);
|
|
||||||
|
|
||||||
// we expect the index to be the zero (ie, the same as the
|
|
||||||
// BaseIndex), because the BaseIndex points at the second event,
|
|
||||||
// and we've advanced past the first.
|
|
||||||
expect(timelineIndex.index).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should retreat into the previous timeline", function() {
|
|
||||||
const timelines = createLinkedTimelines();
|
|
||||||
const tl1 = timelines[0];
|
|
||||||
const tl2 = timelines[1];
|
|
||||||
|
|
||||||
// initialise the index pointing at the start of the second
|
|
||||||
// timeline
|
|
||||||
const timelineIndex = new TimelineIndex(tl2, -1);
|
|
||||||
|
|
||||||
const result = timelineIndex.advance(-1);
|
|
||||||
expect(result).toEqual(-1);
|
|
||||||
expect(timelineIndex.timeline).toBe(tl1);
|
|
||||||
expect(timelineIndex.index).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("retreat", function() {
|
|
||||||
it("should retreat up to the start of the timeline", function() {
|
|
||||||
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
|
||||||
const result = timelineIndex.retreat(2);
|
|
||||||
expect(result).toEqual(1);
|
|
||||||
expect(timelineIndex.index).toEqual(-1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("TimelineWindow", function() {
|
|
||||||
/**
|
|
||||||
* create a dummy eventTimelineSet and client, and a TimelineWindow
|
|
||||||
* attached to them.
|
|
||||||
*/
|
|
||||||
let timelineSet;
|
|
||||||
let client;
|
|
||||||
function createWindow(timeline, opts) {
|
|
||||||
timelineSet = { getTimelineForEvent: () => null };
|
|
||||||
client = {};
|
|
||||||
client.getEventTimeline = function(timelineSet0, eventId0) {
|
|
||||||
expect(timelineSet0).toBe(timelineSet);
|
|
||||||
return Promise.resolve(timeline);
|
|
||||||
};
|
|
||||||
|
|
||||||
return new TimelineWindow(client, timelineSet, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("load", function() {
|
|
||||||
it("should initialise from the live timeline", function() {
|
|
||||||
const liveTimeline = createTimeline();
|
|
||||||
const room = {};
|
|
||||||
room.getLiveTimeline = function() {
|
|
||||||
return liveTimeline;
|
|
||||||
};
|
|
||||||
|
|
||||||
const timelineWindow = new TimelineWindow(undefined, room);
|
|
||||||
return timelineWindow.load(undefined, 2).then(function() {
|
|
||||||
const expectedEvents = liveTimeline.getEvents().slice(1);
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should initialise from a specific event", function() {
|
|
||||||
const timeline = createTimeline();
|
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
|
||||||
|
|
||||||
const timelineSet = { getTimelineForEvent: () => null };
|
|
||||||
const client = {};
|
|
||||||
client.getEventTimeline = function(timelineSet0, eventId0) {
|
|
||||||
expect(timelineSet0).toBe(timelineSet);
|
|
||||||
expect(eventId0).toEqual(eventId);
|
|
||||||
return Promise.resolve(timeline);
|
|
||||||
};
|
|
||||||
|
|
||||||
const timelineWindow = new TimelineWindow(client, timelineSet);
|
|
||||||
return timelineWindow.load(eventId, 3).then(function() {
|
|
||||||
const expectedEvents = timeline.getEvents();
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("canPaginate should return false until load has returned", function() {
|
|
||||||
const timeline = createTimeline();
|
|
||||||
timeline.setPaginationToken("toktok1", EventTimeline.BACKWARDS);
|
|
||||||
timeline.setPaginationToken("toktok2", EventTimeline.FORWARDS);
|
|
||||||
|
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
|
||||||
|
|
||||||
const timelineSet = { getTimelineForEvent: () => null };
|
|
||||||
const client = {};
|
|
||||||
|
|
||||||
const timelineWindow = new TimelineWindow(client, timelineSet);
|
|
||||||
|
|
||||||
client.getEventTimeline = function(timelineSet0, eventId0) {
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
return Promise.resolve(timeline);
|
|
||||||
};
|
|
||||||
|
|
||||||
return timelineWindow.load(eventId, 3).then(function() {
|
|
||||||
const expectedEvents = timeline.getEvents();
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("pagination", function() {
|
|
||||||
it("should be able to advance across the initial timeline", function() {
|
|
||||||
const timeline = createTimeline();
|
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
|
||||||
const timelineWindow = createWindow(timeline);
|
|
||||||
|
|
||||||
return timelineWindow.load(eventId, 1).then(function() {
|
|
||||||
const expectedEvents = [timeline.getEvents()[1]];
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
|
|
||||||
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(true);
|
|
||||||
const expectedEvents = timeline.getEvents().slice(1);
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
|
|
||||||
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(false);
|
|
||||||
|
|
||||||
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(true);
|
|
||||||
const expectedEvents = timeline.getEvents();
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should advance into next timeline", function() {
|
|
||||||
const tls = createLinkedTimelines();
|
|
||||||
const eventId = tls[0].getEvents()[1].getId();
|
|
||||||
const timelineWindow = createWindow(tls[0], { windowLimit: 5 });
|
|
||||||
|
|
||||||
return timelineWindow.load(eventId, 3).then(function() {
|
|
||||||
const expectedEvents = tls[0].getEvents();
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
|
|
||||||
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(true);
|
|
||||||
const expectedEvents = tls[0].getEvents()
|
|
||||||
.concat(tls[1].getEvents().slice(0, 2));
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
|
|
||||||
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(true);
|
|
||||||
// the windowLimit should have made us drop an event from
|
|
||||||
// tls[0]
|
|
||||||
const expectedEvents = tls[0].getEvents().slice(1)
|
|
||||||
.concat(tls[1].getEvents());
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should retreat into previous timeline", function() {
|
|
||||||
const tls = createLinkedTimelines();
|
|
||||||
const eventId = tls[1].getEvents()[1].getId();
|
|
||||||
const timelineWindow = createWindow(tls[1], { windowLimit: 5 });
|
|
||||||
|
|
||||||
return timelineWindow.load(eventId, 3).then(function() {
|
|
||||||
const expectedEvents = tls[1].getEvents();
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
|
|
||||||
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(true);
|
|
||||||
const expectedEvents = tls[0].getEvents().slice(1, 3)
|
|
||||||
.concat(tls[1].getEvents());
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
|
|
||||||
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(true);
|
|
||||||
// the windowLimit should have made us drop an event from
|
|
||||||
// tls[1]
|
|
||||||
const expectedEvents = tls[0].getEvents()
|
|
||||||
.concat(tls[1].getEvents().slice(0, 2));
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should make forward pagination requests", function() {
|
|
||||||
const timeline = createTimeline();
|
|
||||||
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
|
|
||||||
|
|
||||||
const timelineWindow = createWindow(timeline, { windowLimit: 5 });
|
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
|
||||||
|
|
||||||
client.paginateEventTimeline = function(timeline0, opts) {
|
|
||||||
expect(timeline0).toBe(timeline);
|
|
||||||
expect(opts.backwards).toBe(false);
|
|
||||||
expect(opts.limit).toEqual(2);
|
|
||||||
|
|
||||||
addEventsToTimeline(timeline, 3, false);
|
|
||||||
return Promise.resolve(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return timelineWindow.load(eventId, 3).then(function() {
|
|
||||||
const expectedEvents = timeline.getEvents();
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(true);
|
|
||||||
const expectedEvents = timeline.getEvents().slice(0, 5);
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should make backward pagination requests", function() {
|
|
||||||
const timeline = createTimeline();
|
|
||||||
timeline.setPaginationToken("toktok", EventTimeline.BACKWARDS);
|
|
||||||
|
|
||||||
const timelineWindow = createWindow(timeline, { windowLimit: 5 });
|
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
|
||||||
|
|
||||||
client.paginateEventTimeline = function(timeline0, opts) {
|
|
||||||
expect(timeline0).toBe(timeline);
|
|
||||||
expect(opts.backwards).toBe(true);
|
|
||||||
expect(opts.limit).toEqual(2);
|
|
||||||
|
|
||||||
addEventsToTimeline(timeline, 3, true);
|
|
||||||
return Promise.resolve(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return timelineWindow.load(eventId, 3).then(function() {
|
|
||||||
const expectedEvents = timeline.getEvents();
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(true);
|
|
||||||
const expectedEvents = timeline.getEvents().slice(1, 6);
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should limit the number of unsuccessful pagination requests", function() {
|
|
||||||
const timeline = createTimeline();
|
|
||||||
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
|
|
||||||
|
|
||||||
const timelineWindow = createWindow(timeline, { windowLimit: 5 });
|
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
|
||||||
|
|
||||||
let paginateCount = 0;
|
|
||||||
client.paginateEventTimeline = function(timeline0, opts) {
|
|
||||||
expect(timeline0).toBe(timeline);
|
|
||||||
expect(opts.backwards).toBe(false);
|
|
||||||
expect(opts.limit).toEqual(2);
|
|
||||||
paginateCount += 1;
|
|
||||||
return Promise.resolve(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return timelineWindow.load(eventId, 3).then(function() {
|
|
||||||
const expectedEvents = timeline.getEvents();
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
return timelineWindow.paginate(EventTimeline.FORWARDS, 2, true, 3);
|
|
||||||
}).then(function(success) {
|
|
||||||
expect(success).toBe(false);
|
|
||||||
expect(paginateCount).toEqual(3);
|
|
||||||
const expectedEvents = timeline.getEvents().slice(0, 3);
|
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
|
||||||
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
|
||||||
.toBe(false);
|
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
|
||||||
.toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
439
spec/unit/timeline-window.spec.ts
Normal file
439
spec/unit/timeline-window.spec.ts
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
/*
|
||||||
|
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 { MockedObject } from 'jest-mock';
|
||||||
|
|
||||||
|
import { MatrixClient } from "../../src/client";
|
||||||
|
import { EventTimelineSet } from "../../src/models/event-timeline-set";
|
||||||
|
import { Room } from "../../src/models/room";
|
||||||
|
import { EventTimeline } from "../../src/models/event-timeline";
|
||||||
|
import { TimelineIndex, TimelineWindow } from "../../src/timeline-window";
|
||||||
|
import { mkMessage } from "../test-utils/test-utils";
|
||||||
|
|
||||||
|
const ROOM_ID = "roomId";
|
||||||
|
const USER_ID = "userId";
|
||||||
|
const mockClient = {
|
||||||
|
getEventTimeline: jest.fn(),
|
||||||
|
paginateEventTimeline: jest.fn(),
|
||||||
|
} as unknown as MockedObject<MatrixClient>;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create a timeline with a bunch (default 3) events.
|
||||||
|
* baseIndex is 1 by default.
|
||||||
|
*/
|
||||||
|
function createTimeline(numEvents = 3, baseIndex = 1): EventTimeline {
|
||||||
|
const room = new Room(ROOM_ID, mockClient, USER_ID);
|
||||||
|
const timelineSet = new EventTimelineSet(room);
|
||||||
|
jest.spyOn(timelineSet.room, 'getUnfilteredTimelineSet').mockReturnValue(timelineSet);
|
||||||
|
|
||||||
|
const timeline = new EventTimeline(timelineSet);
|
||||||
|
|
||||||
|
// add the events after the baseIndex first
|
||||||
|
addEventsToTimeline(timeline, numEvents - baseIndex, false);
|
||||||
|
|
||||||
|
// then add those before the baseIndex
|
||||||
|
addEventsToTimeline(timeline, baseIndex, true);
|
||||||
|
|
||||||
|
expect(timeline.getBaseIndex()).toEqual(baseIndex);
|
||||||
|
return timeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEventsToTimeline(timeline: EventTimeline, numEvents: number, toStartOfTimeline: boolean) {
|
||||||
|
for (let i = 0; i < numEvents; i++) {
|
||||||
|
timeline.addEvent(
|
||||||
|
mkMessage({
|
||||||
|
room: ROOM_ID, user: USER_ID,
|
||||||
|
event: true,
|
||||||
|
}),
|
||||||
|
{ toStartOfTimeline },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create a pair of linked timelines
|
||||||
|
*/
|
||||||
|
function createLinkedTimelines(): [EventTimeline, EventTimeline] {
|
||||||
|
const tl1 = createTimeline();
|
||||||
|
const tl2 = createTimeline();
|
||||||
|
tl1.setNeighbouringTimeline(tl2, EventTimeline.FORWARDS);
|
||||||
|
tl2.setNeighbouringTimeline(tl1, EventTimeline.BACKWARDS);
|
||||||
|
return [tl1, tl2];
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("TimelineIndex", function() {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
mockClient.getEventTimeline.mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("minIndex", function() {
|
||||||
|
it("should return the min index relative to BaseIndex", function() {
|
||||||
|
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
||||||
|
expect(timelineIndex.minIndex()).toEqual(-1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("maxIndex", function() {
|
||||||
|
it("should return the max index relative to BaseIndex", function() {
|
||||||
|
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
||||||
|
expect(timelineIndex.maxIndex()).toEqual(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("advance", function() {
|
||||||
|
it("should advance up to the end of the timeline", function() {
|
||||||
|
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
||||||
|
const result = timelineIndex.advance(3);
|
||||||
|
expect(result).toEqual(2);
|
||||||
|
expect(timelineIndex.index).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should retreat back to the start of the timeline", function() {
|
||||||
|
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
||||||
|
const result = timelineIndex.advance(-2);
|
||||||
|
expect(result).toEqual(-1);
|
||||||
|
expect(timelineIndex.index).toEqual(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should advance into the next timeline", function() {
|
||||||
|
const timelines = createLinkedTimelines();
|
||||||
|
const tl1 = timelines[0];
|
||||||
|
const tl2 = timelines[1];
|
||||||
|
|
||||||
|
// initialise the index pointing at the end of the first timeline
|
||||||
|
const timelineIndex = new TimelineIndex(tl1, 2);
|
||||||
|
|
||||||
|
const result = timelineIndex.advance(1);
|
||||||
|
expect(result).toEqual(1);
|
||||||
|
expect(timelineIndex.timeline).toBe(tl2);
|
||||||
|
|
||||||
|
// we expect the index to be the zero (ie, the same as the
|
||||||
|
// BaseIndex), because the BaseIndex points at the second event,
|
||||||
|
// and we've advanced past the first.
|
||||||
|
expect(timelineIndex.index).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should retreat into the previous timeline", function() {
|
||||||
|
const timelines = createLinkedTimelines();
|
||||||
|
const tl1 = timelines[0];
|
||||||
|
const tl2 = timelines[1];
|
||||||
|
|
||||||
|
// initialise the index pointing at the start of the second
|
||||||
|
// timeline
|
||||||
|
const timelineIndex = new TimelineIndex(tl2, -1);
|
||||||
|
|
||||||
|
const result = timelineIndex.advance(-1);
|
||||||
|
expect(result).toEqual(-1);
|
||||||
|
expect(timelineIndex.timeline).toBe(tl1);
|
||||||
|
expect(timelineIndex.index).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("retreat", function() {
|
||||||
|
it("should retreat up to the start of the timeline", function() {
|
||||||
|
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
||||||
|
const result = timelineIndex.retreat(2);
|
||||||
|
expect(result).toEqual(1);
|
||||||
|
expect(timelineIndex.index).toEqual(-1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("TimelineWindow", function() {
|
||||||
|
/**
|
||||||
|
* create a dummy eventTimelineSet and client, and a TimelineWindow
|
||||||
|
* attached to them.
|
||||||
|
*/
|
||||||
|
function createWindow(timeline: EventTimeline, opts?: {
|
||||||
|
windowLimit?: number;
|
||||||
|
}): [TimelineWindow, EventTimelineSet] {
|
||||||
|
const timelineSet = { getTimelineForEvent: () => null } as unknown as EventTimelineSet;
|
||||||
|
mockClient.getEventTimeline.mockResolvedValue(timeline);
|
||||||
|
|
||||||
|
return [new TimelineWindow(mockClient, timelineSet, opts), timelineSet];
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
mockClient.getEventTimeline.mockResolvedValue(undefined);
|
||||||
|
mockClient.paginateEventTimeline.mockReturnValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("load", function() {
|
||||||
|
it("should initialise from the live timeline", async function() {
|
||||||
|
const liveTimeline = createTimeline();
|
||||||
|
const room = new Room(ROOM_ID, mockClient, USER_ID);
|
||||||
|
const timelineSet = new EventTimelineSet(room);
|
||||||
|
jest.spyOn(timelineSet, 'getLiveTimeline').mockReturnValue(liveTimeline);
|
||||||
|
|
||||||
|
const timelineWindow = new TimelineWindow(mockClient, timelineSet);
|
||||||
|
await timelineWindow.load(undefined, 2);
|
||||||
|
|
||||||
|
expect(timelineSet.getLiveTimeline).toHaveBeenCalled();
|
||||||
|
|
||||||
|
const expectedEvents = liveTimeline.getEvents().slice(1);
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should initialise from a specific event", async function() {
|
||||||
|
const timeline = createTimeline();
|
||||||
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
|
|
||||||
|
const timelineSet = { getTimelineForEvent: () => null } as unknown as EventTimelineSet;
|
||||||
|
mockClient.getEventTimeline.mockResolvedValue(timeline);
|
||||||
|
|
||||||
|
const timelineWindow = new TimelineWindow(mockClient, timelineSet);
|
||||||
|
await timelineWindow.load(eventId, 3);
|
||||||
|
expect(mockClient.getEventTimeline).toHaveBeenCalledWith(timelineSet, eventId);
|
||||||
|
const expectedEvents = timeline.getEvents();
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("canPaginate should return false until load has returned", async function() {
|
||||||
|
const timeline = createTimeline();
|
||||||
|
timeline.setPaginationToken("toktok1", EventTimeline.BACKWARDS);
|
||||||
|
timeline.setPaginationToken("toktok2", EventTimeline.FORWARDS);
|
||||||
|
|
||||||
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
|
|
||||||
|
const timelineSet = { getTimelineForEvent: () => null } as unknown as EventTimelineSet;
|
||||||
|
mockClient.getEventTimeline.mockResolvedValue(timeline);
|
||||||
|
|
||||||
|
const timelineWindow = new TimelineWindow(mockClient, timelineSet);
|
||||||
|
|
||||||
|
const timelineWindowLoadPromise = timelineWindow.load(eventId, 3);
|
||||||
|
|
||||||
|
// cannot paginate before load is complete
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS)).toBe(false);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS)).toBe(false);
|
||||||
|
|
||||||
|
// wait for load
|
||||||
|
await timelineWindowLoadPromise;
|
||||||
|
const expectedEvents = timeline.getEvents();
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
|
// can paginate now
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("pagination", function() {
|
||||||
|
it("should be able to advance across the initial timeline", async function() {
|
||||||
|
const timeline = createTimeline();
|
||||||
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
|
const [timelineWindow] = createWindow(timeline);
|
||||||
|
|
||||||
|
await timelineWindow.load(eventId, 1);
|
||||||
|
|
||||||
|
const expectedEvents = [timeline.getEvents()[1]];
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.FORWARDS, 2)).toBe(true);
|
||||||
|
const expectedEventsAfterPagination = timeline.getEvents().slice(1);
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEventsAfterPagination);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
|
||||||
|
// cant paginate forward anymore
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.FORWARDS, 2)).toBe(false);
|
||||||
|
|
||||||
|
// paginate back again
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.BACKWARDS, 2)).toBe(true);
|
||||||
|
|
||||||
|
const expectedEvents3 = timeline.getEvents();
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents3);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.BACKWARDS, 2)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should advance into next timeline", async function() {
|
||||||
|
const tls = createLinkedTimelines();
|
||||||
|
const eventId = tls[0].getEvents()[1].getId();
|
||||||
|
const [timelineWindow] = createWindow(tls[0], { windowLimit: 5 });
|
||||||
|
|
||||||
|
await timelineWindow.load(eventId, 3);
|
||||||
|
const expectedEvents = tls[0].getEvents();
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.FORWARDS, 2)).toBe(true);
|
||||||
|
const expectedEvents2 = tls[0].getEvents()
|
||||||
|
.concat(tls[1].getEvents().slice(0, 2));
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents2);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.FORWARDS, 2)).toBe(true);
|
||||||
|
|
||||||
|
// the windowLimit should have made us drop an event from
|
||||||
|
// tls[0]
|
||||||
|
const expectedEvents3 = tls[0].getEvents().slice(1)
|
||||||
|
.concat(tls[1].getEvents());
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents3);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.FORWARDS, 2)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should retreat into previous timeline", async function() {
|
||||||
|
const tls = createLinkedTimelines();
|
||||||
|
const eventId = tls[1].getEvents()[1].getId();
|
||||||
|
const [timelineWindow] = createWindow(tls[1], { windowLimit: 5 });
|
||||||
|
|
||||||
|
await timelineWindow.load(eventId, 3);
|
||||||
|
|
||||||
|
const expectedEvents = tls[1].getEvents();
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.BACKWARDS, 2)).toBe(true);
|
||||||
|
const expectedEvents2 = tls[0].getEvents().slice(1, 3)
|
||||||
|
.concat(tls[1].getEvents());
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents2);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.BACKWARDS, 2)).toBe(true);
|
||||||
|
// the windowLimit should have made us drop an event from
|
||||||
|
// tls[1]
|
||||||
|
const expectedEvents3 = tls[0].getEvents()
|
||||||
|
.concat(tls[1].getEvents().slice(0, 2));
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents3);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.BACKWARDS, 2)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should make forward pagination requests", async function() {
|
||||||
|
const timeline = createTimeline();
|
||||||
|
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
|
||||||
|
|
||||||
|
const [timelineWindow] = createWindow(timeline, { windowLimit: 5 });
|
||||||
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
|
|
||||||
|
mockClient.paginateEventTimeline.mockImplementation(async (_t, _opts) => {
|
||||||
|
addEventsToTimeline(timeline, 3, false);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
await timelineWindow.load(eventId, 3);
|
||||||
|
const expectedEvents = timeline.getEvents();
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS)).toBe(false);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS)).toBe(true);
|
||||||
|
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.FORWARDS, 2)).toBe(true);
|
||||||
|
expect(mockClient.paginateEventTimeline).toHaveBeenCalledWith(timeline, { backwards: false, limit: 2 });
|
||||||
|
const expectedEvents2 = timeline.getEvents().slice(0, 5);
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should make backward pagination requests", async function() {
|
||||||
|
const timeline = createTimeline();
|
||||||
|
timeline.setPaginationToken("toktok", EventTimeline.BACKWARDS);
|
||||||
|
|
||||||
|
const [timelineWindow] = createWindow(timeline, { windowLimit: 5 });
|
||||||
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
|
|
||||||
|
mockClient.paginateEventTimeline.mockImplementation(async (_t, _opts) => {
|
||||||
|
addEventsToTimeline(timeline, 3, true);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
await timelineWindow.load(eventId, 3);
|
||||||
|
const expectedEvents = timeline.getEvents();
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS)).toBe(true);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS)).toBe(false);
|
||||||
|
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.BACKWARDS, 2)).toBe(true);
|
||||||
|
expect(mockClient.paginateEventTimeline).toHaveBeenCalledWith(timeline, { backwards: true, limit: 2 });
|
||||||
|
|
||||||
|
const expectedEvents2 = timeline.getEvents().slice(1, 6);
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit the number of unsuccessful pagination requests", async function() {
|
||||||
|
const timeline = createTimeline();
|
||||||
|
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
|
||||||
|
|
||||||
|
const [timelineWindow] = createWindow(timeline, { windowLimit: 5 });
|
||||||
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
|
|
||||||
|
mockClient.paginateEventTimeline.mockImplementation(async (_t, _opts) => {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
await timelineWindow.load(eventId, 3);
|
||||||
|
const expectedEvents = timeline.getEvents();
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
expect(await timelineWindow.paginate(EventTimeline.FORWARDS, 2, true, 3)).toBe(false);
|
||||||
|
|
||||||
|
expect(mockClient.paginateEventTimeline).toHaveBeenCalledWith(timeline, { backwards: false, limit: 2 });
|
||||||
|
|
||||||
|
expect(mockClient.paginateEventTimeline).toHaveBeenCalledTimes(3);
|
||||||
|
const expectedEvents2 = timeline.getEvents().slice(0, 3);
|
||||||
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents2);
|
||||||
|
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
|
.toBe(false);
|
||||||
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
|
.toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -1,16 +1,32 @@
|
|||||||
import { User } from "../../src/models/user";
|
/*
|
||||||
import * as utils from "../test-utils/test-utils";
|
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 { User, UserEvent } from "../../src/models/user";
|
||||||
|
import { mkEvent } from "../test-utils/test-utils";
|
||||||
|
|
||||||
describe("User", function() {
|
describe("User", function() {
|
||||||
const userId = "@alice:bar";
|
const userId = "@alice:bar";
|
||||||
let user;
|
let user: User;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
user = new User(userId);
|
user = new User(userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("setPresenceEvent", function() {
|
describe("setPresenceEvent", function() {
|
||||||
const event = utils.mkEvent({
|
const event = mkEvent({
|
||||||
type: "m.presence", content: {
|
type: "m.presence", content: {
|
||||||
presence: "online",
|
presence: "online",
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
@@ -22,7 +38,7 @@ describe("User", function() {
|
|||||||
|
|
||||||
it("should emit 'User.displayName' if the display name changes", function() {
|
it("should emit 'User.displayName' if the display name changes", function() {
|
||||||
let emitCount = 0;
|
let emitCount = 0;
|
||||||
user.on("User.displayName", function(ev, usr) {
|
user.on(UserEvent.DisplayName, function(ev, usr) {
|
||||||
emitCount += 1;
|
emitCount += 1;
|
||||||
});
|
});
|
||||||
user.setPresenceEvent(event);
|
user.setPresenceEvent(event);
|
||||||
@@ -33,7 +49,7 @@ describe("User", function() {
|
|||||||
|
|
||||||
it("should emit 'User.avatarUrl' if the avatar URL changes", function() {
|
it("should emit 'User.avatarUrl' if the avatar URL changes", function() {
|
||||||
let emitCount = 0;
|
let emitCount = 0;
|
||||||
user.on("User.avatarUrl", function(ev, usr) {
|
user.on(UserEvent.AvatarUrl, function(ev, usr) {
|
||||||
emitCount += 1;
|
emitCount += 1;
|
||||||
});
|
});
|
||||||
user.setPresenceEvent(event);
|
user.setPresenceEvent(event);
|
||||||
@@ -44,7 +60,7 @@ describe("User", function() {
|
|||||||
|
|
||||||
it("should emit 'User.presence' if the presence changes", function() {
|
it("should emit 'User.presence' if the presence changes", function() {
|
||||||
let emitCount = 0;
|
let emitCount = 0;
|
||||||
user.on("User.presence", function(ev, usr) {
|
user.on(UserEvent.Presence, function(ev, usr) {
|
||||||
emitCount += 1;
|
emitCount += 1;
|
||||||
});
|
});
|
||||||
user.setPresenceEvent(event);
|
user.setPresenceEvent(event);
|
Reference in New Issue
Block a user