UNPKG

14.5 kBJavaScriptView Raw
1"use strict";
2import 'source-map-support/register';
3const sdk = require("../..");
4const HttpBackend = require("matrix-mock-request");
5const publicGlobals = require("../../lib/matrix");
6const Room = publicGlobals.Room;
7const MemoryStore = publicGlobals.MemoryStore;
8const Filter = publicGlobals.Filter;
9const utils = require("../test-utils");
10const MockStorageApi = require("../MockStorageApi");
11
12import expect from 'expect';
13
14describe("MatrixClient", function() {
15 const baseUrl = "http://localhost.or.something";
16 let client = null;
17 let httpBackend = null;
18 let store = null;
19 let sessionStore = null;
20 const userId = "@alice:localhost";
21 const accessToken = "aseukfgwef";
22
23 beforeEach(function() {
24 utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
25 httpBackend = new HttpBackend();
26 store = new MemoryStore();
27
28 const mockStorage = new MockStorageApi();
29 sessionStore = new sdk.WebStorageSessionStore(mockStorage);
30
31 sdk.request(httpBackend.requestFn);
32 client = sdk.createClient({
33 baseUrl: baseUrl,
34 userId: userId,
35 deviceId: "aliceDevice",
36 accessToken: accessToken,
37 store: store,
38 sessionStore: sessionStore,
39 });
40 });
41
42 afterEach(function() {
43 httpBackend.verifyNoOutstandingExpectation();
44 return httpBackend.stop();
45 });
46
47 describe("uploadContent", function() {
48 const buf = new Buffer('hello world');
49 it("should upload the file", function(done) {
50 httpBackend.when(
51 "POST", "/_matrix/media/r0/upload",
52 ).check(function(req) {
53 expect(req.rawData).toEqual(buf);
54 expect(req.queryParams.filename).toEqual("hi.txt");
55 if (!(req.queryParams.access_token == accessToken ||
56 req.headers["Authorization"] == "Bearer " + accessToken)) {
57 expect(true).toBe(false);
58 }
59 expect(req.headers["Content-Type"]).toEqual("text/plain");
60 expect(req.opts.json).toBeFalsy();
61 expect(req.opts.timeout).toBe(undefined);
62 }).respond(200, "content", true);
63
64 const prom = client.uploadContent({
65 stream: buf,
66 name: "hi.txt",
67 type: "text/plain",
68 });
69
70 expect(prom).toBeTruthy();
71
72 const uploads = client.getCurrentUploads();
73 expect(uploads.length).toEqual(1);
74 expect(uploads[0].promise).toBe(prom);
75 expect(uploads[0].loaded).toEqual(0);
76
77 prom.then(function(response) {
78 // for backwards compatibility, we return the raw JSON
79 expect(response).toEqual("content");
80
81 const uploads = client.getCurrentUploads();
82 expect(uploads.length).toEqual(0);
83 }).nodeify(done);
84
85 httpBackend.flush();
86 });
87
88 it("should parse the response if rawResponse=false", function(done) {
89 httpBackend.when(
90 "POST", "/_matrix/media/r0/upload",
91 ).check(function(req) {
92 expect(req.opts.json).toBeFalsy();
93 }).respond(200, { "content_uri": "uri" });
94
95 client.uploadContent({
96 stream: buf,
97 name: "hi.txt",
98 type: "text/plain",
99 }, {
100 rawResponse: false,
101 }).then(function(response) {
102 expect(response.content_uri).toEqual("uri");
103 }).nodeify(done);
104
105 httpBackend.flush();
106 });
107
108 it("should parse errors into a MatrixError", function(done) {
109 httpBackend.when(
110 "POST", "/_matrix/media/r0/upload",
111 ).check(function(req) {
112 expect(req.rawData).toEqual(buf);
113 expect(req.opts.json).toBeFalsy();
114 }).respond(400, {
115 "errcode": "M_SNAFU",
116 "error": "broken",
117 });
118
119 client.uploadContent({
120 stream: buf,
121 name: "hi.txt",
122 type: "text/plain",
123 }).then(function(response) {
124 throw Error("request not failed");
125 }, function(error) {
126 expect(error.httpStatus).toEqual(400);
127 expect(error.errcode).toEqual("M_SNAFU");
128 expect(error.message).toEqual("broken");
129 }).nodeify(done);
130
131 httpBackend.flush();
132 });
133
134 it("should return a promise which can be cancelled", function(done) {
135 const prom = client.uploadContent({
136 stream: buf,
137 name: "hi.txt",
138 type: "text/plain",
139 });
140
141 const uploads = client.getCurrentUploads();
142 expect(uploads.length).toEqual(1);
143 expect(uploads[0].promise).toBe(prom);
144 expect(uploads[0].loaded).toEqual(0);
145
146 prom.then(function(response) {
147 throw Error("request not aborted");
148 }, function(error) {
149 expect(error).toEqual("aborted");
150
151 const uploads = client.getCurrentUploads();
152 expect(uploads.length).toEqual(0);
153 }).nodeify(done);
154
155 const r = client.cancelUpload(prom);
156 expect(r).toBe(true);
157 });
158 });
159
160 describe("joinRoom", function() {
161 it("should no-op if you've already joined a room", function() {
162 const roomId = "!foo:bar";
163 const room = new Room(roomId, userId);
164 room.addLiveEvents([
165 utils.mkMembership({
166 user: userId, room: roomId, mship: "join", event: true,
167 }),
168 ]);
169 store.storeRoom(room);
170 client.joinRoom(roomId);
171 httpBackend.verifyNoOutstandingRequests();
172 });
173 });
174
175 describe("getFilter", function() {
176 const filterId = "f1lt3r1d";
177
178 it("should return a filter from the store if allowCached", function(done) {
179 const filter = Filter.fromJson(userId, filterId, {
180 event_format: "client",
181 });
182 store.storeFilter(filter);
183 client.getFilter(userId, filterId, true).done(function(gotFilter) {
184 expect(gotFilter).toEqual(filter);
185 done();
186 });
187 httpBackend.verifyNoOutstandingRequests();
188 });
189
190 it("should do an HTTP request if !allowCached even if one exists",
191 function(done) {
192 const httpFilterDefinition = {
193 event_format: "federation",
194 };
195
196 httpBackend.when(
197 "GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId,
198 ).respond(200, httpFilterDefinition);
199
200 const storeFilter = Filter.fromJson(userId, filterId, {
201 event_format: "client",
202 });
203 store.storeFilter(storeFilter);
204 client.getFilter(userId, filterId, false).done(function(gotFilter) {
205 expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
206 done();
207 });
208
209 httpBackend.flush();
210 });
211
212 it("should do an HTTP request if nothing is in the cache and then store it",
213 function(done) {
214 const httpFilterDefinition = {
215 event_format: "federation",
216 };
217 expect(store.getFilter(userId, filterId)).toBe(null);
218
219 httpBackend.when(
220 "GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId,
221 ).respond(200, httpFilterDefinition);
222 client.getFilter(userId, filterId, true).done(function(gotFilter) {
223 expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
224 expect(store.getFilter(userId, filterId)).toBeTruthy();
225 done();
226 });
227
228 httpBackend.flush();
229 });
230 });
231
232 describe("createFilter", function() {
233 const filterId = "f1llllllerid";
234
235 it("should do an HTTP request and then store the filter", function(done) {
236 expect(store.getFilter(userId, filterId)).toBe(null);
237
238 const filterDefinition = {
239 event_format: "client",
240 };
241
242 httpBackend.when(
243 "POST", "/user/" + encodeURIComponent(userId) + "/filter",
244 ).check(function(req) {
245 expect(req.data).toEqual(filterDefinition);
246 }).respond(200, {
247 filter_id: filterId,
248 });
249
250 client.createFilter(filterDefinition).done(function(gotFilter) {
251 expect(gotFilter.getDefinition()).toEqual(filterDefinition);
252 expect(store.getFilter(userId, filterId)).toEqual(gotFilter);
253 done();
254 });
255
256 httpBackend.flush();
257 });
258 });
259
260 describe("searching", function() {
261 const response = {
262 search_categories: {
263 room_events: {
264 count: 24,
265 results: {
266 "$flibble:localhost": {
267 rank: 0.1,
268 result: {
269 type: "m.room.message",
270 user_id: "@alice:localhost",
271 room_id: "!feuiwhf:localhost",
272 content: {
273 body: "a result",
274 msgtype: "m.text",
275 },
276 },
277 },
278 },
279 },
280 },
281 };
282
283 it("searchMessageText should perform a /search for room_events", function(done) {
284 client.searchMessageText({
285 query: "monkeys",
286 });
287 httpBackend.when("POST", "/search").check(function(req) {
288 expect(req.data).toEqual({
289 search_categories: {
290 room_events: {
291 search_term: "monkeys",
292 },
293 },
294 });
295 }).respond(200, response);
296
297 httpBackend.flush().done(function() {
298 done();
299 });
300 });
301 });
302
303
304 describe("downloadKeys", function() {
305 if (!sdk.CRYPTO_ENABLED) {
306 return;
307 }
308
309 beforeEach(function() {
310 return client.initCrypto();
311 });
312
313 it("should do an HTTP request and then store the keys", function(done) {
314 const ed25519key = "7wG2lzAqbjcyEkOP7O4gU7ItYcn+chKzh5sT/5r2l78";
315 // ed25519key = client.getDeviceEd25519Key();
316 const borisKeys = {
317 dev1: {
318 algorithms: ["1"],
319 device_id: "dev1",
320 keys: { "ed25519:dev1": ed25519key },
321 signatures: {
322 boris: {
323 "ed25519:dev1":
324 "RAhmbNDq1efK3hCpBzZDsKoGSsrHUxb25NW5/WbEV9R" +
325 "JVwLdP032mg5QsKt/pBDUGtggBcnk43n3nBWlA88WAw",
326 },
327 },
328 unsigned: { "abc": "def" },
329 user_id: "boris",
330 },
331 };
332 const chazKeys = {
333 dev2: {
334 algorithms: ["2"],
335 device_id: "dev2",
336 keys: { "ed25519:dev2": ed25519key },
337 signatures: {
338 chaz: {
339 "ed25519:dev2":
340 "FwslH/Q7EYSb7swDJbNB5PSzcbEO1xRRBF1riuijqvL" +
341 "EkrK9/XVN8jl4h7thGuRITQ01siBQnNmMK9t45QfcCQ",
342 },
343 },
344 unsigned: { "ghi": "def" },
345 user_id: "chaz",
346 },
347 };
348
349 /*
350 function sign(o) {
351 var anotherjson = require('another-json');
352 var b = JSON.parse(JSON.stringify(o));
353 delete(b.signatures);
354 delete(b.unsigned);
355 return client._crypto._olmDevice.sign(anotherjson.stringify(b));
356 };
357
358 logger.log("Ed25519: " + ed25519key);
359 logger.log("boris:", sign(borisKeys.dev1));
360 logger.log("chaz:", sign(chazKeys.dev2));
361 */
362
363 httpBackend.when("POST", "/keys/query").check(function(req) {
364 expect(req.data).toEqual({device_keys: {
365 'boris': {},
366 'chaz': {},
367 }});
368 }).respond(200, {
369 device_keys: {
370 boris: borisKeys,
371 chaz: chazKeys,
372 },
373 });
374
375 client.downloadKeys(["boris", "chaz"]).then(function(res) {
376 assertObjectContains(res.boris.dev1, {
377 verified: 0, // DeviceVerification.UNVERIFIED
378 keys: { "ed25519:dev1": ed25519key },
379 algorithms: ["1"],
380 unsigned: { "abc": "def" },
381 });
382
383 assertObjectContains(res.chaz.dev2, {
384 verified: 0, // DeviceVerification.UNVERIFIED
385 keys: { "ed25519:dev2": ed25519key },
386 algorithms: ["2"],
387 unsigned: { "ghi": "def" },
388 });
389 }).nodeify(done);
390
391 httpBackend.flush();
392 });
393 });
394
395 describe("deleteDevice", function() {
396 const auth = {a: 1};
397 it("should pass through an auth dict", function(done) {
398 httpBackend.when(
399 "DELETE", "/_matrix/client/r0/devices/my_device",
400 ).check(function(req) {
401 expect(req.data).toEqual({auth: auth});
402 }).respond(200);
403
404 client.deleteDevice(
405 "my_device", auth,
406 ).nodeify(done);
407
408 httpBackend.flush();
409 });
410 });
411});
412
413function assertObjectContains(obj, expected) {
414 for (const k in expected) {
415 if (expected.hasOwnProperty(k)) {
416 expect(obj[k]).toEqual(expected[k]);
417 }
418 }
419}