1 | "use strict";
|
2 | import 'source-map-support/register';
|
3 | import Promise from 'bluebird';
|
4 | const sdk = require("../..");
|
5 | const EventTimeline = sdk.EventTimeline;
|
6 | const TimelineWindow = sdk.TimelineWindow;
|
7 | const TimelineIndex = require("../../lib/timeline-window").TimelineIndex;
|
8 |
|
9 | const utils = require("../test-utils");
|
10 | import expect from 'expect';
|
11 |
|
12 | const ROOM_ID = "roomId";
|
13 | const USER_ID = "userId";
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | function createTimeline(numEvents, baseIndex) {
|
20 | if (numEvents === undefined) {
|
21 | numEvents = 3;
|
22 | }
|
23 | if (baseIndex === undefined) {
|
24 | baseIndex = 1;
|
25 | }
|
26 |
|
27 |
|
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 |
|
36 | addEventsToTimeline(timeline, numEvents - baseIndex, false);
|
37 |
|
38 |
|
39 | addEventsToTimeline(timeline, baseIndex, true);
|
40 |
|
41 | expect(timeline.getBaseIndex()).toEqual(baseIndex);
|
42 | return timeline;
|
43 | }
|
44 |
|
45 | function 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 |
|
59 |
|
60 | function 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 |
|
69 | describe("TimelineIndex", function() {
|
70 | beforeEach(function() {
|
71 | utils.beforeEach(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 |
|
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 |
|
116 |
|
117 |
|
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 |
|
127 |
|
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 |
|
148 | describe("TimelineWindow", function() {
|
149 | |
150 |
|
151 |
|
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);
|
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 |
|
313 |
|
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 |
|
358 |
|
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 | });
|