mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-04-19 18:02:16 +03:00
* feat(client): Add authenticated media parameter to getMediaConfig * test(client): add tests for mediaconfig --------- Co-authored-by: Maurizio <maurizio-noah.abbruzzo-santiago@t-systems.com>
2059 lines
78 KiB
TypeScript
2059 lines
78 KiB
TypeScript
/*
|
|
Copyright 2022 - 2023 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 type HttpBackend from "matrix-mock-request";
|
|
import * as utils from "../test-utils/test-utils";
|
|
import { type IStoredClientOpts, MatrixClient } from "../../src/client";
|
|
import { MatrixEvent } from "../../src/models/event";
|
|
import {
|
|
Filter,
|
|
JoinRule,
|
|
type KnockRoomOpts,
|
|
MemoryStore,
|
|
Method,
|
|
Room,
|
|
type RoomSummary,
|
|
SERVICE_TYPES,
|
|
} from "../../src/matrix";
|
|
import { TestClient } from "../TestClient";
|
|
import { THREAD_RELATION_TYPE } from "../../src/models/thread";
|
|
import { type IFilterDefinition } from "../../src/filter";
|
|
import { type ISearchResults } from "../../src/@types/search";
|
|
import { type IStore } from "../../src/store";
|
|
import { SetPresence } from "../../src/sync";
|
|
import { KnownMembership } from "../../src/@types/membership";
|
|
|
|
describe("MatrixClient", function () {
|
|
const userId = "@alice:localhost";
|
|
const accessToken = "aseukfgwef";
|
|
const idServerDomain = "identity.localhost"; // not a real server
|
|
const identityAccessToken = "woop-i-am-a-secret";
|
|
let client: MatrixClient;
|
|
let httpBackend: HttpBackend;
|
|
let store: MemoryStore;
|
|
|
|
const defaultClientOpts: IStoredClientOpts = {
|
|
threadSupport: false,
|
|
};
|
|
const setupTests = (): [MatrixClient, HttpBackend, MemoryStore] => {
|
|
const store = new MemoryStore();
|
|
|
|
const testClient = new TestClient(userId, "aliceDevice", accessToken, undefined, {
|
|
store: store as IStore,
|
|
identityServer: {
|
|
getAccessToken: () => Promise.resolve(identityAccessToken),
|
|
},
|
|
idBaseUrl: `https://${idServerDomain}`,
|
|
});
|
|
|
|
return [testClient.client, testClient.httpBackend, store];
|
|
};
|
|
|
|
beforeEach(function () {
|
|
[client, httpBackend, store] = setupTests();
|
|
});
|
|
|
|
afterEach(function () {
|
|
httpBackend.verifyNoOutstandingExpectation();
|
|
return httpBackend.stop();
|
|
});
|
|
|
|
describe("uploadContent", function () {
|
|
const buf = Buffer.from("hello world");
|
|
const file = buf;
|
|
const opts = {
|
|
type: "text/plain",
|
|
name: "hi.txt",
|
|
};
|
|
|
|
it("should upload the file", function () {
|
|
httpBackend
|
|
.when("POST", "/_matrix/media/v3/upload")
|
|
.check(function (req) {
|
|
expect(req.rawData).toEqual(buf);
|
|
expect(req.queryParams?.filename).toEqual("hi.txt");
|
|
expect(req.headers["Authorization"]).toBe("Bearer " + accessToken);
|
|
expect(req.headers["Content-Type"]).toEqual("text/plain");
|
|
// @ts-ignore private property
|
|
expect(req.opts.json).toBeFalsy();
|
|
// @ts-ignore private property
|
|
expect(req.opts.timeout).toBe(undefined);
|
|
})
|
|
.respond(200, '{"content_uri": "content"}', true);
|
|
|
|
const prom = client.uploadContent(file, opts);
|
|
|
|
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) {
|
|
expect(response.content_uri).toEqual("content");
|
|
|
|
const uploads = client.getCurrentUploads();
|
|
expect(uploads.length).toEqual(0);
|
|
});
|
|
|
|
httpBackend.flush("");
|
|
return prom2;
|
|
});
|
|
|
|
it("should parse errors into a MatrixError", function () {
|
|
httpBackend
|
|
.when("POST", "/_matrix/media/v3/upload")
|
|
.check(function (req) {
|
|
expect(req.rawData).toEqual(buf);
|
|
// @ts-ignore private property
|
|
expect(req.opts.json).toBeFalsy();
|
|
})
|
|
.respond(400, {
|
|
errcode: "M_SNAFU",
|
|
error: "broken",
|
|
});
|
|
|
|
const prom = client.uploadContent(file, opts).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("MatrixError: [400] broken");
|
|
},
|
|
);
|
|
|
|
httpBackend.flush("");
|
|
return prom;
|
|
});
|
|
|
|
it("should return a promise which can be cancelled", async () => {
|
|
const prom = client.uploadContent(file, opts);
|
|
|
|
const uploads = client.getCurrentUploads();
|
|
expect(uploads.length).toEqual(1);
|
|
expect(uploads[0].promise).toBe(prom);
|
|
expect(uploads[0].loaded).toEqual(0);
|
|
|
|
const r = client.cancelUpload(prom);
|
|
expect(r).toBe(true);
|
|
await expect(prom).rejects.toThrow("Aborted");
|
|
expect(client.getCurrentUploads()).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe("mediaConfig", function () {
|
|
it("should get media config on unauthenticated media call", async () => {
|
|
httpBackend.when("GET", "/_matrix/media/v3/config").respond(200, '{"m.upload.size": 50000000}', true);
|
|
|
|
const prom = client.getMediaConfig();
|
|
|
|
httpBackend.flushAllExpected();
|
|
|
|
expect((await prom)["m.upload.size"]).toEqual(50000000);
|
|
});
|
|
|
|
it("should get media config on authenticated media call", async () => {
|
|
httpBackend
|
|
.when("GET", "/_matrix/client/v1/media/config")
|
|
.respond(200, '{"m.upload.size": 50000000}', true);
|
|
|
|
const prom = client.getMediaConfig(true);
|
|
|
|
httpBackend.flushAllExpected();
|
|
|
|
expect((await prom)["m.upload.size"]).toEqual(50000000);
|
|
});
|
|
});
|
|
|
|
describe("joinRoom", function () {
|
|
it("should no-op given the ID of a room you've already joined", async () => {
|
|
const roomId = "!foo:bar";
|
|
const room = new Room(roomId, client, userId);
|
|
client.fetchRoomEvent = () =>
|
|
Promise.resolve({
|
|
type: "test",
|
|
content: {},
|
|
});
|
|
room.addLiveEvents(
|
|
[
|
|
utils.mkMembership({
|
|
user: userId,
|
|
room: roomId,
|
|
mship: KnownMembership.Join,
|
|
event: true,
|
|
}),
|
|
],
|
|
{ addToState: true },
|
|
);
|
|
httpBackend.verifyNoOutstandingRequests();
|
|
store.storeRoom(room);
|
|
|
|
const joinPromise = client.joinRoom(roomId);
|
|
httpBackend.verifyNoOutstandingRequests();
|
|
expect(await joinPromise).toBe(room);
|
|
});
|
|
|
|
it("should no-op given the alias of a room you've already joined", async () => {
|
|
const roomId = "!roomId:server";
|
|
const roomAlias = "#my-fancy-room:server";
|
|
const room = new Room(roomId, client, userId);
|
|
room.addLiveEvents(
|
|
[
|
|
utils.mkMembership({
|
|
user: userId,
|
|
room: roomId,
|
|
mship: KnownMembership.Join,
|
|
event: true,
|
|
}),
|
|
],
|
|
{ addToState: true },
|
|
);
|
|
store.storeRoom(room);
|
|
|
|
// The method makes a request to resolve the alias
|
|
httpBackend.when("POST", "/join/" + encodeURIComponent(roomAlias)).respond(200, { room_id: roomId });
|
|
|
|
const joinPromise = client.joinRoom(roomAlias);
|
|
await httpBackend.flushAllExpected();
|
|
expect(await joinPromise).toBe(room);
|
|
});
|
|
|
|
it("should send request to inviteSignUrl if specified", async () => {
|
|
const roomId = "!roomId:server";
|
|
const inviteSignUrl = "https://id.server/sign/this/for/me";
|
|
const viaServers = ["a", "b", "c"];
|
|
const signature = {
|
|
sender: "sender",
|
|
mxid: "@sender:foo",
|
|
token: "token",
|
|
signatures: {},
|
|
};
|
|
|
|
httpBackend
|
|
.when("POST", inviteSignUrl)
|
|
.check((request) => {
|
|
expect(request.queryParams?.mxid).toEqual(client.getUserId());
|
|
})
|
|
.respond(200, signature);
|
|
httpBackend
|
|
.when("POST", "/join/" + encodeURIComponent(roomId))
|
|
.check((request) => {
|
|
expect(request.data.third_party_signed).toEqual(signature);
|
|
})
|
|
.respond(200, { room_id: roomId });
|
|
|
|
const prom = client.joinRoom(roomId, {
|
|
inviteSignUrl,
|
|
viaServers,
|
|
});
|
|
await httpBackend.flushAllExpected();
|
|
expect((await prom).roomId).toBe(roomId);
|
|
});
|
|
});
|
|
|
|
describe("knockRoom", function () {
|
|
const roomId = "!some-room-id:example.org";
|
|
const reason = "some reason";
|
|
const viaServers = "example.com";
|
|
|
|
type TestCase = [string, KnockRoomOpts];
|
|
const testCases: TestCase[] = [
|
|
["should knock a room", {}],
|
|
["should knock a room for a reason", { reason }],
|
|
["should knock a room via given servers", { viaServers }],
|
|
["should knock a room for a reason via given servers", { reason, viaServers }],
|
|
];
|
|
|
|
it.each(testCases)("%s", async (_, opts) => {
|
|
httpBackend
|
|
.when("POST", "/knock/" + encodeURIComponent(roomId))
|
|
.check((request) => {
|
|
expect(request.data).toEqual({ reason: opts.reason });
|
|
expect(request.queryParams).toEqual({ server_name: opts.viaServers, via: opts.viaServers });
|
|
})
|
|
.respond(200, { room_id: roomId });
|
|
|
|
const prom = client.knockRoom(roomId, opts);
|
|
await httpBackend.flushAllExpected();
|
|
expect((await prom).room_id).toBe(roomId);
|
|
});
|
|
|
|
it("should no-op if you've already knocked a room", function () {
|
|
const room = new Room(roomId, client, userId);
|
|
|
|
client.fetchRoomEvent = () =>
|
|
Promise.resolve({
|
|
type: "test",
|
|
content: {},
|
|
});
|
|
|
|
room.addLiveEvents(
|
|
[
|
|
utils.mkMembership({
|
|
user: userId,
|
|
room: roomId,
|
|
mship: KnownMembership.Knock,
|
|
event: true,
|
|
}),
|
|
],
|
|
{ addToState: true },
|
|
);
|
|
|
|
httpBackend.verifyNoOutstandingRequests();
|
|
store.storeRoom(room);
|
|
client.knockRoom(roomId);
|
|
httpBackend.verifyNoOutstandingRequests();
|
|
});
|
|
|
|
describe("errors", function () {
|
|
type TestCase = [number, { errcode: string; error?: string }, string];
|
|
const testCases: TestCase[] = [
|
|
[
|
|
403,
|
|
{ errcode: "M_FORBIDDEN", error: "You don't have permission to knock" },
|
|
"[M_FORBIDDEN: MatrixError: [403] You don't have permission to knock]",
|
|
],
|
|
[
|
|
500,
|
|
{ errcode: "INTERNAL_SERVER_ERROR" },
|
|
"[INTERNAL_SERVER_ERROR: MatrixError: [500] Unknown message]",
|
|
],
|
|
];
|
|
|
|
it.each(testCases)("should handle %s error", async (code, { errcode, error }, snapshot) => {
|
|
httpBackend.when("POST", "/knock/" + encodeURIComponent(roomId)).respond(code, { errcode, error });
|
|
|
|
const prom = client.knockRoom(roomId);
|
|
await Promise.all([
|
|
httpBackend.flushAllExpected(),
|
|
expect(prom).rejects.toMatchInlineSnapshot(snapshot),
|
|
]);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("getFilter", function () {
|
|
const filterId = "f1lt3r1d";
|
|
|
|
it("should return a filter from the store if allowCached", async () => {
|
|
const filter = Filter.fromJson(userId, filterId, {
|
|
event_format: "client",
|
|
});
|
|
store.storeFilter(filter);
|
|
const gotFilter = await client.getFilter(userId, filterId, true);
|
|
expect(gotFilter).toEqual(filter);
|
|
httpBackend.verifyNoOutstandingRequests();
|
|
});
|
|
|
|
it("should do an HTTP request if !allowCached even if one exists", async () => {
|
|
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);
|
|
const [gotFilter] = await Promise.all([client.getFilter(userId, filterId, false), httpBackend.flush("")]);
|
|
expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
|
|
});
|
|
|
|
it("should do an HTTP request if nothing is in the cache and then store it", async () => {
|
|
const httpFilterDefinition = {
|
|
event_format: "federation",
|
|
};
|
|
expect(store.getFilter(userId, filterId)).toBe(null);
|
|
|
|
httpBackend
|
|
.when("GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId)
|
|
.respond(200, httpFilterDefinition);
|
|
const [gotFilter] = await Promise.all([client.getFilter(userId, filterId, true), httpBackend.flush("")]);
|
|
expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
|
|
expect(store.getFilter(userId, filterId)).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe("createFilter", function () {
|
|
const filterId = "f1llllllerid";
|
|
|
|
it("should do an HTTP request and then store the filter", async () => {
|
|
expect(store.getFilter(userId, filterId)).toBe(null);
|
|
|
|
const filterDefinition = {
|
|
event_format: "client" as IFilterDefinition["event_format"],
|
|
};
|
|
|
|
httpBackend
|
|
.when("POST", "/user/" + encodeURIComponent(userId) + "/filter")
|
|
.check(function (req) {
|
|
expect(req.data).toEqual(filterDefinition);
|
|
})
|
|
.respond(200, {
|
|
filter_id: filterId,
|
|
});
|
|
|
|
const [gotFilter] = await Promise.all([client.createFilter(filterDefinition), httpBackend.flush("")]);
|
|
expect(gotFilter.getDefinition()).toEqual(filterDefinition);
|
|
expect(store.getFilter(userId, filterId)).toEqual(gotFilter);
|
|
});
|
|
});
|
|
|
|
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,
|
|
highlights: [],
|
|
results: [
|
|
{
|
|
rank: 0.1,
|
|
result: {
|
|
event_id: "$flibble:localhost",
|
|
type: "m.room.message",
|
|
sender: "@test:locahost",
|
|
origin_server_ts: 123,
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
body: "main timeline",
|
|
msgtype: "m.text",
|
|
},
|
|
},
|
|
context: {
|
|
profile_info: {},
|
|
events_after: [
|
|
{
|
|
event_id: "$ev-after:server",
|
|
type: "m.room.message",
|
|
sender: "@test:locahost",
|
|
origin_server_ts: 123,
|
|
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",
|
|
sender: "@test:locahost",
|
|
origin_server_ts: 123,
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
body: "main timeline again",
|
|
msgtype: "m.text",
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
};
|
|
|
|
const data: ISearchResults = {
|
|
results: [],
|
|
highlights: [],
|
|
};
|
|
client.processRoomEventsSearch(data, response);
|
|
|
|
expect(data.results).toHaveLength(1);
|
|
expect(data.results[0].context.getTimeline()).toHaveLength(2);
|
|
expect(data.results[0].context.getTimeline().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,
|
|
highlights: [],
|
|
results: [
|
|
{
|
|
rank: 0.1,
|
|
result: {
|
|
event_id: "$flibble:localhost",
|
|
type: "m.room.message",
|
|
sender: "@test:locahost",
|
|
origin_server_ts: 123,
|
|
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: {
|
|
profile_info: {},
|
|
events_after: [
|
|
{
|
|
event_id: "$ev-after:server",
|
|
type: "m.room.message",
|
|
sender: "@test:locahost",
|
|
origin_server_ts: 123,
|
|
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: ISearchResults = {
|
|
results: [],
|
|
highlights: [],
|
|
};
|
|
client.processRoomEventsSearch(data, response);
|
|
|
|
expect(data.results).toHaveLength(1);
|
|
expect(data.results[0].context.getTimeline()).toHaveLength(1);
|
|
expect(
|
|
data.results[0].context.getTimeline().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,
|
|
highlights: [],
|
|
results: [
|
|
{
|
|
rank: 0.1,
|
|
result: {
|
|
event_id: "$flibble:localhost",
|
|
sender: "@test:locahost",
|
|
origin_server_ts: 123,
|
|
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",
|
|
sender: "@test:locahost",
|
|
origin_server_ts: 123,
|
|
type: "m.room.message",
|
|
user_id: "@alice:localhost",
|
|
room_id: "!feuiwhf:localhost",
|
|
content: {
|
|
body: "main timeline",
|
|
msgtype: "m.text",
|
|
},
|
|
},
|
|
],
|
|
events_before: [],
|
|
profile_info: {},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
};
|
|
|
|
const data: ISearchResults = {
|
|
results: [],
|
|
highlights: [],
|
|
};
|
|
client.processRoomEventsSearch(data, response);
|
|
|
|
expect(data.results).toHaveLength(1);
|
|
expect(data.results[0].context.getTimeline()).toHaveLength(1);
|
|
expect(
|
|
data.results[0].context.getTimeline().find((e) => e.getId() === "$flibble:localhost"),
|
|
).toBeTruthy();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("partitionThreadedEvents", function () {
|
|
let room: Room;
|
|
beforeEach(() => {
|
|
room = new Room("!STrMRsukXHtqQdSeHa:matrix.org", client, userId);
|
|
});
|
|
|
|
it("returns empty arrays when given an empty arrays", function () {
|
|
const events: MatrixEvent[] = [];
|
|
const [timeline, threaded] = room.partitionThreadedEvents(events);
|
|
expect(timeline).toEqual([]);
|
|
expect(threaded).toEqual([]);
|
|
});
|
|
|
|
it("should not copy pre-thread in-timeline vote events onto both timelines", function () {
|
|
// @ts-ignore setting private property
|
|
client.clientOpts = {
|
|
...defaultClientOpts,
|
|
threadSupport: true,
|
|
};
|
|
|
|
const eventPollResponseReference = buildEventPollResponseReference();
|
|
const eventPollStartThreadRoot = buildEventPollStartThreadRoot();
|
|
const eventMessageInThread = buildEventMessageInThread(eventPollStartThreadRoot);
|
|
|
|
const events = [eventPollStartThreadRoot, eventMessageInThread, eventPollResponseReference];
|
|
// Vote has no threadId yet
|
|
// @ts-ignore private property
|
|
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.threadRootId).toBeTruthy();
|
|
|
|
expect(threaded).toEqual([eventPollStartThreadRoot, eventMessageInThread]);
|
|
});
|
|
|
|
it("should not copy pre-thread in-timeline reactions onto both timelines", function () {
|
|
// @ts-ignore setting private property
|
|
client.clientOpts = {
|
|
...defaultClientOpts,
|
|
threadSupport: 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]);
|
|
});
|
|
|
|
it("should not copy post-thread in-timeline vote events onto both timelines", function () {
|
|
// @ts-ignore setting private property
|
|
client.clientOpts = {
|
|
...defaultClientOpts,
|
|
threadSupport: 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, eventMessageInThread]);
|
|
});
|
|
|
|
it("should not copy post-thread in-timeline reactions onto both timelines", function () {
|
|
// @ts-ignore setting private property
|
|
client.clientOpts = {
|
|
...defaultClientOpts,
|
|
threadSupport: 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]);
|
|
});
|
|
|
|
it("sends room state events to the main timeline only", function () {
|
|
// @ts-ignore setting private property
|
|
client.clientOpts = {
|
|
...defaultClientOpts,
|
|
threadSupport: 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, eventMessageInThread]);
|
|
});
|
|
|
|
it("sends redactions of reactions to thread responses to thread timeline only", () => {
|
|
// @ts-ignore setting private property
|
|
client.clientOpts = {
|
|
...defaultClientOpts,
|
|
threadSupport: 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", () => {
|
|
// @ts-ignore setting private property
|
|
client.clientOpts = {
|
|
...defaultClientOpts,
|
|
threadSupport: 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", () => {
|
|
// @ts-ignore setting private property
|
|
client.clientOpts = {
|
|
...defaultClientOpts,
|
|
threadSupport: 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]);
|
|
|
|
expect(threaded).toEqual([threadRootEvent, eventMessageInThread, replyToThreadResponse]);
|
|
});
|
|
});
|
|
|
|
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", "/_matrix/client/versions").respond(200, {});
|
|
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",
|
|
};
|
|
|
|
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);
|
|
});
|
|
});
|
|
|
|
describe("inviteByThreePid", () => {
|
|
it("should supply an id_access_token", async () => {
|
|
const targetEmail = "gerald@example.org";
|
|
|
|
httpBackend
|
|
.when("POST", "/invite")
|
|
.check((req) => {
|
|
expect(req.data).toStrictEqual({
|
|
id_server: idServerDomain,
|
|
id_access_token: identityAccessToken,
|
|
medium: "email",
|
|
address: targetEmail,
|
|
});
|
|
})
|
|
.respond(200, {});
|
|
|
|
const prom = client.inviteByThreePid("!room:example.org", "email", targetEmail);
|
|
await httpBackend.flush("");
|
|
await prom; // returns empty object, so no validation needed
|
|
});
|
|
});
|
|
|
|
describe("createRoom", () => {
|
|
it("should populate id_access_token on 3pid invites", async () => {
|
|
const targetEmail = "gerald@example.org";
|
|
const response = {
|
|
room_id: "!room:localhost",
|
|
};
|
|
const input = {
|
|
invite_3pid: [
|
|
{
|
|
// we intentionally exclude the access token here, so it can be populated for us
|
|
id_server: idServerDomain,
|
|
medium: "email",
|
|
address: targetEmail,
|
|
},
|
|
],
|
|
};
|
|
|
|
httpBackend
|
|
.when("POST", "/createRoom")
|
|
.check((req) => {
|
|
expect(req.data).toMatchObject({
|
|
invite_3pid: expect.arrayContaining([
|
|
{
|
|
...input.invite_3pid[0],
|
|
id_access_token: identityAccessToken,
|
|
},
|
|
]),
|
|
});
|
|
expect(req.data.invite_3pid.length).toBe(1);
|
|
})
|
|
.respond(200, response);
|
|
|
|
const prom = client.createRoom(input);
|
|
await httpBackend.flush("");
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("requestLoginToken", () => {
|
|
it("should hit the expected API endpoint with UIA", async () => {
|
|
const response = {};
|
|
const uiaData = {};
|
|
const prom = client.requestLoginToken(uiaData);
|
|
httpBackend.when("POST", "/v1/login/get_token", { auth: uiaData }).respond(200, response);
|
|
await httpBackend.flush("");
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
|
|
it("should hit the expected API endpoint without UIA", async () => {
|
|
const response = { login_token: "xyz", expires_in_ms: 5000 };
|
|
const prom = client.requestLoginToken();
|
|
httpBackend.when("POST", "/v1/login/get_token", {}).respond(200, response);
|
|
await httpBackend.flush("");
|
|
expect(await prom).toStrictEqual(response);
|
|
});
|
|
});
|
|
|
|
describe("logout", () => {
|
|
it("should abort pending requests when called with stopClient=true", async () => {
|
|
httpBackend.when("POST", "/logout").respond(200, {});
|
|
const fn = jest.fn();
|
|
client.http.request(Method.Get, "/test").catch(fn);
|
|
client.logout(true);
|
|
await httpBackend.flush(undefined);
|
|
expect(fn).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("sendHtmlEmote", () => {
|
|
it("should send valid html emote", async () => {
|
|
httpBackend
|
|
.when("PUT", "/send")
|
|
.check((req) => {
|
|
expect(req.data).toStrictEqual({
|
|
msgtype: "m.emote",
|
|
body: "Body",
|
|
formatted_body: "<h1>Body</h1>",
|
|
format: "org.matrix.custom.html",
|
|
});
|
|
})
|
|
.respond(200, { event_id: "$foobar" });
|
|
const prom = client.sendHtmlEmote("!room:server", "Body", "<h1>Body</h1>");
|
|
await httpBackend.flush(undefined);
|
|
await expect(prom).resolves.toStrictEqual({ event_id: "$foobar" });
|
|
});
|
|
});
|
|
|
|
describe("sendHtmlMessage", () => {
|
|
it("should send valid html message", async () => {
|
|
httpBackend
|
|
.when("PUT", "/send")
|
|
.check((req) => {
|
|
expect(req.data).toStrictEqual({
|
|
msgtype: "m.text",
|
|
body: "Body",
|
|
formatted_body: "<h1>Body</h1>",
|
|
format: "org.matrix.custom.html",
|
|
});
|
|
})
|
|
.respond(200, { event_id: "$foobar" });
|
|
const prom = client.sendHtmlMessage("!room:server", "Body", "<h1>Body</h1>");
|
|
await httpBackend.flush(undefined);
|
|
await expect(prom).resolves.toStrictEqual({ event_id: "$foobar" });
|
|
});
|
|
});
|
|
|
|
describe("forget", () => {
|
|
it("should remove from store by default", async () => {
|
|
const room = new Room("!roomId:server", client, userId);
|
|
client.store.storeRoom(room);
|
|
expect(client.store.getRooms()).toContain(room);
|
|
|
|
httpBackend.when("POST", "/forget").respond(200, {});
|
|
await Promise.all([client.forget(room.roomId), httpBackend.flushAllExpected()]);
|
|
expect(client.store.getRooms()).not.toContain(room);
|
|
});
|
|
});
|
|
|
|
describe("getCapabilities", () => {
|
|
it("should return cached capabilities if present", async () => {
|
|
const capsObject = {
|
|
"m.change_password": false,
|
|
};
|
|
|
|
httpBackend!.when("GET", "/versions").respond(200, {});
|
|
httpBackend!.when("GET", "/pushrules").respond(200, {});
|
|
httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
|
|
httpBackend.when("GET", "/capabilities").respond(200, {
|
|
capabilities: capsObject,
|
|
});
|
|
|
|
client.startClient();
|
|
await httpBackend!.flushAllExpected();
|
|
|
|
expect(await client.getCapabilities()).toEqual(capsObject);
|
|
});
|
|
|
|
it("should fetch capabilities if cache not present", async () => {
|
|
const capsObject = {
|
|
"m.change_password": false,
|
|
};
|
|
|
|
httpBackend.when("GET", "/capabilities").respond(200, {
|
|
capabilities: capsObject,
|
|
});
|
|
|
|
const capsPromise = client.getCapabilities();
|
|
await httpBackend!.flushAllExpected();
|
|
|
|
expect(await capsPromise).toEqual(capsObject);
|
|
});
|
|
});
|
|
|
|
describe("getCachedCapabilities", () => {
|
|
it("should return cached capabilities or undefined", async () => {
|
|
const capsObject = {
|
|
"m.change_password": false,
|
|
};
|
|
|
|
httpBackend!.when("GET", "/versions").respond(200, {});
|
|
httpBackend!.when("GET", "/pushrules").respond(200, {});
|
|
httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
|
|
httpBackend.when("GET", "/capabilities").respond(200, {
|
|
capabilities: capsObject,
|
|
});
|
|
|
|
expect(client.getCachedCapabilities()).toBeUndefined();
|
|
|
|
client.startClient();
|
|
|
|
await httpBackend!.flushAllExpected();
|
|
|
|
expect(client.getCachedCapabilities()).toEqual(capsObject);
|
|
});
|
|
});
|
|
|
|
describe("fetchCapabilities", () => {
|
|
const capsObject = {
|
|
"m.change_password": false,
|
|
};
|
|
|
|
beforeEach(() => {
|
|
httpBackend.when("GET", "/capabilities").respond(200, {
|
|
capabilities: capsObject,
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.useRealTimers();
|
|
});
|
|
|
|
it("should always fetch capabilities and then cache", async () => {
|
|
const prom = client.fetchCapabilities();
|
|
await httpBackend.flushAllExpected();
|
|
const caps = await prom;
|
|
|
|
expect(caps).toEqual(capsObject);
|
|
});
|
|
|
|
it("should write-through the cache", async () => {
|
|
httpBackend!.when("GET", "/versions").respond(200, {});
|
|
httpBackend!.when("GET", "/pushrules").respond(200, {});
|
|
httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
|
|
|
|
client.startClient();
|
|
await httpBackend!.flushAllExpected();
|
|
|
|
expect(client.getCachedCapabilities()).toEqual(capsObject);
|
|
|
|
const newCapsObject = {
|
|
"m.change_password": true,
|
|
};
|
|
|
|
httpBackend.when("GET", "/capabilities").respond(200, {
|
|
capabilities: newCapsObject,
|
|
});
|
|
|
|
const prom = client.fetchCapabilities();
|
|
await httpBackend.flushAllExpected();
|
|
await prom;
|
|
|
|
expect(client.getCachedCapabilities()).toEqual(newCapsObject);
|
|
});
|
|
});
|
|
|
|
describe("getTerms", () => {
|
|
it("should return Identity Server terms", async () => {
|
|
httpBackend.when("GET", "/terms").respond(200, { foo: "bar" });
|
|
const prom = client.getTerms(SERVICE_TYPES.IS, "http://identity.server");
|
|
await httpBackend.flushAllExpected();
|
|
await expect(prom).resolves.toEqual({ foo: "bar" });
|
|
});
|
|
|
|
it("should return Integrations Manager terms", async () => {
|
|
httpBackend.when("GET", "/terms").respond(200, { foo: "bar" });
|
|
const prom = client.getTerms(SERVICE_TYPES.IM, "http://im.server");
|
|
await httpBackend.flushAllExpected();
|
|
await expect(prom).resolves.toEqual({ foo: "bar" });
|
|
});
|
|
});
|
|
|
|
describe("agreeToTerms", () => {
|
|
it("should send `user_accepts` via body of POST request", async () => {
|
|
const terms = ["https://vector.im/notice-1"];
|
|
|
|
httpBackend
|
|
.when("POST", "/terms")
|
|
.check((req) => {
|
|
expect(req.data.user_accepts).toStrictEqual(terms);
|
|
})
|
|
.respond(200, {});
|
|
|
|
const prom = client.agreeToTerms(SERVICE_TYPES.IS, "https://vector.im", "at", terms);
|
|
await httpBackend.flushAllExpected();
|
|
await prom;
|
|
});
|
|
});
|
|
|
|
describe("publicRooms", () => {
|
|
it("should use GET request if no server or filter is specified", () => {
|
|
httpBackend.when("GET", "/publicRooms").respond(200, {});
|
|
client.publicRooms({});
|
|
return httpBackend.flushAllExpected();
|
|
});
|
|
|
|
it("should use GET request if only server is specified", () => {
|
|
httpBackend
|
|
.when("GET", "/publicRooms")
|
|
.check((request) => {
|
|
expect(request.queryParams?.server).toBe("server1");
|
|
})
|
|
.respond(200, {});
|
|
client.publicRooms({ server: "server1" });
|
|
return httpBackend.flushAllExpected();
|
|
});
|
|
|
|
it("should use POST request if filter is specified", () => {
|
|
httpBackend
|
|
.when("POST", "/publicRooms")
|
|
.check((request) => {
|
|
expect(request.data.filter.generic_search_term).toBe("foobar");
|
|
})
|
|
.respond(200, {});
|
|
client.publicRooms({ filter: { generic_search_term: "foobar" } });
|
|
return httpBackend.flushAllExpected();
|
|
});
|
|
});
|
|
|
|
describe("login", () => {
|
|
it("should persist values to the client opts", async () => {
|
|
const token = "!token&";
|
|
const userId = "@m:t";
|
|
|
|
httpBackend.when("POST", "/login").respond(200, {
|
|
access_token: token,
|
|
user_id: userId,
|
|
});
|
|
const prom = client.login("fake.login", {});
|
|
await httpBackend.flushAllExpected();
|
|
const resp = await prom;
|
|
expect(resp.access_token).toBe(token);
|
|
expect(resp.user_id).toBe(userId);
|
|
expect(client.getUserId()).toBe(userId);
|
|
expect(client.http.opts.accessToken).toBe(token);
|
|
});
|
|
});
|
|
|
|
describe("registerWithIdentityServer", () => {
|
|
it("should pass data to POST request", async () => {
|
|
const token = {
|
|
access_token: "access_token",
|
|
token_type: "Bearer",
|
|
matrix_server_name: "server_name",
|
|
expires_in: 12345,
|
|
};
|
|
|
|
httpBackend
|
|
.when("POST", "/account/register")
|
|
.check((req) => {
|
|
expect(req.data).toStrictEqual(token);
|
|
})
|
|
.respond(200, {
|
|
access_token: "at",
|
|
token: "tt",
|
|
});
|
|
|
|
const prom = client.registerWithIdentityServer(token);
|
|
await httpBackend.flushAllExpected();
|
|
const resp = await prom;
|
|
expect(resp.access_token).toBe("at");
|
|
expect(resp.token).toBe("tt");
|
|
});
|
|
});
|
|
|
|
describe("setPowerLevel", () => {
|
|
it.each([
|
|
{
|
|
userId: "alice@localhost",
|
|
powerLevel: 100,
|
|
expectation: {
|
|
"alice@localhost": 100,
|
|
},
|
|
},
|
|
{
|
|
userId: ["alice@localhost", "bob@localhost"],
|
|
powerLevel: 100,
|
|
expectation: {
|
|
"alice@localhost": 100,
|
|
"bob@localhost": 100,
|
|
},
|
|
},
|
|
{
|
|
userId: "alice@localhost",
|
|
powerLevel: undefined,
|
|
expectation: {},
|
|
},
|
|
])("should modify power levels of $userId correctly", async ({ userId, powerLevel, expectation }) => {
|
|
httpBackend.when("GET", "/state/m.room.power_levels/").respond(200, {
|
|
users: {
|
|
"alice@localhost": 50,
|
|
},
|
|
});
|
|
|
|
httpBackend
|
|
.when("PUT", "/state/m.room.power_levels")
|
|
.check((req) => {
|
|
expect(req.data.users).toStrictEqual(expectation);
|
|
})
|
|
.respond(200, {});
|
|
|
|
const prom = client.setPowerLevel("!room_id:server", userId, powerLevel);
|
|
await httpBackend.flushAllExpected();
|
|
await prom;
|
|
});
|
|
|
|
it("should use power level from room state if available", async () => {
|
|
client.clientRunning = true;
|
|
client.isInitialSyncComplete = () => true;
|
|
const room = new Room("!room_id:server", client, client.getUserId()!);
|
|
room.currentState.events.set("m.room.power_levels", new Map());
|
|
room.currentState.events.get("m.room.power_levels")!.set(
|
|
"",
|
|
new MatrixEvent({
|
|
type: "m.room.power_levels",
|
|
state_key: "",
|
|
content: {
|
|
users: {
|
|
"@bob:localhost": 50,
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
client.getRoom = () => room;
|
|
|
|
httpBackend
|
|
.when("PUT", "/state/m.room.power_levels")
|
|
.check((req) => {
|
|
expect(req.data).toStrictEqual({
|
|
users: {
|
|
"@bob:localhost": 50,
|
|
[userId]: 42,
|
|
},
|
|
});
|
|
})
|
|
.respond(200, {});
|
|
|
|
const prom = client.setPowerLevel("!room_id:server", userId, 42);
|
|
await httpBackend.flushAllExpected();
|
|
await prom;
|
|
});
|
|
|
|
it("should throw error if state API errors", async () => {
|
|
httpBackend.when("GET", "/state/m.room.power_levels/").respond(500, {
|
|
errcode: "ERR_DERP",
|
|
});
|
|
|
|
const prom = client.setPowerLevel("!room_id:server", userId, 42);
|
|
await Promise.all([
|
|
expect(prom).rejects.toMatchInlineSnapshot(`[ERR_DERP: MatrixError: [500] Unknown message]`),
|
|
httpBackend.flushAllExpected(),
|
|
]);
|
|
});
|
|
|
|
it("should not throw error if /state/ API returns M_NOT_FOUND", async () => {
|
|
httpBackend.when("GET", "/state/m.room.power_levels/").respond(404, {
|
|
errcode: "M_NOT_FOUND",
|
|
});
|
|
|
|
httpBackend
|
|
.when("PUT", "/state/m.room.power_levels")
|
|
.check((req) => {
|
|
expect(req.data).toStrictEqual({
|
|
users: {
|
|
[userId]: 42,
|
|
},
|
|
});
|
|
})
|
|
.respond(200, {});
|
|
|
|
const prom = client.setPowerLevel("!room_id:server", userId, 42);
|
|
await httpBackend.flushAllExpected();
|
|
await prom;
|
|
});
|
|
});
|
|
|
|
describe("setSyncPresence", () => {
|
|
it("should pass calls through to the underlying sync api", () => {
|
|
const setPresence = jest.fn();
|
|
// @ts-ignore
|
|
client.syncApi = { setPresence };
|
|
client.setSyncPresence(SetPresence.Unavailable);
|
|
expect(setPresence).toHaveBeenCalledWith(SetPresence.Unavailable);
|
|
});
|
|
});
|
|
|
|
describe("sendTyping", () => {
|
|
it("should bail early for guests", async () => {
|
|
client.setGuest(true);
|
|
await client.sendTyping("!room:server", true, 100);
|
|
});
|
|
|
|
it("should call /typing API", async () => {
|
|
client.setGuest(false);
|
|
httpBackend
|
|
.when("PUT", "/rooms/!room%3Aserver/typing/" + encodeURIComponent(client.getSafeUserId()))
|
|
.check((req) => {
|
|
expect(req.data).toEqual({
|
|
typing: true,
|
|
timeout: 100,
|
|
});
|
|
})
|
|
.respond(200, {});
|
|
await Promise.all([client.sendTyping("!room:server", true, 100), httpBackend.flushAllExpected()]);
|
|
});
|
|
});
|
|
|
|
describe("setGuestAccess", () => {
|
|
it("should set both guest access and history visibility if opts.allowRead=true", async () => {
|
|
httpBackend
|
|
.when("PUT", "/rooms/!room%3Aserver/state/m.room.guest_access/")
|
|
.check((req) => {
|
|
expect(req.data).toEqual({
|
|
guest_access: "forbidden",
|
|
});
|
|
})
|
|
.respond(200, { event_id: "$event1" });
|
|
httpBackend
|
|
.when("PUT", "/rooms/!room%3Aserver/state/m.room.history_visibility/")
|
|
.check((req) => {
|
|
expect(req.data).toEqual({
|
|
history_visibility: "world_readable",
|
|
});
|
|
})
|
|
.respond(200, { event_id: "$event2" });
|
|
await Promise.all([
|
|
client.setGuestAccess("!room:server", { allowRead: true, allowJoin: false }),
|
|
httpBackend.flushAllExpected(),
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("searchUserDirectory", () => {
|
|
it("should call /user_directory/search API", async () => {
|
|
httpBackend
|
|
.when("POST", "/user_directory/search")
|
|
.check((req) => {
|
|
expect(req.data).toEqual({
|
|
search_term: "This is my query",
|
|
});
|
|
})
|
|
.respond(200, {});
|
|
await Promise.all([
|
|
client.searchUserDirectory({ term: "This is my query" }),
|
|
httpBackend.flushAllExpected(),
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("getFallbackAuthUrl", () => {
|
|
it("should return fallback url", () => {
|
|
expect(client.getFallbackAuthUrl("loginType", "authSessionId")).toMatchInlineSnapshot(
|
|
`"http://alice.localhost.test.server/_matrix/client/v3/auth/loginType/fallback/web?session=authSessionId"`,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("addThreePidOnly", () => {
|
|
it("should make expected POST request", async () => {
|
|
httpBackend
|
|
.when("POST", "/_matrix/client/v3/account/3pid/add")
|
|
.check(function (req) {
|
|
expect(req.data).toEqual({
|
|
client_secret: "secret",
|
|
sid: "sid",
|
|
});
|
|
expect(req.headers["Authorization"]).toBe("Bearer " + accessToken);
|
|
})
|
|
.respond(200, {});
|
|
|
|
await Promise.all([
|
|
client.addThreePidOnly({
|
|
client_secret: "secret",
|
|
sid: "sid",
|
|
}),
|
|
httpBackend.flushAllExpected(),
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("bindThreePid", () => {
|
|
it("should make expected POST request", async () => {
|
|
httpBackend
|
|
.when("POST", "/_matrix/client/v3/account/3pid/bind")
|
|
.check(function (req) {
|
|
expect(req.data).toEqual({
|
|
client_secret: "secret",
|
|
id_server: "server",
|
|
id_access_token: "token",
|
|
sid: "sid",
|
|
});
|
|
expect(req.headers["Authorization"]).toBe("Bearer " + accessToken);
|
|
})
|
|
.respond(200, {});
|
|
|
|
await Promise.all([
|
|
client.bindThreePid({
|
|
client_secret: "secret",
|
|
id_server: "server",
|
|
id_access_token: "token",
|
|
sid: "sid",
|
|
}),
|
|
httpBackend.flushAllExpected(),
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("unbindThreePid", () => {
|
|
it("should make expected POST request", async () => {
|
|
httpBackend
|
|
.when("POST", "/_matrix/client/v3/account/3pid/unbind")
|
|
.check(function (req) {
|
|
expect(req.data).toEqual({
|
|
medium: "email",
|
|
address: "alice@server.com",
|
|
id_server: "identity.localhost",
|
|
});
|
|
expect(req.headers["Authorization"]).toBe("Bearer " + accessToken);
|
|
})
|
|
.respond(200, {});
|
|
|
|
await Promise.all([client.unbindThreePid("email", "alice@server.com"), httpBackend.flushAllExpected()]);
|
|
});
|
|
});
|
|
|
|
describe("getRoomSummary", () => {
|
|
const roomId = "!foo:bar";
|
|
const encodedRoomId = encodeURIComponent(roomId);
|
|
|
|
const roomSummary: RoomSummary = {
|
|
"room_id": roomId,
|
|
"name": "My Room",
|
|
"avatar_url": "",
|
|
"topic": "My room topic",
|
|
"world_readable": false,
|
|
"guest_can_join": false,
|
|
"num_joined_members": 1,
|
|
"room_type": "",
|
|
"join_rule": JoinRule.Public,
|
|
"membership": "leave",
|
|
"im.nheko.summary.room_version": "6",
|
|
"im.nheko.summary.encryption": "algo",
|
|
};
|
|
|
|
const prefix = "/_matrix/client/unstable/im.nheko.summary/";
|
|
const suffix = `summary/${encodedRoomId}`;
|
|
const deprecatedSuffix = `rooms/${encodedRoomId}/summary`;
|
|
|
|
const errorUnrecogStatus = 404;
|
|
const errorUnrecogBody = {
|
|
errcode: "M_UNRECOGNIZED",
|
|
error: "Unsupported endpoint",
|
|
};
|
|
|
|
const errorBadreqStatus = 400;
|
|
const errorBadreqBody = {
|
|
errcode: "M_UNKNOWN",
|
|
error: "Invalid request",
|
|
};
|
|
|
|
it("should respond with a valid room summary object", () => {
|
|
httpBackend.when("GET", prefix + suffix).respond(200, roomSummary);
|
|
|
|
const prom = client.getRoomSummary(roomId).then((response) => {
|
|
expect(response).toEqual(roomSummary);
|
|
});
|
|
|
|
httpBackend.flush("");
|
|
return prom;
|
|
});
|
|
|
|
it("should allow fallback to the deprecated endpoint", () => {
|
|
httpBackend.when("GET", prefix + suffix).respond(errorUnrecogStatus, errorUnrecogBody);
|
|
httpBackend.when("GET", prefix + deprecatedSuffix).respond(200, roomSummary);
|
|
|
|
const prom = client.getRoomSummary(roomId).then((response) => {
|
|
expect(response).toEqual(roomSummary);
|
|
});
|
|
|
|
httpBackend.flush("");
|
|
return prom;
|
|
});
|
|
|
|
it("should respond to unsupported path with error", () => {
|
|
httpBackend.when("GET", prefix + suffix).respond(errorUnrecogStatus, errorUnrecogBody);
|
|
httpBackend.when("GET", prefix + deprecatedSuffix).respond(errorUnrecogStatus, errorUnrecogBody);
|
|
|
|
const prom = client.getRoomSummary(roomId).then(
|
|
function (response) {
|
|
throw Error("request not failed");
|
|
},
|
|
function (error) {
|
|
expect(error.httpStatus).toEqual(errorUnrecogStatus);
|
|
expect(error.errcode).toEqual(errorUnrecogBody.errcode);
|
|
expect(error.message).toEqual(`MatrixError: [${errorUnrecogStatus}] ${errorUnrecogBody.error}`);
|
|
},
|
|
);
|
|
|
|
httpBackend.flush("");
|
|
return prom;
|
|
});
|
|
|
|
it("should respond to invalid path arguments with error", () => {
|
|
httpBackend.when("GET", prefix).respond(errorBadreqStatus, errorBadreqBody);
|
|
|
|
const prom = client.getRoomSummary("notAroom").then(
|
|
function (response) {
|
|
throw Error("request not failed");
|
|
},
|
|
function (error) {
|
|
expect(error.httpStatus).toEqual(errorBadreqStatus);
|
|
expect(error.errcode).toEqual(errorBadreqBody.errcode);
|
|
expect(error.message).toEqual(`MatrixError: [${errorBadreqStatus}] ${errorBadreqBody.error}`);
|
|
},
|
|
);
|
|
|
|
httpBackend.flush("");
|
|
return prom;
|
|
});
|
|
});
|
|
|
|
describe("getDomain", () => {
|
|
it("should return null if no userId is set", () => {
|
|
const client = new MatrixClient({ baseUrl: "http://localhost" });
|
|
expect(client.getDomain()).toBeNull();
|
|
});
|
|
|
|
it("should return the domain of the userId", () => {
|
|
expect(client.getDomain()).toBe("localhost");
|
|
});
|
|
});
|
|
|
|
describe("getUserIdLocalpart", () => {
|
|
it("should return null if no userId is set", () => {
|
|
const client = new MatrixClient({ baseUrl: "http://localhost" });
|
|
expect(client.getUserIdLocalpart()).toBeNull();
|
|
});
|
|
|
|
it("should return the localpart of the userId", () => {
|
|
expect(client.getUserIdLocalpart()).toBe("alice");
|
|
});
|
|
});
|
|
});
|
|
|
|
function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent {
|
|
const ret = event.toSnapshot();
|
|
ret.setThreadId(newThreadId);
|
|
return ret;
|
|
}
|
|
|
|
const buildEventMessageInThread = (root: MatrixEvent) =>
|
|
new MatrixEvent({
|
|
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 },
|
|
});
|
|
|
|
const buildEventPollResponseReference = () =>
|
|
new MatrixEvent({
|
|
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 },
|
|
});
|
|
|
|
const buildEventReaction = (event: MatrixEvent) =>
|
|
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: MatrixEvent) =>
|
|
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({
|
|
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 },
|
|
});
|
|
|
|
const buildEventReply = (target: MatrixEvent) =>
|
|
new MatrixEvent({
|
|
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 },
|
|
});
|
|
|
|
const buildEventRoomName = () =>
|
|
new MatrixEvent({
|
|
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 },
|
|
});
|
|
|
|
const buildEventEncryption = () =>
|
|
new MatrixEvent({
|
|
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 },
|
|
});
|
|
|
|
const buildEventGuestAccess = () =>
|
|
new MatrixEvent({
|
|
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 },
|
|
});
|
|
|
|
const buildEventHistoryVisibility = () =>
|
|
new MatrixEvent({
|
|
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 },
|
|
});
|
|
|
|
const buildEventJoinRules = () =>
|
|
new MatrixEvent({
|
|
content: {
|
|
join_rule: KnownMembership.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 },
|
|
});
|
|
|
|
const buildEventPowerLevels = () =>
|
|
new MatrixEvent({
|
|
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 },
|
|
});
|
|
|
|
const buildEventMember = () =>
|
|
new MatrixEvent({
|
|
content: {
|
|
avatar_url: "mxc://matrix.org/aNtbVcFfwotudypZcHsIcPOc",
|
|
displayname: "andybalaam-test1",
|
|
membership: KnownMembership.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 },
|
|
});
|
|
|
|
const buildEventCreate = () =>
|
|
new MatrixEvent({
|
|
content: {
|
|
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 },
|
|
});
|