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
* Update jest monorepo * -w * Fix guest rooms test to use async/await instead of a done callback The done callback was never being called because it relies on a `process.nextTick()` deep within the mock. For this test we don't get a "next tick" because the event loop is busy, so we instead cargocult some test infrastructure from surrounding tests and verify the expected API call was cleared from the queue. * Enable github-actions reporter * Don't override local reporters * Stop DeviceLists at end of tests * stop more clients * Fix tests and DRY typing * Fix client/crypto stopping in tests * Fix Buffer c'tor deprecated warnings * Fix devicelist-integ test being excluded due to poor naming Co-authored-by: Renovate Bot <bot@renovateapp.com> Co-authored-by: Travis Ralston <travisr@matrix.org> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
1292 lines
47 KiB
JavaScript
1292 lines
47 KiB
JavaScript
/*
|
|
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 * as utils from "../test-utils/test-utils";
|
|
import { CRYPTO_ENABLED } from "../../src/client";
|
|
import { MatrixEvent } from "../../src/models/event";
|
|
import { Filter, MemoryStore, Room } from "../../src/matrix";
|
|
import { TestClient } from "../TestClient";
|
|
import { THREAD_RELATION_TYPE } from "../../src/models/thread";
|
|
|
|
describe("MatrixClient", function() {
|
|
let client = null;
|
|
let httpBackend = null;
|
|
let store = null;
|
|
const userId = "@alice:localhost";
|
|
const accessToken = "aseukfgwef";
|
|
|
|
beforeEach(function() {
|
|
store = new MemoryStore();
|
|
|
|
const testClient = new TestClient(userId, "aliceDevice", accessToken, undefined, { store });
|
|
httpBackend = testClient.httpBackend;
|
|
client = testClient.client;
|
|
});
|
|
|
|
afterEach(function() {
|
|
httpBackend.verifyNoOutstandingExpectation();
|
|
return httpBackend.stop();
|
|
});
|
|
|
|
describe("uploadContent", function() {
|
|
const buf = Buffer.from('hello world');
|
|
it("should upload the file", function() {
|
|
httpBackend.when(
|
|
"POST", "/_matrix/media/r0/upload",
|
|
).check(function(req) {
|
|
expect(req.rawData).toEqual(buf);
|
|
expect(req.queryParams.filename).toEqual("hi.txt");
|
|
if (!(req.queryParams.access_token == accessToken ||
|
|
req.headers["Authorization"] == "Bearer " + accessToken)) {
|
|
expect(true).toBe(false);
|
|
}
|
|
expect(req.headers["Content-Type"]).toEqual("text/plain");
|
|
expect(req.opts.json).toBeFalsy();
|
|
expect(req.opts.timeout).toBe(undefined);
|
|
}).respond(200, "content", true);
|
|
|
|
const prom = client.uploadContent({
|
|
stream: buf,
|
|
name: "hi.txt",
|
|
type: "text/plain",
|
|
});
|
|
|
|
expect(prom).toBeTruthy();
|
|
|
|
const uploads = client.getCurrentUploads();
|
|
expect(uploads.length).toEqual(1);
|
|
expect(uploads[0].promise).toBe(prom);
|
|
expect(uploads[0].loaded).toEqual(0);
|
|
|
|
const prom2 = prom.then(function(response) {
|
|
// for backwards compatibility, we return the raw JSON
|
|
expect(response).toEqual("content");
|
|
|
|
const uploads = client.getCurrentUploads();
|
|
expect(uploads.length).toEqual(0);
|
|
});
|
|
|
|
httpBackend.flush();
|
|
return prom2;
|
|
});
|
|
|
|
it("should parse the response if rawResponse=false", function() {
|
|
httpBackend.when(
|
|
"POST", "/_matrix/media/r0/upload",
|
|
).check(function(req) {
|
|
expect(req.opts.json).toBeFalsy();
|
|
}).respond(200, { "content_uri": "uri" });
|
|
|
|
const prom = client.uploadContent({
|
|
stream: buf,
|
|
name: "hi.txt",
|
|
type: "text/plain",
|
|
}, {
|
|
rawResponse: false,
|
|
}).then(function(response) {
|
|
expect(response.content_uri).toEqual("uri");
|
|
});
|
|
|
|
httpBackend.flush();
|
|
return prom;
|
|
});
|
|
|
|
it("should parse errors into a MatrixError", function() {
|
|
httpBackend.when(
|
|
"POST", "/_matrix/media/r0/upload",
|
|
).check(function(req) {
|
|
expect(req.rawData).toEqual(buf);
|
|
expect(req.opts.json).toBeFalsy();
|
|
}).respond(400, {
|
|
"errcode": "M_SNAFU",
|
|
"error": "broken",
|
|
});
|
|
|
|
const prom = client.uploadContent({
|
|
stream: buf,
|
|
name: "hi.txt",
|
|
type: "text/plain",
|
|
}).then(function(response) {
|
|
throw Error("request not failed");
|
|
}, function(error) {
|
|
expect(error.httpStatus).toEqual(400);
|
|
expect(error.errcode).toEqual("M_SNAFU");
|
|
expect(error.message).toEqual("broken");
|
|
});
|
|
|
|
httpBackend.flush();
|
|
return prom;
|
|
});
|
|
|
|
it("should return a promise which can be cancelled", function() {
|
|
const prom = client.uploadContent({
|
|
stream: buf,
|
|
name: "hi.txt",
|
|
type: "text/plain",
|
|
});
|
|
|
|
const uploads = client.getCurrentUploads();
|
|
expect(uploads.length).toEqual(1);
|
|
expect(uploads[0].promise).toBe(prom);
|
|
expect(uploads[0].loaded).toEqual(0);
|
|
|
|
const prom2 = prom.then(function(response) {
|
|
throw Error("request not aborted");
|
|
}, function(error) {
|
|
expect(error).toEqual("aborted");
|
|
|
|
const uploads = client.getCurrentUploads();
|
|
expect(uploads.length).toEqual(0);
|
|
});
|
|
|
|
const r = client.cancelUpload(prom);
|
|
expect(r).toBe(true);
|
|
return prom2;
|
|
});
|
|
});
|
|
|
|
describe("joinRoom", function() {
|
|
it("should no-op if you've already joined a room", function() {
|
|
const roomId = "!foo:bar";
|
|
const room = new Room(roomId, client, userId);
|
|
client.fetchRoomEvent = () => Promise.resolve({});
|
|
room.addLiveEvents([
|
|
utils.mkMembership({
|
|
user: userId, room: roomId, mship: "join", event: true,
|
|
}),
|
|
]);
|
|
httpBackend.verifyNoOutstandingRequests();
|
|
store.storeRoom(room);
|
|
client.joinRoom(roomId);
|
|
httpBackend.verifyNoOutstandingRequests();
|
|
});
|
|
});
|
|
|
|
describe("getFilter", function() {
|
|
const filterId = "f1lt3r1d";
|
|
|
|
it("should return a filter from the store if allowCached", function(done) {
|
|
const filter = Filter.fromJson(userId, filterId, {
|
|
event_format: "client",
|
|
});
|
|
store.storeFilter(filter);
|
|
client.getFilter(userId, filterId, true).then(function(gotFilter) {
|
|
expect(gotFilter).toEqual(filter);
|
|
done();
|
|
});
|
|
httpBackend.verifyNoOutstandingRequests();
|
|
});
|
|
|
|
it("should do an HTTP request if !allowCached even if one exists",
|
|
function(done) {
|
|
const httpFilterDefinition = {
|
|
event_format: "federation",
|
|
};
|
|
|
|
httpBackend.when(
|
|
"GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId,
|
|
).respond(200, httpFilterDefinition);
|
|
|
|
const storeFilter = Filter.fromJson(userId, filterId, {
|
|
event_format: "client",
|
|
});
|
|
store.storeFilter(storeFilter);
|
|
client.getFilter(userId, filterId, false).then(function(gotFilter) {
|
|
expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
|
|
done();
|
|
});
|
|
|
|
httpBackend.flush();
|
|
});
|
|
|
|
it("should do an HTTP request if nothing is in the cache and then store it",
|
|
function(done) {
|
|
const httpFilterDefinition = {
|
|
event_format: "federation",
|
|
};
|
|
expect(store.getFilter(userId, filterId)).toBe(null);
|
|
|
|
httpBackend.when(
|
|
"GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId,
|
|
).respond(200, httpFilterDefinition);
|
|
client.getFilter(userId, filterId, true).then(function(gotFilter) {
|
|
expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
|
|
expect(store.getFilter(userId, filterId)).toBeTruthy();
|
|
done();
|
|
});
|
|
|
|
httpBackend.flush();
|
|
});
|
|
});
|
|
|
|
describe("createFilter", function() {
|
|
const filterId = "f1llllllerid";
|
|
|
|
it("should do an HTTP request and then store the filter", function(done) {
|
|
expect(store.getFilter(userId, filterId)).toBe(null);
|
|
|
|
const filterDefinition = {
|
|
event_format: "client",
|
|
};
|
|
|
|
httpBackend.when(
|
|
"POST", "/user/" + encodeURIComponent(userId) + "/filter",
|
|
).check(function(req) {
|
|
expect(req.data).toEqual(filterDefinition);
|
|
}).respond(200, {
|
|
filter_id: filterId,
|
|
});
|
|
|
|
client.createFilter(filterDefinition).then(function(gotFilter) {
|
|
expect(gotFilter.getDefinition()).toEqual(filterDefinition);
|
|
expect(store.getFilter(userId, filterId)).toEqual(gotFilter);
|
|
done();
|
|
});
|
|
|
|
httpBackend.flush();
|
|
});
|
|
});
|
|
|
|
describe("searching", function() {
|
|
it("searchMessageText should perform a /search for room_events", function() {
|
|
const response = {
|
|
search_categories: {
|
|
room_events: {
|
|
count: 24,
|
|
results: [{
|
|
rank: 0.1,
|
|
result: {
|
|
event_id: "$flibble:localhost",
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
body: "a result",
|
|
msgtype: "m.text",
|
|
},
|
|
},
|
|
}],
|
|
},
|
|
},
|
|
};
|
|
|
|
client.searchMessageText({
|
|
query: "monkeys",
|
|
});
|
|
httpBackend.when("POST", "/search").check(function(req) {
|
|
expect(req.data).toEqual({
|
|
search_categories: {
|
|
room_events: {
|
|
search_term: "monkeys",
|
|
},
|
|
},
|
|
});
|
|
}).respond(200, response);
|
|
|
|
return httpBackend.flush();
|
|
});
|
|
|
|
describe("should filter out context from different timelines (threads)", () => {
|
|
it("filters out thread replies when result is in the main timeline", async () => {
|
|
const response = {
|
|
search_categories: {
|
|
room_events: {
|
|
count: 24,
|
|
results: [{
|
|
rank: 0.1,
|
|
result: {
|
|
event_id: "$flibble:localhost",
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
body: "main timeline",
|
|
msgtype: "m.text",
|
|
},
|
|
},
|
|
context: {
|
|
events_after: [{
|
|
event_id: "$ev-after:server",
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
"body": "thread reply",
|
|
"msgtype": "m.text",
|
|
"m.relates_to": {
|
|
"event_id": "$some-thread:server",
|
|
"rel_type": THREAD_RELATION_TYPE.name,
|
|
},
|
|
},
|
|
}],
|
|
events_before: [{
|
|
event_id: "$ev-before:server",
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
body: "main timeline again",
|
|
msgtype: "m.text",
|
|
},
|
|
}],
|
|
},
|
|
}],
|
|
},
|
|
},
|
|
};
|
|
|
|
const data = {
|
|
results: [],
|
|
highlights: [],
|
|
};
|
|
client.processRoomEventsSearch(data, response);
|
|
|
|
expect(data.results).toHaveLength(1);
|
|
expect(data.results[0].context.timeline).toHaveLength(2);
|
|
expect(data.results[0].context.timeline.find(e => e.getId() === "$ev-after:server")).toBeFalsy();
|
|
});
|
|
|
|
it("filters out thread replies from threads other than the thread the result replied to", () => {
|
|
const response = {
|
|
search_categories: {
|
|
room_events: {
|
|
count: 24,
|
|
results: [{
|
|
rank: 0.1,
|
|
result: {
|
|
event_id: "$flibble:localhost",
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
"body": "thread 1 reply 1",
|
|
"msgtype": "m.text",
|
|
"m.relates_to": {
|
|
"event_id": "$thread1:server",
|
|
"rel_type": THREAD_RELATION_TYPE.name,
|
|
},
|
|
},
|
|
},
|
|
context: {
|
|
events_after: [{
|
|
event_id: "$ev-after:server",
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
"body": "thread 2 reply 2",
|
|
"msgtype": "m.text",
|
|
"m.relates_to": {
|
|
"event_id": "$thread2:server",
|
|
"rel_type": THREAD_RELATION_TYPE.name,
|
|
},
|
|
},
|
|
}],
|
|
events_before: [],
|
|
},
|
|
}],
|
|
},
|
|
},
|
|
};
|
|
|
|
const data = {
|
|
results: [],
|
|
highlights: [],
|
|
};
|
|
client.processRoomEventsSearch(data, response);
|
|
|
|
expect(data.results).toHaveLength(1);
|
|
expect(data.results[0].context.timeline).toHaveLength(1);
|
|
expect(data.results[0].context.timeline.find(e => e.getId() === "$flibble:localhost")).toBeTruthy();
|
|
});
|
|
|
|
it("filters out main timeline events when result is a thread reply", () => {
|
|
const response = {
|
|
search_categories: {
|
|
room_events: {
|
|
count: 24,
|
|
results: [{
|
|
rank: 0.1,
|
|
result: {
|
|
event_id: "$flibble:localhost",
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
"body": "thread 1 reply 1",
|
|
"msgtype": "m.text",
|
|
"m.relates_to": {
|
|
"event_id": "$thread1:server",
|
|
"rel_type": THREAD_RELATION_TYPE.name,
|
|
},
|
|
},
|
|
},
|
|
context: {
|
|
events_after: [{
|
|
event_id: "$ev-after:server",
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
"body": "main timeline",
|
|
"msgtype": "m.text",
|
|
},
|
|
}],
|
|
events_before: [],
|
|
},
|
|
}],
|
|
},
|
|
},
|
|
};
|
|
|
|
const data = {
|
|
results: [],
|
|
highlights: [],
|
|
};
|
|
client.processRoomEventsSearch(data, response);
|
|
|
|
expect(data.results).toHaveLength(1);
|
|
expect(data.results[0].context.timeline).toHaveLength(1);
|
|
expect(data.results[0].context.timeline.find(e => e.getId() === "$flibble:localhost")).toBeTruthy();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("downloadKeys", function() {
|
|
if (!CRYPTO_ENABLED) {
|
|
return;
|
|
}
|
|
|
|
beforeEach(function() {
|
|
return client.initCrypto();
|
|
});
|
|
|
|
afterEach(() => {
|
|
client.stopClient();
|
|
});
|
|
|
|
it("should do an HTTP request and then store the keys", function() {
|
|
const ed25519key = "7wG2lzAqbjcyEkOP7O4gU7ItYcn+chKzh5sT/5r2l78";
|
|
// ed25519key = client.getDeviceEd25519Key();
|
|
const borisKeys = {
|
|
dev1: {
|
|
algorithms: ["1"],
|
|
device_id: "dev1",
|
|
keys: { "ed25519:dev1": ed25519key },
|
|
signatures: {
|
|
boris: {
|
|
"ed25519:dev1":
|
|
"RAhmbNDq1efK3hCpBzZDsKoGSsrHUxb25NW5/WbEV9R" +
|
|
"JVwLdP032mg5QsKt/pBDUGtggBcnk43n3nBWlA88WAw",
|
|
},
|
|
},
|
|
unsigned: { "abc": "def" },
|
|
user_id: "boris",
|
|
},
|
|
};
|
|
const chazKeys = {
|
|
dev2: {
|
|
algorithms: ["2"],
|
|
device_id: "dev2",
|
|
keys: { "ed25519:dev2": ed25519key },
|
|
signatures: {
|
|
chaz: {
|
|
"ed25519:dev2":
|
|
"FwslH/Q7EYSb7swDJbNB5PSzcbEO1xRRBF1riuijqvL" +
|
|
"EkrK9/XVN8jl4h7thGuRITQ01siBQnNmMK9t45QfcCQ",
|
|
},
|
|
},
|
|
unsigned: { "ghi": "def" },
|
|
user_id: "chaz",
|
|
},
|
|
};
|
|
|
|
/*
|
|
function sign(o) {
|
|
var anotherjson = require('another-json');
|
|
var b = JSON.parse(JSON.stringify(o));
|
|
delete(b.signatures);
|
|
delete(b.unsigned);
|
|
return client.crypto.olmDevice.sign(anotherjson.stringify(b));
|
|
};
|
|
|
|
logger.log("Ed25519: " + ed25519key);
|
|
logger.log("boris:", sign(borisKeys.dev1));
|
|
logger.log("chaz:", sign(chazKeys.dev2));
|
|
*/
|
|
|
|
httpBackend.when("POST", "/keys/query").check(function(req) {
|
|
expect(req.data).toEqual({ device_keys: {
|
|
'boris': [],
|
|
'chaz': [],
|
|
} });
|
|
}).respond(200, {
|
|
device_keys: {
|
|
boris: borisKeys,
|
|
chaz: chazKeys,
|
|
},
|
|
});
|
|
|
|
const prom = client.downloadKeys(["boris", "chaz"]).then(function(res) {
|
|
assertObjectContains(res.boris.dev1, {
|
|
verified: 0, // DeviceVerification.UNVERIFIED
|
|
keys: { "ed25519:dev1": ed25519key },
|
|
algorithms: ["1"],
|
|
unsigned: { "abc": "def" },
|
|
});
|
|
|
|
assertObjectContains(res.chaz.dev2, {
|
|
verified: 0, // DeviceVerification.UNVERIFIED
|
|
keys: { "ed25519:dev2": ed25519key },
|
|
algorithms: ["2"],
|
|
unsigned: { "ghi": "def" },
|
|
});
|
|
});
|
|
|
|
httpBackend.flush();
|
|
return prom;
|
|
});
|
|
});
|
|
|
|
describe("deleteDevice", function() {
|
|
const auth = { a: 1 };
|
|
it("should pass through an auth dict", function() {
|
|
httpBackend.when(
|
|
"DELETE", "/_matrix/client/r0/devices/my_device",
|
|
).check(function(req) {
|
|
expect(req.data).toEqual({ auth: auth });
|
|
}).respond(200);
|
|
|
|
const prom = client.deleteDevice("my_device", auth);
|
|
|
|
httpBackend.flush();
|
|
return prom;
|
|
});
|
|
});
|
|
|
|
describe("partitionThreadedEvents", function() {
|
|
let room;
|
|
beforeEach(() => {
|
|
room = new Room("!STrMRsukXHtqQdSeHa:matrix.org", client, userId);
|
|
});
|
|
|
|
it("returns empty arrays when given an empty arrays", function() {
|
|
const events = [];
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
expect(timeline).toEqual([]);
|
|
expect(threaded).toEqual([]);
|
|
});
|
|
|
|
it("copies pre-thread in-timeline vote events onto both timelines", function() {
|
|
client.clientOpts = { experimentalThreadSupport: true };
|
|
|
|
const eventPollResponseReference = buildEventPollResponseReference();
|
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
|
const eventMessageInThread = buildEventMessageInThread(eventPollStartThreadRoot);
|
|
|
|
const events = [
|
|
eventPollStartThreadRoot,
|
|
eventMessageInThread,
|
|
eventPollResponseReference,
|
|
];
|
|
// Vote has no threadId yet
|
|
expect(eventPollResponseReference.threadId).toBeFalsy();
|
|
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
|
|
expect(timeline).toEqual([
|
|
// The message that was sent in a thread is missing
|
|
eventPollStartThreadRoot,
|
|
eventPollResponseReference,
|
|
]);
|
|
|
|
// The vote event has been copied into the thread
|
|
const eventRefWithThreadId = withThreadId(
|
|
eventPollResponseReference, eventPollStartThreadRoot.getId());
|
|
expect(eventRefWithThreadId.threadId).toBeTruthy();
|
|
|
|
expect(threaded).toEqual([
|
|
eventPollStartThreadRoot,
|
|
eventMessageInThread,
|
|
eventRefWithThreadId,
|
|
]);
|
|
});
|
|
|
|
it("copies pre-thread in-timeline reactions onto both timelines", function() {
|
|
client.clientOpts = { experimentalThreadSupport: true };
|
|
|
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
|
const eventMessageInThread = buildEventMessageInThread(eventPollStartThreadRoot);
|
|
const eventReaction = buildEventReaction(eventPollStartThreadRoot);
|
|
|
|
const events = [
|
|
eventPollStartThreadRoot,
|
|
eventMessageInThread,
|
|
eventReaction,
|
|
];
|
|
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
|
|
expect(timeline).toEqual([
|
|
eventPollStartThreadRoot,
|
|
eventReaction,
|
|
]);
|
|
|
|
expect(threaded).toEqual([
|
|
eventPollStartThreadRoot,
|
|
eventMessageInThread,
|
|
withThreadId(eventReaction, eventPollStartThreadRoot.getId()),
|
|
]);
|
|
});
|
|
|
|
it("copies post-thread in-timeline vote events onto both timelines", function() {
|
|
client.clientOpts = { experimentalThreadSupport: true };
|
|
|
|
const eventPollResponseReference = buildEventPollResponseReference();
|
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
|
const eventMessageInThread = buildEventMessageInThread(eventPollStartThreadRoot);
|
|
|
|
const events = [
|
|
eventPollStartThreadRoot,
|
|
eventPollResponseReference,
|
|
eventMessageInThread,
|
|
];
|
|
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
|
|
expect(timeline).toEqual([
|
|
eventPollStartThreadRoot,
|
|
eventPollResponseReference,
|
|
]);
|
|
|
|
expect(threaded).toEqual([
|
|
eventPollStartThreadRoot,
|
|
withThreadId(eventPollResponseReference, eventPollStartThreadRoot.getId()),
|
|
eventMessageInThread,
|
|
]);
|
|
});
|
|
|
|
it("copies post-thread in-timeline reactions onto both timelines", function() {
|
|
client.clientOpts = { experimentalThreadSupport: true };
|
|
|
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
|
const eventMessageInThread = buildEventMessageInThread(eventPollStartThreadRoot);
|
|
const eventReaction = buildEventReaction(eventPollStartThreadRoot);
|
|
|
|
const events = [
|
|
eventPollStartThreadRoot,
|
|
eventMessageInThread,
|
|
eventReaction,
|
|
];
|
|
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
|
|
expect(timeline).toEqual([
|
|
eventPollStartThreadRoot,
|
|
eventReaction,
|
|
]);
|
|
|
|
expect(threaded).toEqual([
|
|
eventPollStartThreadRoot,
|
|
eventMessageInThread,
|
|
withThreadId(eventReaction, eventPollStartThreadRoot.getId()),
|
|
]);
|
|
});
|
|
|
|
it("sends room state events to the main timeline only", function() {
|
|
client.clientOpts = { experimentalThreadSupport: true };
|
|
// This is based on recording the events in a real room:
|
|
|
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
|
const eventPollResponseReference = buildEventPollResponseReference();
|
|
const eventMessageInThread = buildEventMessageInThread(eventPollStartThreadRoot);
|
|
const eventRoomName = buildEventRoomName();
|
|
const eventEncryption = buildEventEncryption();
|
|
const eventGuestAccess = buildEventGuestAccess();
|
|
const eventHistoryVisibility = buildEventHistoryVisibility();
|
|
const eventJoinRules = buildEventJoinRules();
|
|
const eventPowerLevels = buildEventPowerLevels();
|
|
const eventMember = buildEventMember();
|
|
const eventCreate = buildEventCreate();
|
|
|
|
const events = [
|
|
eventPollStartThreadRoot,
|
|
eventPollResponseReference,
|
|
eventMessageInThread,
|
|
eventRoomName,
|
|
eventEncryption,
|
|
eventGuestAccess,
|
|
eventHistoryVisibility,
|
|
eventJoinRules,
|
|
eventPowerLevels,
|
|
eventMember,
|
|
eventCreate,
|
|
];
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
|
|
expect(timeline).toEqual([
|
|
// The message that was sent in a thread is missing
|
|
eventPollStartThreadRoot,
|
|
eventPollResponseReference,
|
|
eventRoomName,
|
|
eventEncryption,
|
|
eventGuestAccess,
|
|
eventHistoryVisibility,
|
|
eventJoinRules,
|
|
eventPowerLevels,
|
|
eventMember,
|
|
eventCreate,
|
|
]);
|
|
|
|
// Thread should contain only stuff that happened in the thread - no room state events
|
|
expect(threaded).toEqual([
|
|
eventPollStartThreadRoot,
|
|
withThreadId(eventPollResponseReference, eventPollStartThreadRoot.getId()),
|
|
eventMessageInThread,
|
|
]);
|
|
});
|
|
|
|
it("sends redactions of reactions to thread responses to thread timeline only", () => {
|
|
client.clientOpts = { experimentalThreadSupport: true };
|
|
|
|
const threadRootEvent = buildEventPollStartThreadRoot();
|
|
const eventMessageInThread = buildEventMessageInThread(threadRootEvent);
|
|
const threadedReaction = buildEventReaction(eventMessageInThread);
|
|
const threadedReactionRedaction = buildEventRedaction(threadedReaction);
|
|
|
|
const events = [
|
|
threadRootEvent,
|
|
eventMessageInThread,
|
|
threadedReaction,
|
|
threadedReactionRedaction,
|
|
];
|
|
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
|
|
expect(timeline).toEqual([
|
|
threadRootEvent,
|
|
]);
|
|
|
|
expect(threaded).toEqual([
|
|
threadRootEvent,
|
|
eventMessageInThread,
|
|
threadedReaction,
|
|
threadedReactionRedaction,
|
|
]);
|
|
});
|
|
|
|
it("sends reply to reply to thread root outside of thread to main timeline only", () => {
|
|
client.clientOpts = { experimentalThreadSupport: true };
|
|
|
|
const threadRootEvent = buildEventPollStartThreadRoot();
|
|
const eventMessageInThread = buildEventMessageInThread(threadRootEvent);
|
|
const directReplyToThreadRoot = buildEventReply(threadRootEvent);
|
|
const replyToReply = buildEventReply(directReplyToThreadRoot);
|
|
|
|
const events = [
|
|
threadRootEvent,
|
|
eventMessageInThread,
|
|
directReplyToThreadRoot,
|
|
replyToReply,
|
|
];
|
|
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
|
|
expect(timeline).toEqual([
|
|
threadRootEvent,
|
|
directReplyToThreadRoot,
|
|
replyToReply,
|
|
]);
|
|
|
|
expect(threaded).toEqual([
|
|
threadRootEvent,
|
|
eventMessageInThread,
|
|
]);
|
|
});
|
|
|
|
it("sends reply to thread responses to main timeline only", () => {
|
|
client.clientOpts = { experimentalThreadSupport: true };
|
|
|
|
const threadRootEvent = buildEventPollStartThreadRoot();
|
|
const eventMessageInThread = buildEventMessageInThread(threadRootEvent);
|
|
const replyToThreadResponse = buildEventReply(eventMessageInThread);
|
|
|
|
const events = [
|
|
threadRootEvent,
|
|
eventMessageInThread,
|
|
replyToThreadResponse,
|
|
];
|
|
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
|
|
expect(timeline).toEqual([
|
|
threadRootEvent,
|
|
replyToThreadResponse,
|
|
]);
|
|
|
|
expect(threaded).toEqual([
|
|
threadRootEvent,
|
|
eventMessageInThread,
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("getThirdpartyUser", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = [{
|
|
userid: "@Bob",
|
|
protocol: "irc",
|
|
fields: {},
|
|
}];
|
|
|
|
const prom = client.getThirdpartyUser("irc", {});
|
|
httpBackend.when("GET", "/thirdparty/user/irc").respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("getThirdpartyLocation", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = [{
|
|
alias: "#alias",
|
|
protocol: "irc",
|
|
fields: {},
|
|
}];
|
|
|
|
const prom = client.getThirdpartyLocation("irc", {});
|
|
httpBackend.when("GET", "/thirdparty/location/irc").respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("getPushers", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {
|
|
pushers: [],
|
|
};
|
|
|
|
const prom = client.getPushers();
|
|
httpBackend.when("GET", "/pushers").respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("getKeyChanges", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {
|
|
changed: [],
|
|
left: [],
|
|
};
|
|
|
|
const prom = client.getKeyChanges("old", "new");
|
|
httpBackend.when("GET", "/keys/changes").check((req) => {
|
|
expect(req.queryParams.from).toEqual("old");
|
|
expect(req.queryParams.to).toEqual("new");
|
|
}).respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("getDevices", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {
|
|
devices: [],
|
|
};
|
|
|
|
const prom = client.getDevices();
|
|
httpBackend.when("GET", "/devices").respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("getDevice", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {
|
|
device_id: "DEADBEEF",
|
|
display_name: "NotAPhone",
|
|
last_seen_ip: "127.0.0.1",
|
|
last_seen_ts: 1,
|
|
};
|
|
|
|
const prom = client.getDevice("DEADBEEF");
|
|
httpBackend.when("GET", "/devices/DEADBEEF").respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("getThreePids", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {
|
|
threepids: [],
|
|
};
|
|
|
|
const prom = client.getThreePids();
|
|
httpBackend.when("GET", "/account/3pid").respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("deleteAlias", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {};
|
|
const prom = client.deleteAlias("#foo:bar");
|
|
httpBackend.when("DELETE", "/directory/room/" + encodeURIComponent("#foo:bar")).respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("deleteRoomTag", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {};
|
|
const prom = client.deleteRoomTag("!roomId:server", "u.tag");
|
|
const url = `/user/${encodeURIComponent(userId)}/rooms/${encodeURIComponent("!roomId:server")}/tags/u.tag`;
|
|
httpBackend.when("DELETE", url).respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("getRoomTags", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {
|
|
tags: {
|
|
"u.tag": {
|
|
order: 0.5,
|
|
},
|
|
},
|
|
};
|
|
|
|
const prom = client.getRoomTags("!roomId:server");
|
|
const url = `/user/${encodeURIComponent(userId)}/rooms/${encodeURIComponent("!roomId:server")}/tags`;
|
|
httpBackend.when("GET", url).respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("requestRegisterEmailToken", () => {
|
|
it("should hit the expected API endpoint", async () => {
|
|
const response = {
|
|
sid: "random_sid",
|
|
submit_url: "https://foobar.matrix/_matrix/matrix",
|
|
};
|
|
|
|
httpBackend.when("GET", "/_matrix/client/versions").respond(200, {
|
|
versions: ["r0.5.0"],
|
|
});
|
|
|
|
const prom = client.requestRegisterEmailToken("bob@email", "secret", 1);
|
|
httpBackend.when("POST", "/register/email/requestToken").check(req => {
|
|
expect(req.data).toStrictEqual({
|
|
email: "bob@email",
|
|
client_secret: "secret",
|
|
send_attempt: 1,
|
|
});
|
|
}).respond(200, response);
|
|
await httpBackend.flush();
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
});
|
|
|
|
function withThreadId(event, newThreadId) {
|
|
const ret = event.toSnapshot();
|
|
ret.setThreadId(newThreadId);
|
|
return ret;
|
|
}
|
|
|
|
const buildEventMessageInThread = (root) => new MatrixEvent({
|
|
"age": 80098509,
|
|
"content": {
|
|
"algorithm": "m.megolm.v1.aes-sha2",
|
|
"ciphertext": "ENCRYPTEDSTUFF",
|
|
"device_id": "XISFUZSKHH",
|
|
"m.relates_to": {
|
|
"event_id": root.getId(),
|
|
"m.in_reply_to": {
|
|
"event_id": root.getId(),
|
|
},
|
|
"rel_type": "m.thread",
|
|
},
|
|
"sender_key": "i3N3CtG/CD2bGB8rA9fW6adLYSDvlUhf2iuU73L65Vg",
|
|
"session_id": "Ja11R/KG6ua0wdk8zAzognrxjio1Gm/RK2Gn6lFL804",
|
|
},
|
|
"event_id": "$W4chKIGYowtBblVLkRimeIg8TcdjETnxhDPGfi6NpDg",
|
|
"origin_server_ts": 1643815466378,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"type": "m.room.encrypted",
|
|
"unsigned": { "age": 80098509 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventPollResponseReference = () => new MatrixEvent({
|
|
"age": 80098509,
|
|
"content": {
|
|
"algorithm": "m.megolm.v1.aes-sha2",
|
|
"ciphertext": "ENCRYPTEDSTUFF",
|
|
"device_id": "XISFUZSKHH",
|
|
"m.relates_to": {
|
|
"event_id": "$VLS2ojbPmxb6x8ECetn45hmND6cRDcjgv-j-to9m7Vo",
|
|
"rel_type": "m.reference",
|
|
},
|
|
"sender_key": "i3N3CtG/CD2bGB8rA9fW6adLYSDvlUhf2iuU73L65Vg",
|
|
"session_id": "Ja11R/KG6ua0wdk8zAzognrxjio1Gm/RK2Gn6lFL804",
|
|
},
|
|
"event_id": "$91JvpezvsF0cKgav3g8W-uEVS4WkDHgxbJZvL3uMR1g",
|
|
"origin_server_ts": 1643815458650,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"type": "m.room.encrypted",
|
|
"unsigned": { "age": 80106237 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventReaction = (event) => new MatrixEvent({
|
|
"content": {
|
|
"m.relates_to": {
|
|
"event_id": event.getId(),
|
|
"key": "🤗",
|
|
"rel_type": "m.annotation",
|
|
},
|
|
},
|
|
"origin_server_ts": 1643977249238,
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"type": "m.reaction",
|
|
"unsigned": {
|
|
"age": 22598,
|
|
"transaction_id": "m1643977249073.16",
|
|
},
|
|
"event_id": "$86B2b-x3LgE4DlV4y24b7UHnt72LIA3rzjvMysTtAfA",
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
});
|
|
|
|
const buildEventRedaction = (event) => new MatrixEvent({
|
|
"content": {
|
|
|
|
},
|
|
"origin_server_ts": 1643977249239,
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"redacts": event.getId(),
|
|
"type": "m.room.redaction",
|
|
"unsigned": {
|
|
"age": 22597,
|
|
"transaction_id": "m1643977249073.17",
|
|
},
|
|
"event_id": "$86B2b-x3LgE4DlV4y24b7UHnt72LIA3rzjvMysTtAfB",
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
});
|
|
|
|
const buildEventPollStartThreadRoot = () => new MatrixEvent({
|
|
"age": 80108647,
|
|
"content": {
|
|
"algorithm": "m.megolm.v1.aes-sha2",
|
|
"ciphertext": "ENCRYPTEDSTUFF",
|
|
"device_id": "XISFUZSKHH",
|
|
"sender_key": "i3N3CtG/CD2bGB8rA9fW6adLYSDvlUhf2iuU73L65Vg",
|
|
"session_id": "Ja11R/KG6ua0wdk8zAzognrxjio1Gm/RK2Gn6lFL804",
|
|
},
|
|
"event_id": "$VLS2ojbPmxb6x8ECetn45hmND6cRDcjgv-j-to9m7Vo",
|
|
"origin_server_ts": 1643815456240,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"type": "m.room.encrypted",
|
|
"unsigned": { "age": 80108647 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventReply = (target) => new MatrixEvent({
|
|
"age": 80098509,
|
|
"content": {
|
|
"algorithm": "m.megolm.v1.aes-sha2",
|
|
"ciphertext": "ENCRYPTEDSTUFF",
|
|
"device_id": "XISFUZSKHH",
|
|
"m.relates_to": {
|
|
"m.in_reply_to": {
|
|
"event_id": target.getId(),
|
|
},
|
|
},
|
|
"sender_key": "i3N3CtG/CD2bGB8rA9fW6adLYSDvlUhf2iuU73L65Vg",
|
|
"session_id": "Ja11R/KG6ua0wdk8zAzognrxjio1Gm/RK2Gn6lFL804",
|
|
},
|
|
"event_id": target.getId() + Math.random(),
|
|
"origin_server_ts": 1643815466378,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"type": "m.room.encrypted",
|
|
"unsigned": { "age": 80098509 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventRoomName = () => new MatrixEvent({
|
|
"age": 80123249,
|
|
"content": {
|
|
"name": "1 poll, 1 vote, 1 thread",
|
|
},
|
|
"event_id": "$QAdyNJtKnl1j7or2yMycbOCvb6bCgvHs5lg3ZMd5xWk",
|
|
"origin_server_ts": 1643815441638,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"state_key": "",
|
|
"type": "m.room.name",
|
|
"unsigned": { "age": 80123249 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventEncryption = () => new MatrixEvent({
|
|
"age": 80123383,
|
|
"content": {
|
|
"algorithm": "m.megolm.v1.aes-sha2",
|
|
},
|
|
"event_id": "$1hGykogKQkXbHw8bVuyE3BjHnFBEJBcUWnakd0ck2K0",
|
|
"origin_server_ts": 1643815441504,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"state_key": "",
|
|
"type": "m.room.encryption",
|
|
"unsigned": { "age": 80123383 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventGuestAccess = () => new MatrixEvent({
|
|
"age": 80123473,
|
|
"content": {
|
|
"guest_access": "can_join",
|
|
},
|
|
"event_id": "$4_2n-H6K9-0nPbnjjtIue2SU44tGJsnuTmi6UuSrh-U",
|
|
"origin_server_ts": 1643815441414,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"state_key": "",
|
|
"type": "m.room.guest_access",
|
|
"unsigned": { "age": 80123473 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventHistoryVisibility = () => new MatrixEvent({
|
|
"age": 80123556,
|
|
"content": {
|
|
"history_visibility": "shared",
|
|
},
|
|
"event_id": "$W6kp44CTnvciOiHSPyhp8dh4n2v1_9kclUPddeaQj0E",
|
|
"origin_server_ts": 1643815441331,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"state_key": "",
|
|
"type": "m.room.history_visibility",
|
|
"unsigned": { "age": 80123556 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventJoinRules = () => new MatrixEvent({
|
|
"age": 80123696,
|
|
"content": {
|
|
"join_rule": "invite",
|
|
},
|
|
"event_id": "$6JDDeDp7fEc0F6YnTWMruNcKWFltR3e9wk7wWDDJrAU",
|
|
"origin_server_ts": 1643815441191,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"state_key": "",
|
|
"type": "m.room.join_rules",
|
|
"unsigned": { "age": 80123696 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventPowerLevels = () => new MatrixEvent({
|
|
"age": 80124105,
|
|
"content": {
|
|
"ban": 50,
|
|
"events": {
|
|
"m.room.avatar": 50,
|
|
"m.room.canonical_alias": 50,
|
|
"m.room.encryption": 100,
|
|
"m.room.history_visibility": 100,
|
|
"m.room.name": 50,
|
|
"m.room.power_levels": 100,
|
|
"m.room.server_acl": 100,
|
|
"m.room.tombstone": 100,
|
|
},
|
|
"events_default": 0,
|
|
"historical": 100,
|
|
"invite": 0,
|
|
"kick": 50,
|
|
"redact": 50,
|
|
"state_default": 50,
|
|
"users": {
|
|
"@andybalaam-test1:matrix.org": 100,
|
|
},
|
|
"users_default": 0,
|
|
},
|
|
"event_id": "$XZY2YgQhXskpc7gmJJG3S0VmS9_QjjCUVeeFTfgfC2E",
|
|
"origin_server_ts": 1643815440782,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"state_key": "",
|
|
"type": "m.room.power_levels",
|
|
"unsigned": { "age": 80124105 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventMember = () => new MatrixEvent({
|
|
"age": 80125279,
|
|
"content": {
|
|
"avatar_url": "mxc://matrix.org/aNtbVcFfwotudypZcHsIcPOc",
|
|
"displayname": "andybalaam-test1",
|
|
"membership": "join",
|
|
},
|
|
"event_id": "$Ex5eVmMs_ti784mo8bgddynbwLvy6231lCycJr7Cl9M",
|
|
"origin_server_ts": 1643815439608,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"state_key": "@andybalaam-test1:matrix.org",
|
|
"type": "m.room.member",
|
|
"unsigned": { "age": 80125279 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
const buildEventCreate = () => new MatrixEvent({
|
|
"age": 80126105,
|
|
"content": {
|
|
"creator": "@andybalaam-test1:matrix.org",
|
|
"room_version": "6",
|
|
},
|
|
"event_id": "$e7j2Gt37k5NPwB6lz2N3V9lO5pUdNK8Ai7i2FPEK-oI",
|
|
"origin_server_ts": 1643815438782,
|
|
"room_id": "!STrMRsukXHtqQdSeHa:matrix.org",
|
|
"sender": "@andybalaam-test1:matrix.org",
|
|
"state_key": "",
|
|
"type": "m.room.create",
|
|
"unsigned": { "age": 80126105 },
|
|
"user_id": "@andybalaam-test1:matrix.org",
|
|
});
|
|
|
|
function assertObjectContains(obj, expected) {
|
|
for (const k in expected) {
|
|
if (expected.hasOwnProperty(k)) {
|
|
expect(obj[k]).toEqual(expected[k]);
|
|
}
|
|
}
|
|
}
|