UNPKG

14.4 kBJavaScriptView Raw
1"use strict";
2import 'source-map-support/register';
3const sdk = require("../..");
4const EventTimeline = sdk.EventTimeline;
5const utils = require("../test-utils");
6
7function mockRoomStates(timeline) {
8 timeline._startState = utils.mock(sdk.RoomState, "startState");
9 timeline._endState = utils.mock(sdk.RoomState, "endState");
10}
11
12import expect from 'expect';
13
14describe("EventTimeline", function() {
15 const roomId = "!foo:bar";
16 const userA = "@alice:bar";
17 const userB = "@bertha:bar";
18 let timeline;
19
20 beforeEach(function() {
21 utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
22
23 // XXX: this is a horrid hack; should use sinon or something instead to mock
24 const timelineSet = { room: { roomId: roomId }};
25 timelineSet.room.getUnfilteredTimelineSet = function() {
26 return timelineSet;
27 };
28
29 timeline = new EventTimeline(timelineSet);
30 });
31
32 describe("construction", function() {
33 it("getRoomId should get room id", function() {
34 const v = timeline.getRoomId();
35 expect(v).toEqual(roomId);
36 });
37 });
38
39 describe("initialiseState", function() {
40 beforeEach(function() {
41 mockRoomStates(timeline);
42 });
43
44 it("should copy state events to start and end state", function() {
45 const events = [
46 utils.mkMembership({
47 room: roomId, mship: "invite", user: userB, skey: userA,
48 event: true,
49 }),
50 utils.mkEvent({
51 type: "m.room.name", room: roomId, user: userB,
52 event: true,
53 content: { name: "New room" },
54 }),
55 ];
56 timeline.initialiseState(events);
57 expect(timeline._startState.setStateEvents).toHaveBeenCalledWith(
58 events,
59 );
60 expect(timeline._endState.setStateEvents).toHaveBeenCalledWith(
61 events,
62 );
63 });
64
65 it("should raise an exception if called after events are added", function() {
66 const event =
67 utils.mkMessage({
68 room: roomId, user: userA, msg: "Adam stole the plushies",
69 event: true,
70 });
71
72 const state = [
73 utils.mkMembership({
74 room: roomId, mship: "invite", user: userB, skey: userA,
75 event: true,
76 }),
77 ];
78
79 expect(function() {
80 timeline.initialiseState(state);
81 }).toNotThrow();
82 timeline.addEvent(event, false);
83 expect(function() {
84 timeline.initialiseState(state);
85 }).toThrow();
86 });
87 });
88
89 describe("paginationTokens", function() {
90 it("pagination tokens should start null", function() {
91 expect(timeline.getPaginationToken(EventTimeline.BACKWARDS)).toBe(null);
92 expect(timeline.getPaginationToken(EventTimeline.FORWARDS)).toBe(null);
93 });
94
95 it("setPaginationToken should set token", function() {
96 timeline.setPaginationToken("back", EventTimeline.BACKWARDS);
97 timeline.setPaginationToken("fwd", EventTimeline.FORWARDS);
98 expect(timeline.getPaginationToken(EventTimeline.BACKWARDS)).toEqual("back");
99 expect(timeline.getPaginationToken(EventTimeline.FORWARDS)).toEqual("fwd");
100 });
101 });
102
103
104 describe("neighbouringTimelines", function() {
105 it("neighbouring timelines should start null", function() {
106 expect(timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS)).toBe(null);
107 expect(timeline.getNeighbouringTimeline(EventTimeline.FORWARDS)).toBe(null);
108 });
109
110 it("setNeighbouringTimeline should set neighbour", function() {
111 const prev = {a: "a"};
112 const next = {b: "b"};
113 timeline.setNeighbouringTimeline(prev, EventTimeline.BACKWARDS);
114 timeline.setNeighbouringTimeline(next, EventTimeline.FORWARDS);
115 expect(timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS)).toBe(prev);
116 expect(timeline.getNeighbouringTimeline(EventTimeline.FORWARDS)).toBe(next);
117 });
118
119 it("setNeighbouringTimeline should throw if called twice", function() {
120 const prev = {a: "a"};
121 const next = {b: "b"};
122 expect(function() {
123 timeline.setNeighbouringTimeline(prev, EventTimeline.BACKWARDS);
124 }).toNotThrow();
125 expect(timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS))
126 .toBe(prev);
127 expect(function() {
128 timeline.setNeighbouringTimeline(prev, EventTimeline.BACKWARDS);
129 }).toThrow();
130
131 expect(function() {
132 timeline.setNeighbouringTimeline(next, EventTimeline.FORWARDS);
133 }).toNotThrow();
134 expect(timeline.getNeighbouringTimeline(EventTimeline.FORWARDS))
135 .toBe(next);
136 expect(function() {
137 timeline.setNeighbouringTimeline(next, EventTimeline.FORWARDS);
138 }).toThrow();
139 });
140 });
141
142 describe("addEvent", function() {
143 beforeEach(function() {
144 mockRoomStates(timeline);
145 });
146
147 const events = [
148 utils.mkMessage({
149 room: roomId, user: userA, msg: "hungry hungry hungry",
150 event: true,
151 }),
152 utils.mkMessage({
153 room: roomId, user: userB, msg: "nom nom nom",
154 event: true,
155 }),
156 ];
157
158 it("should be able to add events to the end", function() {
159 timeline.addEvent(events[0], false);
160 const initialIndex = timeline.getBaseIndex();
161 timeline.addEvent(events[1], false);
162 expect(timeline.getBaseIndex()).toEqual(initialIndex);
163 expect(timeline.getEvents().length).toEqual(2);
164 expect(timeline.getEvents()[0]).toEqual(events[0]);
165 expect(timeline.getEvents()[1]).toEqual(events[1]);
166 });
167
168 it("should be able to add events to the start", function() {
169 timeline.addEvent(events[0], true);
170 const initialIndex = timeline.getBaseIndex();
171 timeline.addEvent(events[1], true);
172 expect(timeline.getBaseIndex()).toEqual(initialIndex + 1);
173 expect(timeline.getEvents().length).toEqual(2);
174 expect(timeline.getEvents()[0]).toEqual(events[1]);
175 expect(timeline.getEvents()[1]).toEqual(events[0]);
176 });
177
178 it("should set event.sender for new and old events", function() {
179 const sentinel = {
180 userId: userA,
181 membership: "join",
182 name: "Alice",
183 };
184 const oldSentinel = {
185 userId: userA,
186 membership: "join",
187 name: "Old Alice",
188 };
189 timeline.getState(EventTimeline.FORWARDS).getSentinelMember
190 .andCall(function(uid) {
191 if (uid === userA) {
192 return sentinel;
193 }
194 return null;
195 });
196 timeline.getState(EventTimeline.BACKWARDS).getSentinelMember
197 .andCall(function(uid) {
198 if (uid === userA) {
199 return oldSentinel;
200 }
201 return null;
202 });
203
204 const newEv = utils.mkEvent({
205 type: "m.room.name", room: roomId, user: userA, event: true,
206 content: { name: "New Room Name" },
207 });
208 const oldEv = utils.mkEvent({
209 type: "m.room.name", room: roomId, user: userA, event: true,
210 content: { name: "Old Room Name" },
211 });
212
213 timeline.addEvent(newEv, false);
214 expect(newEv.sender).toEqual(sentinel);
215 timeline.addEvent(oldEv, true);
216 expect(oldEv.sender).toEqual(oldSentinel);
217 });
218
219 it("should set event.target for new and old m.room.member events",
220 function() {
221 const sentinel = {
222 userId: userA,
223 membership: "join",
224 name: "Alice",
225 };
226 const oldSentinel = {
227 userId: userA,
228 membership: "join",
229 name: "Old Alice",
230 };
231 timeline.getState(EventTimeline.FORWARDS).getSentinelMember
232 .andCall(function(uid) {
233 if (uid === userA) {
234 return sentinel;
235 }
236 return null;
237 });
238 timeline.getState(EventTimeline.BACKWARDS).getSentinelMember
239 .andCall(function(uid) {
240 if (uid === userA) {
241 return oldSentinel;
242 }
243 return null;
244 });
245
246 const newEv = utils.mkMembership({
247 room: roomId, mship: "invite", user: userB, skey: userA, event: true,
248 });
249 const oldEv = utils.mkMembership({
250 room: roomId, mship: "ban", user: userB, skey: userA, event: true,
251 });
252 timeline.addEvent(newEv, false);
253 expect(newEv.target).toEqual(sentinel);
254 timeline.addEvent(oldEv, true);
255 expect(oldEv.target).toEqual(oldSentinel);
256 });
257
258 it("should call setStateEvents on the right RoomState with the right " +
259 "forwardLooking value for new events", function() {
260 const events = [
261 utils.mkMembership({
262 room: roomId, mship: "invite", user: userB, skey: userA, event: true,
263 }),
264 utils.mkEvent({
265 type: "m.room.name", room: roomId, user: userB, event: true,
266 content: {
267 name: "New room",
268 },
269 }),
270 ];
271
272 timeline.addEvent(events[0], false);
273 timeline.addEvent(events[1], false);
274
275 expect(timeline.getState(EventTimeline.FORWARDS).setStateEvents).
276 toHaveBeenCalledWith([events[0]]);
277 expect(timeline.getState(EventTimeline.FORWARDS).setStateEvents).
278 toHaveBeenCalledWith([events[1]]);
279
280 expect(events[0].forwardLooking).toBe(true);
281 expect(events[1].forwardLooking).toBe(true);
282
283 expect(timeline.getState(EventTimeline.BACKWARDS).setStateEvents).
284 toNotHaveBeenCalled();
285 });
286
287
288 it("should call setStateEvents on the right RoomState with the right " +
289 "forwardLooking value for old events", function() {
290 const events = [
291 utils.mkMembership({
292 room: roomId, mship: "invite", user: userB, skey: userA, event: true,
293 }),
294 utils.mkEvent({
295 type: "m.room.name", room: roomId, user: userB, event: true,
296 content: {
297 name: "New room",
298 },
299 }),
300 ];
301
302 timeline.addEvent(events[0], true);
303 timeline.addEvent(events[1], true);
304
305 expect(timeline.getState(EventTimeline.BACKWARDS).setStateEvents).
306 toHaveBeenCalledWith([events[0]]);
307 expect(timeline.getState(EventTimeline.BACKWARDS).setStateEvents).
308 toHaveBeenCalledWith([events[1]]);
309
310 expect(events[0].forwardLooking).toBe(false);
311 expect(events[1].forwardLooking).toBe(false);
312
313 expect(timeline.getState(EventTimeline.FORWARDS).setStateEvents).
314 toNotHaveBeenCalled();
315 });
316 });
317
318 describe("removeEvent", function() {
319 const events = [
320 utils.mkMessage({
321 room: roomId, user: userA, msg: "hungry hungry hungry",
322 event: true,
323 }),
324 utils.mkMessage({
325 room: roomId, user: userB, msg: "nom nom nom",
326 event: true,
327 }),
328 utils.mkMessage({
329 room: roomId, user: userB, msg: "piiie",
330 event: true,
331 }),
332 ];
333
334 it("should remove events", function() {
335 timeline.addEvent(events[0], false);
336 timeline.addEvent(events[1], false);
337 expect(timeline.getEvents().length).toEqual(2);
338
339 let ev = timeline.removeEvent(events[0].getId());
340 expect(ev).toBe(events[0]);
341 expect(timeline.getEvents().length).toEqual(1);
342
343 ev = timeline.removeEvent(events[1].getId());
344 expect(ev).toBe(events[1]);
345 expect(timeline.getEvents().length).toEqual(0);
346 });
347
348 it("should update baseIndex", function() {
349 timeline.addEvent(events[0], false);
350 timeline.addEvent(events[1], true);
351 timeline.addEvent(events[2], false);
352 expect(timeline.getEvents().length).toEqual(3);
353 expect(timeline.getBaseIndex()).toEqual(1);
354
355 timeline.removeEvent(events[2].getId());
356 expect(timeline.getEvents().length).toEqual(2);
357 expect(timeline.getBaseIndex()).toEqual(1);
358
359 timeline.removeEvent(events[1].getId());
360 expect(timeline.getEvents().length).toEqual(1);
361 expect(timeline.getBaseIndex()).toEqual(0);
362 });
363
364 // this is basically https://github.com/vector-im/vector-web/issues/937
365 // - removing the last event got baseIndex into such a state that
366 // further addEvent(ev, false) calls made the index increase.
367 it("should not make baseIndex assplode when removing the last event",
368 function() {
369 timeline.addEvent(events[0], true);
370 timeline.removeEvent(events[0].getId());
371 const initialIndex = timeline.getBaseIndex();
372 timeline.addEvent(events[1], false);
373 timeline.addEvent(events[2], false);
374 expect(timeline.getBaseIndex()).toEqual(initialIndex);
375 expect(timeline.getEvents().length).toEqual(2);
376 });
377 });
378});