UNPKG

19.2 kBJavaScriptView Raw
1"use strict";
2import 'source-map-support/register';
3import Promise from 'bluebird';
4const sdk = require("../..");
5const EventTimeline = sdk.EventTimeline;
6const TimelineWindow = sdk.TimelineWindow;
7const TimelineIndex = require("../../lib/timeline-window").TimelineIndex;
8
9const utils = require("../test-utils");
10import expect from 'expect';
11
12const ROOM_ID = "roomId";
13const USER_ID = "userId";
14
15/*
16 * create a timeline with a bunch (default 3) events.
17 * baseIndex is 1 by default.
18 */
19function createTimeline(numEvents, baseIndex) {
20 if (numEvents === undefined) {
21 numEvents = 3;
22 }
23 if (baseIndex === undefined) {
24 baseIndex = 1;
25 }
26
27 // XXX: this is a horrid hack
28 const timelineSet = { room: { roomId: ROOM_ID }};
29 timelineSet.room.getUnfilteredTimelineSet = function() {
30 return timelineSet;
31 };
32
33 const timeline = new EventTimeline(timelineSet);
34
35 // add the events after the baseIndex first
36 addEventsToTimeline(timeline, numEvents - baseIndex, false);
37
38 // then add those before the baseIndex
39 addEventsToTimeline(timeline, baseIndex, true);
40
41 expect(timeline.getBaseIndex()).toEqual(baseIndex);
42 return timeline;
43}
44
45function addEventsToTimeline(timeline, numEvents, atStart) {
46 for (let i = 0; i < numEvents; i++) {
47 timeline.addEvent(
48 utils.mkMessage({
49 room: ROOM_ID, user: USER_ID,
50 event: true,
51 }), atStart,
52 );
53 }
54}
55
56
57/*
58 * create a pair of linked timelines
59 */
60function createLinkedTimelines() {
61 const tl1 = createTimeline();
62 const tl2 = createTimeline();
63 tl1.setNeighbouringTimeline(tl2, EventTimeline.FORWARDS);
64 tl2.setNeighbouringTimeline(tl1, EventTimeline.BACKWARDS);
65 return [tl1, tl2];
66}
67
68
69describe("TimelineIndex", function() {
70 beforeEach(function() {
71 utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
72 });
73
74 describe("minIndex", function() {
75 it("should return the min index relative to BaseIndex", function() {
76 const timelineIndex = new TimelineIndex(createTimeline(), 0);
77 expect(timelineIndex.minIndex()).toEqual(-1);
78 });
79 });
80
81 describe("maxIndex", function() {
82 it("should return the max index relative to BaseIndex", function() {
83 const timelineIndex = new TimelineIndex(createTimeline(), 0);
84 expect(timelineIndex.maxIndex()).toEqual(2);
85 });
86 });
87
88 describe("advance", function() {
89 it("should advance up to the end of the timeline", function() {
90 const timelineIndex = new TimelineIndex(createTimeline(), 0);
91 const result = timelineIndex.advance(3);
92 expect(result).toEqual(2);
93 expect(timelineIndex.index).toEqual(2);
94 });
95
96 it("should retreat back to the start of the timeline", function() {
97 const timelineIndex = new TimelineIndex(createTimeline(), 0);
98 const result = timelineIndex.advance(-2);
99 expect(result).toEqual(-1);
100 expect(timelineIndex.index).toEqual(-1);
101 });
102
103 it("should advance into the next timeline", function() {
104 const timelines = createLinkedTimelines();
105 const tl1 = timelines[0];
106 const tl2 = timelines[1];
107
108 // initialise the index pointing at the end of the first timeline
109 const timelineIndex = new TimelineIndex(tl1, 2);
110
111 const result = timelineIndex.advance(1);
112 expect(result).toEqual(1);
113 expect(timelineIndex.timeline).toBe(tl2);
114
115 // we expect the index to be the zero (ie, the same as the
116 // BaseIndex), because the BaseIndex points at the second event,
117 // and we've advanced past the first.
118 expect(timelineIndex.index).toEqual(0);
119 });
120
121 it("should retreat into the previous timeline", function() {
122 const timelines = createLinkedTimelines();
123 const tl1 = timelines[0];
124 const tl2 = timelines[1];
125
126 // initialise the index pointing at the start of the second
127 // timeline
128 const timelineIndex = new TimelineIndex(tl2, -1);
129
130 const result = timelineIndex.advance(-1);
131 expect(result).toEqual(-1);
132 expect(timelineIndex.timeline).toBe(tl1);
133 expect(timelineIndex.index).toEqual(1);
134 });
135 });
136
137 describe("retreat", function() {
138 it("should retreat up to the start of the timeline", function() {
139 const timelineIndex = new TimelineIndex(createTimeline(), 0);
140 const result = timelineIndex.retreat(2);
141 expect(result).toEqual(1);
142 expect(timelineIndex.index).toEqual(-1);
143 });
144 });
145});
146
147
148describe("TimelineWindow", function() {
149 /**
150 * create a dummy eventTimelineSet and client, and a TimelineWindow
151 * attached to them.
152 */
153 let timelineSet;
154 let client;
155 function createWindow(timeline, opts) {
156 timelineSet = {};
157 client = {};
158 client.getEventTimeline = function(timelineSet0, eventId0) {
159 expect(timelineSet0).toBe(timelineSet);
160 return Promise.resolve(timeline);
161 };
162
163 return new TimelineWindow(client, timelineSet, opts);
164 }
165
166 beforeEach(function() {
167 utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
168 });
169
170 describe("load", function() {
171 it("should initialise from the live timeline", function(done) {
172 const liveTimeline = createTimeline();
173 const room = {};
174 room.getLiveTimeline = function() {
175 return liveTimeline;
176 };
177
178 const timelineWindow = new TimelineWindow(undefined, room);
179 timelineWindow.load(undefined, 2).then(function() {
180 const expectedEvents = liveTimeline.getEvents().slice(1);
181 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
182 }).nodeify(done);
183 });
184
185 it("should initialise from a specific event", function(done) {
186 const timeline = createTimeline();
187 const eventId = timeline.getEvents()[1].getId();
188
189 const timelineSet = {};
190 const client = {};
191 client.getEventTimeline = function(timelineSet0, eventId0) {
192 expect(timelineSet0).toBe(timelineSet);
193 expect(eventId0).toEqual(eventId);
194 return Promise.resolve(timeline);
195 };
196
197 const timelineWindow = new TimelineWindow(client, timelineSet);
198 timelineWindow.load(eventId, 3).then(function() {
199 const expectedEvents = timeline.getEvents();
200 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
201 }).nodeify(done);
202 });
203
204 it("canPaginate should return false until load has returned",
205 function(done) {
206 const timeline = createTimeline();
207 timeline.setPaginationToken("toktok1", EventTimeline.BACKWARDS);
208 timeline.setPaginationToken("toktok2", EventTimeline.FORWARDS);
209
210 const eventId = timeline.getEvents()[1].getId();
211
212 const timelineSet = {};
213 const client = {};
214
215 const timelineWindow = new TimelineWindow(client, timelineSet);
216
217 client.getEventTimeline = function(timelineSet0, eventId0) {
218 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
219 .toBe(false);
220 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
221 .toBe(false);
222 return Promise.resolve(timeline);
223 };
224
225 timelineWindow.load(eventId, 3).then(function() {
226 const expectedEvents = timeline.getEvents();
227 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
228 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
229 .toBe(true);
230 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
231 .toBe(true);
232 }).nodeify(done);
233 });
234 });
235
236 describe("pagination", function() {
237 it("should be able to advance across the initial timeline",
238 function(done) {
239 const timeline = createTimeline();
240 const eventId = timeline.getEvents()[1].getId();
241 const timelineWindow = createWindow(timeline);
242
243 timelineWindow.load(eventId, 1).then(function() {
244 const expectedEvents = [timeline.getEvents()[1]];
245 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
246
247 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
248 .toBe(true);
249 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
250 .toBe(true);
251
252 return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
253 }).then(function(success) {
254 expect(success).toBe(true);
255 const expectedEvents = timeline.getEvents().slice(1);
256 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
257
258 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
259 .toBe(true);
260 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
261 .toBe(false);
262
263 return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
264 }).then(function(success) {
265 expect(success).toBe(false);
266
267 return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
268 }).then(function(success) {
269 expect(success).toBe(true);
270 const expectedEvents = timeline.getEvents();
271 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
272
273 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
274 .toBe(false);
275 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
276 .toBe(false);
277 return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
278 }).then(function(success) {
279 expect(success).toBe(false);
280 }).nodeify(done);
281 });
282
283 it("should advance into next timeline", function(done) {
284 const tls = createLinkedTimelines();
285 const eventId = tls[0].getEvents()[1].getId();
286 const timelineWindow = createWindow(tls[0], {windowLimit: 5});
287
288 timelineWindow.load(eventId, 3).then(function() {
289 const expectedEvents = tls[0].getEvents();
290 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
291
292 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
293 .toBe(false);
294 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
295 .toBe(true);
296
297 return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
298 }).then(function(success) {
299 expect(success).toBe(true);
300 const expectedEvents = tls[0].getEvents()
301 .concat(tls[1].getEvents().slice(0, 2));
302 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
303
304 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
305 .toBe(false);
306 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
307 .toBe(true);
308
309 return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
310 }).then(function(success) {
311 expect(success).toBe(true);
312 // the windowLimit should have made us drop an event from
313 // tls[0]
314 const expectedEvents = tls[0].getEvents().slice(1)
315 .concat(tls[1].getEvents());
316 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
317
318 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
319 .toBe(true);
320 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
321 .toBe(false);
322 return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
323 }).then(function(success) {
324 expect(success).toBe(false);
325 }).nodeify(done);
326 });
327
328 it("should retreat into previous timeline", function(done) {
329 const tls = createLinkedTimelines();
330 const eventId = tls[1].getEvents()[1].getId();
331 const timelineWindow = createWindow(tls[1], {windowLimit: 5});
332
333 timelineWindow.load(eventId, 3).then(function() {
334 const expectedEvents = tls[1].getEvents();
335 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
336
337 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
338 .toBe(true);
339 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
340 .toBe(false);
341
342 return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
343 }).then(function(success) {
344 expect(success).toBe(true);
345 const expectedEvents = tls[0].getEvents().slice(1, 3)
346 .concat(tls[1].getEvents());
347 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
348
349 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
350 .toBe(true);
351 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
352 .toBe(false);
353
354 return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
355 }).then(function(success) {
356 expect(success).toBe(true);
357 // the windowLimit should have made us drop an event from
358 // tls[1]
359 const expectedEvents = tls[0].getEvents()
360 .concat(tls[1].getEvents().slice(0, 2));
361 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
362
363 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
364 .toBe(false);
365 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
366 .toBe(true);
367 return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
368 }).then(function(success) {
369 expect(success).toBe(false);
370 }).nodeify(done);
371 });
372
373 it("should make forward pagination requests", function(done) {
374 const timeline = createTimeline();
375 timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
376
377 const timelineWindow = createWindow(timeline, {windowLimit: 5});
378 const eventId = timeline.getEvents()[1].getId();
379
380 client.paginateEventTimeline = function(timeline0, opts) {
381 expect(timeline0).toBe(timeline);
382 expect(opts.backwards).toBe(false);
383 expect(opts.limit).toEqual(2);
384
385 addEventsToTimeline(timeline, 3, false);
386 return Promise.resolve(true);
387 };
388
389 timelineWindow.load(eventId, 3).then(function() {
390 const expectedEvents = timeline.getEvents();
391 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
392
393 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
394 .toBe(false);
395 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
396 .toBe(true);
397 return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
398 }).then(function(success) {
399 expect(success).toBe(true);
400 const expectedEvents = timeline.getEvents().slice(0, 5);
401 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
402 }).nodeify(done);
403 });
404
405
406 it("should make backward pagination requests", function(done) {
407 const timeline = createTimeline();
408 timeline.setPaginationToken("toktok", EventTimeline.BACKWARDS);
409
410 const timelineWindow = createWindow(timeline, {windowLimit: 5});
411 const eventId = timeline.getEvents()[1].getId();
412
413 client.paginateEventTimeline = function(timeline0, opts) {
414 expect(timeline0).toBe(timeline);
415 expect(opts.backwards).toBe(true);
416 expect(opts.limit).toEqual(2);
417
418 addEventsToTimeline(timeline, 3, true);
419 return Promise.resolve(true);
420 };
421
422 timelineWindow.load(eventId, 3).then(function() {
423 const expectedEvents = timeline.getEvents();
424 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
425
426 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
427 .toBe(true);
428 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
429 .toBe(false);
430 return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
431 }).then(function(success) {
432 expect(success).toBe(true);
433 const expectedEvents = timeline.getEvents().slice(1, 6);
434 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
435 }).nodeify(done);
436 });
437
438 it("should limit the number of unsuccessful pagination requests",
439 function(done) {
440 const timeline = createTimeline();
441 timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
442
443 const timelineWindow = createWindow(timeline, {windowLimit: 5});
444 const eventId = timeline.getEvents()[1].getId();
445
446 let paginateCount = 0;
447 client.paginateEventTimeline = function(timeline0, opts) {
448 expect(timeline0).toBe(timeline);
449 expect(opts.backwards).toBe(false);
450 expect(opts.limit).toEqual(2);
451 paginateCount += 1;
452 return Promise.resolve(true);
453 };
454
455 timelineWindow.load(eventId, 3).then(function() {
456 const expectedEvents = timeline.getEvents();
457 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
458
459 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
460 .toBe(false);
461 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
462 .toBe(true);
463 return timelineWindow.paginate(EventTimeline.FORWARDS, 2, true, 3);
464 }).then(function(success) {
465 expect(success).toBe(false);
466 expect(paginateCount).toEqual(3);
467 const expectedEvents = timeline.getEvents().slice(0, 3);
468 expect(timelineWindow.getEvents()).toEqual(expectedEvents);
469
470 expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
471 .toBe(false);
472 expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
473 .toBe(true);
474 }).nodeify(done);
475 });
476 });
477});