You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-30 04:23:07 +03:00
Merge branch 'develop' into madlittlemods/stablize-msc3030-timestamp-to-event
Conflicts: spec/unit/matrix-client.spec.ts src/client.ts
This commit is contained in:
@ -40,7 +40,8 @@ import {
|
||||
ContentHelpers,
|
||||
ClientPrefix,
|
||||
Direction,
|
||||
EventTimeline, ICreateRoomOpts,
|
||||
EventTimeline,
|
||||
ICreateRoomOpts,
|
||||
IRequestOpts,
|
||||
MatrixError,
|
||||
MatrixHttpApi,
|
||||
@ -99,7 +100,7 @@ type WrappedRoom = Room & {
|
||||
_state: Map<string, any>;
|
||||
};
|
||||
|
||||
describe("MatrixClient", function() {
|
||||
describe("MatrixClient", function () {
|
||||
const userId = "@alice:bar";
|
||||
const identityServerUrl = "https://identity.server";
|
||||
const identityServerDomain = "identity.server";
|
||||
@ -160,13 +161,20 @@ describe("MatrixClient", function() {
|
||||
});
|
||||
}
|
||||
const next = httpLookups.shift();
|
||||
const logLine = (
|
||||
"MatrixClient[UT] RECV " + method + " " + path + " " +
|
||||
"EXPECT " + (next ? next.method : next) + " " + (next ? next.path : next)
|
||||
);
|
||||
const logLine =
|
||||
"MatrixClient[UT] RECV " +
|
||||
method +
|
||||
" " +
|
||||
path +
|
||||
" " +
|
||||
"EXPECT " +
|
||||
(next ? next.method : next) +
|
||||
" " +
|
||||
(next ? next.path : next);
|
||||
logger.log(logLine);
|
||||
|
||||
if (!next) { // no more things to return
|
||||
if (!next) {
|
||||
// no more things to return
|
||||
if (pendingLookup) {
|
||||
if (pendingLookup.method === method && pendingLookup.path === path) {
|
||||
return pendingLookup.promise;
|
||||
@ -185,15 +193,12 @@ describe("MatrixClient", function() {
|
||||
// lookup or it should match.
|
||||
const doesMatchPrefix = !next.prefix || next.prefix === prefix;
|
||||
if (doesMatchPrefix && next.path === path && next.method === method) {
|
||||
logger.log(
|
||||
"MatrixClient[UT] Matched. Returning " +
|
||||
(next.error ? "BAD" : "GOOD") + " response",
|
||||
);
|
||||
logger.log("MatrixClient[UT] Matched. Returning " + (next.error ? "BAD" : "GOOD") + " response");
|
||||
if (next.expectBody) {
|
||||
expect(body).toEqual(next.expectBody);
|
||||
}
|
||||
if (next.expectQueryParams) {
|
||||
Object.keys(next.expectQueryParams).forEach(function(k) {
|
||||
Object.keys(next.expectQueryParams).forEach(function (k) {
|
||||
expect(queryParams?.[k]).toEqual(next.expectQueryParams![k]);
|
||||
});
|
||||
}
|
||||
@ -237,18 +242,13 @@ describe("MatrixClient", function() {
|
||||
baseUrl: "https://my.home.server",
|
||||
idBaseUrl: identityServerUrl,
|
||||
accessToken: "my.access.token",
|
||||
fetchFn: function() {} as any, // NOP
|
||||
fetchFn: function () {} as any, // NOP
|
||||
store: store,
|
||||
scheduler: scheduler,
|
||||
userId: userId,
|
||||
});
|
||||
// FIXME: We shouldn't be yanking http like this.
|
||||
client.http = ([
|
||||
"authedRequest",
|
||||
"getContentUri",
|
||||
"request",
|
||||
"uploadContent",
|
||||
] as const).reduce((r, k) => {
|
||||
client.http = (["authedRequest", "getContentUri", "request", "uploadContent"] as const).reduce((r, k) => {
|
||||
r[k] = jest.fn();
|
||||
return r;
|
||||
}, {} as MatrixHttpApi<any>);
|
||||
@ -256,22 +256,35 @@ describe("MatrixClient", function() {
|
||||
mocked(client.http.request).mockImplementation(httpReq);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
scheduler = ([
|
||||
"getQueueForEvent",
|
||||
"queueEvent",
|
||||
"removeEventFromQueue",
|
||||
"setProcessFunction",
|
||||
] as const).reduce((r, k) => {
|
||||
r[k] = jest.fn();
|
||||
return r;
|
||||
}, {} as MatrixScheduler);
|
||||
store = ([
|
||||
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
|
||||
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom", "storeUser",
|
||||
"getFilterIdByName", "setFilterIdByName", "getFilter", "storeFilter",
|
||||
"startup", "deleteAllData",
|
||||
] as const).reduce((r, k) => {
|
||||
beforeEach(function () {
|
||||
scheduler = (["getQueueForEvent", "queueEvent", "removeEventFromQueue", "setProcessFunction"] as const).reduce(
|
||||
(r, k) => {
|
||||
r[k] = jest.fn();
|
||||
return r;
|
||||
},
|
||||
{} as MatrixScheduler,
|
||||
);
|
||||
store = (
|
||||
[
|
||||
"getRoom",
|
||||
"getRooms",
|
||||
"getUser",
|
||||
"getSyncToken",
|
||||
"scrollback",
|
||||
"save",
|
||||
"wantsSave",
|
||||
"setSyncToken",
|
||||
"storeEvents",
|
||||
"storeRoom",
|
||||
"storeUser",
|
||||
"getFilterIdByName",
|
||||
"setFilterIdByName",
|
||||
"getFilter",
|
||||
"storeFilter",
|
||||
"startup",
|
||||
"deleteAllData",
|
||||
] as const
|
||||
).reduce((r, k) => {
|
||||
r[k] = jest.fn();
|
||||
return r;
|
||||
}, {} as Store);
|
||||
@ -292,13 +305,13 @@ describe("MatrixClient", function() {
|
||||
httpLookups.push(SYNC_RESPONSE);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
afterEach(function () {
|
||||
// need to re-stub the requests with NOPs because there are no guarantees
|
||||
// clients from previous tests will be GC'd before the next test. This
|
||||
// means they may call /events and then fail an expect() which will fail
|
||||
// a DIFFERENT test (pollution between tests!) - we return unresolved
|
||||
// promises to stop the client from continuing to run.
|
||||
mocked(client.http.authedRequest).mockImplementation(function() {
|
||||
mocked(client.http.authedRequest).mockImplementation(function () {
|
||||
return new Promise(() => {});
|
||||
});
|
||||
client.stopClient();
|
||||
@ -436,12 +449,14 @@ describe("MatrixClient", function() {
|
||||
it("overload without threadId works", async () => {
|
||||
const eventId = "$eventId:example.org";
|
||||
const txnId = client.makeTxnId();
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: content,
|
||||
}];
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: content,
|
||||
},
|
||||
];
|
||||
|
||||
await client.sendEvent(roomId, EventType.RoomMessage, { ...content }, txnId);
|
||||
});
|
||||
@ -449,12 +464,14 @@ describe("MatrixClient", function() {
|
||||
it("overload with null threadId works", async () => {
|
||||
const eventId = "$eventId:example.org";
|
||||
const txnId = client.makeTxnId();
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: content,
|
||||
}];
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: content,
|
||||
},
|
||||
];
|
||||
|
||||
await client.sendEvent(roomId, null, EventType.RoomMessage, { ...content }, txnId);
|
||||
});
|
||||
@ -463,19 +480,21 @@ describe("MatrixClient", function() {
|
||||
const eventId = "$eventId:example.org";
|
||||
const txnId = client.makeTxnId();
|
||||
const threadId = "$threadId:server";
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: {
|
||||
...content,
|
||||
"m.relates_to": {
|
||||
"event_id": threadId,
|
||||
"is_falling_back": true,
|
||||
"rel_type": "m.thread",
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: {
|
||||
...content,
|
||||
"m.relates_to": {
|
||||
event_id: threadId,
|
||||
is_falling_back: true,
|
||||
rel_type: "m.thread",
|
||||
},
|
||||
},
|
||||
},
|
||||
}];
|
||||
];
|
||||
|
||||
await client.sendEvent(roomId, threadId, EventType.RoomMessage, { ...content }, txnId);
|
||||
});
|
||||
@ -491,22 +510,24 @@ describe("MatrixClient", function() {
|
||||
const rootEvent = new MatrixEvent({ event_id: threadId });
|
||||
room.createThread(threadId, rootEvent, [rootEvent], false);
|
||||
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: {
|
||||
...content,
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
event_id: threadId,
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: {
|
||||
...content,
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
event_id: threadId,
|
||||
},
|
||||
"event_id": threadId,
|
||||
"is_falling_back": true,
|
||||
"rel_type": "m.thread",
|
||||
},
|
||||
"event_id": threadId,
|
||||
"is_falling_back": true,
|
||||
"rel_type": "m.thread",
|
||||
},
|
||||
},
|
||||
}];
|
||||
];
|
||||
|
||||
await client.sendEvent(roomId, threadId, EventType.RoomMessage, { ...content }, txnId);
|
||||
});
|
||||
@ -531,22 +552,24 @@ describe("MatrixClient", function() {
|
||||
const rootEvent = new MatrixEvent({ event_id: threadId });
|
||||
room.createThread(threadId, rootEvent, [rootEvent], false);
|
||||
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: {
|
||||
...content,
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
event_id: "$other:event",
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
expectBody: {
|
||||
...content,
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
event_id: "$other:event",
|
||||
},
|
||||
"event_id": threadId,
|
||||
"is_falling_back": false,
|
||||
"rel_type": "m.thread",
|
||||
},
|
||||
"event_id": threadId,
|
||||
"is_falling_back": false,
|
||||
"rel_type": "m.thread",
|
||||
},
|
||||
},
|
||||
}];
|
||||
];
|
||||
|
||||
await client.sendEvent(roomId, threadId, EventType.RoomMessage, { ...content }, txnId);
|
||||
});
|
||||
@ -732,15 +755,12 @@ describe("MatrixClient", function() {
|
||||
expect(tree).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should not POST /filter if a matching filter already exists", async function() {
|
||||
httpLookups = [
|
||||
PUSH_RULES_RESPONSE,
|
||||
SYNC_RESPONSE,
|
||||
];
|
||||
it("should not POST /filter if a matching filter already exists", async function () {
|
||||
httpLookups = [PUSH_RULES_RESPONSE, SYNC_RESPONSE];
|
||||
const filterId = "ehfewf";
|
||||
mocked(store.getFilterIdByName).mockReturnValue(filterId);
|
||||
const filter = new Filter("0", filterId);
|
||||
filter.setDefinition({ "room": { "timeline": { "limit": 8 } } });
|
||||
filter.setDefinition({ room: { timeline: { limit: 8 } } });
|
||||
mocked(store.getFilter).mockReturnValue(filter);
|
||||
const syncPromise = new Promise<void>((resolve, reject) => {
|
||||
client.on(ClientEvent.Sync, function syncListener(state) {
|
||||
@ -757,12 +777,12 @@ describe("MatrixClient", function() {
|
||||
await syncPromise;
|
||||
});
|
||||
|
||||
describe("getSyncState", function() {
|
||||
it("should return null if the client isn't started", function() {
|
||||
describe("getSyncState", function () {
|
||||
it("should return null if the client isn't started", function () {
|
||||
expect(client.getSyncState()).toBe(null);
|
||||
});
|
||||
|
||||
it("should return the same sync state as emitted sync events", async function() {
|
||||
it("should return the same sync state as emitted sync events", async function () {
|
||||
const syncingPromise = new Promise<void>((resolve) => {
|
||||
client.on(ClientEvent.Sync, function syncListener(state) {
|
||||
expect(state).toEqual(client.getSyncState());
|
||||
@ -777,22 +797,20 @@ describe("MatrixClient", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("getOrCreateFilter", function() {
|
||||
it("should POST createFilter if no id is present in localStorage", function() {
|
||||
});
|
||||
it("should use an existing filter if id is present in localStorage", function() {
|
||||
});
|
||||
it("should handle localStorage filterId missing from the server", function(done) {
|
||||
describe("getOrCreateFilter", function () {
|
||||
it("should POST createFilter if no id is present in localStorage", function () {});
|
||||
it("should use an existing filter if id is present in localStorage", function () {});
|
||||
it("should handle localStorage filterId missing from the server", function (done) {
|
||||
function getFilterName(userId: string, suffix?: string) {
|
||||
// scope this on the user ID because people may login on many accounts
|
||||
// and they all need to be stored!
|
||||
return "FILTER_SYNC_" + userId + (suffix ? "_" + suffix : "");
|
||||
}
|
||||
const invalidFilterId = 'invalidF1lt3r';
|
||||
const invalidFilterId = "invalidF1lt3r";
|
||||
httpLookups = [];
|
||||
httpLookups.push({
|
||||
method: "GET",
|
||||
path: FILTER_PATH + '/' + invalidFilterId,
|
||||
path: FILTER_PATH + "/" + invalidFilterId,
|
||||
error: {
|
||||
errcode: "M_UNKNOWN",
|
||||
name: "M_UNKNOWN",
|
||||
@ -808,25 +826,27 @@ describe("MatrixClient", function() {
|
||||
client.store.setFilterIdByName(filterName, invalidFilterId);
|
||||
const filter = new Filter(client.credentials.userId);
|
||||
|
||||
client.getOrCreateFilter(filterName, filter).then(function(filterId) {
|
||||
client.getOrCreateFilter(filterName, filter).then(function (filterId) {
|
||||
expect(filterId).toEqual(FILTER_RESPONSE.data?.filter_id);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("retryImmediately", function() {
|
||||
it("should return false if there is no request waiting", async function() {
|
||||
describe("retryImmediately", function () {
|
||||
it("should return false if there is no request waiting", async function () {
|
||||
httpLookups = [];
|
||||
await client.startClient();
|
||||
expect(client.retryImmediately()).toBe(false);
|
||||
});
|
||||
|
||||
it("should work on /filter", function(done) {
|
||||
it("should work on /filter", function (done) {
|
||||
httpLookups = [];
|
||||
httpLookups.push(PUSH_RULES_RESPONSE);
|
||||
httpLookups.push({
|
||||
method: "POST", path: FILTER_PATH, error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
method: "POST",
|
||||
path: FILTER_PATH,
|
||||
error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
});
|
||||
httpLookups.push(FILTER_RESPONSE);
|
||||
httpLookups.push(SYNC_RESPONSE);
|
||||
@ -847,20 +867,22 @@ describe("MatrixClient", function() {
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
it("should work on /sync", function(done) {
|
||||
it("should work on /sync", function (done) {
|
||||
httpLookups.push({
|
||||
method: "GET", path: "/sync", error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
method: "GET",
|
||||
path: "/sync",
|
||||
error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
});
|
||||
httpLookups.push({
|
||||
method: "GET", path: "/sync", data: SYNC_DATA,
|
||||
method: "GET",
|
||||
path: "/sync",
|
||||
data: SYNC_DATA,
|
||||
});
|
||||
|
||||
client.on(ClientEvent.Sync, function syncListener(state) {
|
||||
if (state === "ERROR" && httpLookups.length > 0) {
|
||||
expect(httpLookups.length).toEqual(1);
|
||||
expect(client.retryImmediately()).toBe(
|
||||
true,
|
||||
);
|
||||
expect(client.retryImmediately()).toBe(true);
|
||||
jest.advanceTimersByTime(1);
|
||||
} else if (state === "RECONNECTING" && httpLookups.length > 0) {
|
||||
jest.advanceTimersByTime(10000);
|
||||
@ -872,10 +894,12 @@ describe("MatrixClient", function() {
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
it("should work on /pushrules", function(done) {
|
||||
it("should work on /pushrules", function (done) {
|
||||
httpLookups = [];
|
||||
httpLookups.push({
|
||||
method: "GET", path: "/pushrules/", error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
method: "GET",
|
||||
path: "/pushrules/",
|
||||
error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
});
|
||||
httpLookups.push(PUSH_RULES_RESPONSE);
|
||||
httpLookups.push(FILTER_RESPONSE);
|
||||
@ -898,13 +922,11 @@ describe("MatrixClient", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("emitted sync events", function() {
|
||||
describe("emitted sync events", function () {
|
||||
function syncChecker(expectedStates: [string, string | null][], done: Function) {
|
||||
return function syncListener(state: SyncState, old: SyncState | null) {
|
||||
const expected = expectedStates.shift();
|
||||
logger.log(
|
||||
"'sync' curr=%s old=%s EXPECT=%s", state, old, expected,
|
||||
);
|
||||
logger.log("'sync' curr=%s old=%s EXPECT=%s", state, old, expected);
|
||||
if (!expected) {
|
||||
done();
|
||||
return;
|
||||
@ -920,19 +942,21 @@ describe("MatrixClient", function() {
|
||||
};
|
||||
}
|
||||
|
||||
it("should transition null -> PREPARED after the first /sync", function(done) {
|
||||
it("should transition null -> PREPARED after the first /sync", function (done) {
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
expectedStates.push(["PREPARED", null]);
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
it("should transition null -> ERROR after a failed /filter", function(done) {
|
||||
it("should transition null -> ERROR after a failed /filter", function (done) {
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
httpLookups = [];
|
||||
httpLookups.push(PUSH_RULES_RESPONSE);
|
||||
httpLookups.push({
|
||||
method: "POST", path: FILTER_PATH, error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
method: "POST",
|
||||
path: FILTER_PATH,
|
||||
error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
});
|
||||
expectedStates.push(["ERROR", null]);
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
@ -942,24 +966,31 @@ describe("MatrixClient", function() {
|
||||
// Disabled because now `startClient` makes a legit call to `/versions`
|
||||
// And those tests are really unhappy about it... Not possible to figure
|
||||
// out what a good resolution would look like
|
||||
xit("should transition ERROR -> CATCHUP after /sync if prev failed", function(done) {
|
||||
xit("should transition ERROR -> CATCHUP after /sync if prev failed", function (done) {
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
acceptKeepalives = false;
|
||||
httpLookups = [];
|
||||
httpLookups.push(PUSH_RULES_RESPONSE);
|
||||
httpLookups.push(FILTER_RESPONSE);
|
||||
httpLookups.push({
|
||||
method: "GET", path: "/sync", error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
method: "GET",
|
||||
path: "/sync",
|
||||
error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
});
|
||||
httpLookups.push({
|
||||
method: "GET", path: KEEP_ALIVE_PATH,
|
||||
method: "GET",
|
||||
path: KEEP_ALIVE_PATH,
|
||||
error: { errcode: "KEEPALIVE_FAIL" },
|
||||
});
|
||||
httpLookups.push({
|
||||
method: "GET", path: KEEP_ALIVE_PATH, data: {},
|
||||
method: "GET",
|
||||
path: KEEP_ALIVE_PATH,
|
||||
data: {},
|
||||
});
|
||||
httpLookups.push({
|
||||
method: "GET", path: "/sync", data: SYNC_DATA,
|
||||
method: "GET",
|
||||
path: "/sync",
|
||||
data: SYNC_DATA,
|
||||
});
|
||||
|
||||
expectedStates.push(["RECONNECTING", null]);
|
||||
@ -969,7 +1000,7 @@ describe("MatrixClient", function() {
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
it("should transition PREPARED -> SYNCING after /sync", function(done) {
|
||||
it("should transition PREPARED -> SYNCING after /sync", function (done) {
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
expectedStates.push(["PREPARED", null]);
|
||||
expectedStates.push(["SYNCING", "PREPARED"]);
|
||||
@ -977,14 +1008,17 @@ describe("MatrixClient", function() {
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
xit("should transition SYNCING -> ERROR after a failed /sync", function(done) {
|
||||
xit("should transition SYNCING -> ERROR after a failed /sync", function (done) {
|
||||
acceptKeepalives = false;
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
httpLookups.push({
|
||||
method: "GET", path: "/sync", error: { errcode: "NONONONONO" },
|
||||
method: "GET",
|
||||
path: "/sync",
|
||||
error: { errcode: "NONONONONO" },
|
||||
});
|
||||
httpLookups.push({
|
||||
method: "GET", path: KEEP_ALIVE_PATH,
|
||||
method: "GET",
|
||||
path: KEEP_ALIVE_PATH,
|
||||
error: { errcode: "KEEPALIVE_FAIL" },
|
||||
});
|
||||
|
||||
@ -996,10 +1030,12 @@ describe("MatrixClient", function() {
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
xit("should transition ERROR -> SYNCING after /sync if prev failed", function(done) {
|
||||
xit("should transition ERROR -> SYNCING after /sync if prev failed", function (done) {
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
httpLookups.push({
|
||||
method: "GET", path: "/sync", error: { errcode: "NONONONONO" },
|
||||
method: "GET",
|
||||
path: "/sync",
|
||||
error: { errcode: "NONONONONO" },
|
||||
});
|
||||
httpLookups.push(SYNC_RESPONSE);
|
||||
|
||||
@ -1010,7 +1046,7 @@ describe("MatrixClient", function() {
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
it("should transition SYNCING -> SYNCING on subsequent /sync successes", function(done) {
|
||||
it("should transition SYNCING -> SYNCING on subsequent /sync successes", function (done) {
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
httpLookups.push(SYNC_RESPONSE);
|
||||
httpLookups.push(SYNC_RESPONSE);
|
||||
@ -1022,18 +1058,22 @@ describe("MatrixClient", function() {
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
xit("should transition ERROR -> ERROR if keepalive keeps failing", function(done) {
|
||||
xit("should transition ERROR -> ERROR if keepalive keeps failing", function (done) {
|
||||
acceptKeepalives = false;
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
httpLookups.push({
|
||||
method: "GET", path: "/sync", error: { errcode: "NONONONONO" },
|
||||
method: "GET",
|
||||
path: "/sync",
|
||||
error: { errcode: "NONONONONO" },
|
||||
});
|
||||
httpLookups.push({
|
||||
method: "GET", path: KEEP_ALIVE_PATH,
|
||||
method: "GET",
|
||||
path: KEEP_ALIVE_PATH,
|
||||
error: { errcode: "KEEPALIVE_FAIL" },
|
||||
});
|
||||
httpLookups.push({
|
||||
method: "GET", path: KEEP_ALIVE_PATH,
|
||||
method: "GET",
|
||||
path: KEEP_ALIVE_PATH,
|
||||
error: { errcode: "KEEPALIVE_FAIL" },
|
||||
});
|
||||
|
||||
@ -1047,27 +1087,29 @@ describe("MatrixClient", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("inviteByEmail", function() {
|
||||
describe("inviteByEmail", function () {
|
||||
const roomId = "!foo:bar";
|
||||
|
||||
it("should send an invite HTTP POST", function() {
|
||||
httpLookups = [{
|
||||
method: "POST",
|
||||
path: "/rooms/!foo%3Abar/invite",
|
||||
data: {},
|
||||
expectBody: {
|
||||
id_server: identityServerDomain,
|
||||
medium: "email",
|
||||
address: "alice@gmail.com",
|
||||
it("should send an invite HTTP POST", function () {
|
||||
httpLookups = [
|
||||
{
|
||||
method: "POST",
|
||||
path: "/rooms/!foo%3Abar/invite",
|
||||
data: {},
|
||||
expectBody: {
|
||||
id_server: identityServerDomain,
|
||||
medium: "email",
|
||||
address: "alice@gmail.com",
|
||||
},
|
||||
},
|
||||
}];
|
||||
];
|
||||
client.inviteByEmail(roomId, "alice@gmail.com");
|
||||
expect(httpLookups.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("guest rooms", function() {
|
||||
it("should only do /sync calls (without filter/pushrules)", async function() {
|
||||
describe("guest rooms", function () {
|
||||
it("should only do /sync calls (without filter/pushrules)", async function () {
|
||||
httpLookups = []; // no /pushrules or /filter
|
||||
httpLookups.push({
|
||||
method: "GET",
|
||||
@ -1079,20 +1121,21 @@ describe("MatrixClient", function() {
|
||||
expect(httpLookups.length).toBe(0);
|
||||
});
|
||||
|
||||
xit("should be able to peek into a room using peekInRoom", function(done) {
|
||||
});
|
||||
xit("should be able to peek into a room using peekInRoom", function (done) {});
|
||||
});
|
||||
|
||||
describe("getPresence", function() {
|
||||
it("should send a presence HTTP GET", function() {
|
||||
httpLookups = [{
|
||||
method: "GET",
|
||||
path: `/presence/${encodeURIComponent(userId)}/status`,
|
||||
data: {
|
||||
"presence": "unavailable",
|
||||
"last_active_ago": 420845,
|
||||
describe("getPresence", function () {
|
||||
it("should send a presence HTTP GET", function () {
|
||||
httpLookups = [
|
||||
{
|
||||
method: "GET",
|
||||
path: `/presence/${encodeURIComponent(userId)}/status`,
|
||||
data: {
|
||||
presence: "unavailable",
|
||||
last_active_ago: 420845,
|
||||
},
|
||||
},
|
||||
}];
|
||||
];
|
||||
client.getPresence(userId);
|
||||
expect(httpLookups.length).toEqual(0);
|
||||
});
|
||||
@ -1130,11 +1173,13 @@ describe("MatrixClient", function() {
|
||||
it("overload without threadId works", async () => {
|
||||
const eventId = "$eventId:example.org";
|
||||
const txnId = client.makeTxnId();
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
}];
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
},
|
||||
];
|
||||
|
||||
await client.redactEvent(roomId, eventId, txnId);
|
||||
});
|
||||
@ -1142,11 +1187,13 @@ describe("MatrixClient", function() {
|
||||
it("overload with null threadId works", async () => {
|
||||
const eventId = "$eventId:example.org";
|
||||
const txnId = client.makeTxnId();
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
}];
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
},
|
||||
];
|
||||
|
||||
await client.redactEvent(roomId, null, eventId, txnId);
|
||||
});
|
||||
@ -1154,11 +1201,13 @@ describe("MatrixClient", function() {
|
||||
it("overload with threadId works", async () => {
|
||||
const eventId = "$eventId:example.org";
|
||||
const txnId = client.makeTxnId();
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
}];
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${txnId}`,
|
||||
data: { event_id: eventId },
|
||||
},
|
||||
];
|
||||
|
||||
await client.redactEvent(roomId, "$threadId:server", eventId, txnId);
|
||||
});
|
||||
@ -1167,12 +1216,14 @@ describe("MatrixClient", function() {
|
||||
const eventId = "$eventId:example.org";
|
||||
const txnId = client.makeTxnId();
|
||||
const reason = "This is the redaction reason";
|
||||
httpLookups = [{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${txnId}`,
|
||||
expectBody: { reason }, // NOT ENCRYPTED
|
||||
data: { event_id: eventId },
|
||||
}];
|
||||
httpLookups = [
|
||||
{
|
||||
method: "PUT",
|
||||
path: `/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${txnId}`,
|
||||
expectBody: { reason }, // NOT ENCRYPTED
|
||||
data: { event_id: eventId },
|
||||
},
|
||||
];
|
||||
|
||||
await client.redactEvent(roomId, eventId, txnId, { reason });
|
||||
});
|
||||
@ -1218,7 +1269,8 @@ describe("MatrixClient", function() {
|
||||
expect(getRoomId).toEqual(roomId);
|
||||
return mockRoom;
|
||||
};
|
||||
client.crypto = { // mock crypto
|
||||
client.crypto = {
|
||||
// mock crypto
|
||||
encryptEvent: () => new Promise(() => {}),
|
||||
stop: jest.fn(),
|
||||
} as unknown as Crypto;
|
||||
@ -1227,7 +1279,7 @@ describe("MatrixClient", function() {
|
||||
function assertCancelled() {
|
||||
expect(event.status).toBe(EventStatus.CANCELLED);
|
||||
expect(client.scheduler?.removeEventFromQueue(event)).toBeFalsy();
|
||||
expect(httpLookups.filter(h => h.path.includes("/send/")).length).toBe(0);
|
||||
expect(httpLookups.filter((h) => h.path.includes("/send/")).length).toBe(0);
|
||||
}
|
||||
|
||||
it("should cancel an event which is queued", () => {
|
||||
@ -1265,22 +1317,22 @@ describe("MatrixClient", function() {
|
||||
const room = new Room("!room1:matrix.org", client, userId);
|
||||
|
||||
const rootEvent = new MatrixEvent({
|
||||
"content": {},
|
||||
"origin_server_ts": 1,
|
||||
"room_id": "!room1:matrix.org",
|
||||
"sender": "@alice:matrix.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
content: {},
|
||||
origin_server_ts: 1,
|
||||
room_id: "!room1:matrix.org",
|
||||
sender: "@alice:matrix.org",
|
||||
type: "m.room.message",
|
||||
unsigned: {
|
||||
"m.relations": {
|
||||
"m.thread": {
|
||||
"latest_event": {},
|
||||
"count": 33,
|
||||
"current_user_participated": false,
|
||||
latest_event: {},
|
||||
count: 33,
|
||||
current_user_participated: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
"event_id": "$ev1",
|
||||
"user_id": "@alice:matrix.org",
|
||||
event_id: "$ev1",
|
||||
user_id: "@alice:matrix.org",
|
||||
});
|
||||
|
||||
expect(rootEvent.isThreadRoot).toBe(true);
|
||||
@ -1305,12 +1357,7 @@ describe("MatrixClient", function() {
|
||||
const rpEvent = new MatrixEvent({ event_id: "read_private_event_id" });
|
||||
client.getRoom = () => room;
|
||||
|
||||
client.setRoomReadMarkers(
|
||||
"room_id",
|
||||
"read_marker_event_id",
|
||||
rrEvent,
|
||||
rpEvent,
|
||||
);
|
||||
client.setRoomReadMarkers("room_id", "read_marker_event_id", rrEvent, rpEvent);
|
||||
|
||||
expect(client.setRoomReadMarkersHttpRequest).toHaveBeenCalledWith(
|
||||
"room_id",
|
||||
@ -1335,7 +1382,7 @@ describe("MatrixClient", function() {
|
||||
});
|
||||
|
||||
describe("beacons", () => {
|
||||
const roomId = '!room:server.org';
|
||||
const roomId = "!room:server.org";
|
||||
const content = makeBeaconInfoContent(100, true);
|
||||
|
||||
beforeEach(() => {
|
||||
@ -1348,10 +1395,10 @@ describe("MatrixClient", function() {
|
||||
// event type combined
|
||||
const expectedEventType = M_BEACON_INFO.name;
|
||||
const [method, path, queryParams, requestContent] = mocked(client.http.authedRequest).mock.calls[0];
|
||||
expect(method).toBe('PUT');
|
||||
expect(method).toBe("PUT");
|
||||
expect(path).toEqual(
|
||||
`/rooms/${encodeURIComponent(roomId)}/state/` +
|
||||
`${encodeURIComponent(expectedEventType)}/${encodeURIComponent(userId)}`,
|
||||
`${encodeURIComponent(expectedEventType)}/${encodeURIComponent(userId)}`,
|
||||
);
|
||||
expect(queryParams).toBeFalsy();
|
||||
expect(requestContent).toEqual(content);
|
||||
@ -1364,31 +1411,31 @@ describe("MatrixClient", function() {
|
||||
const [, path, , requestContent] = mocked(client.http.authedRequest).mock.calls[0];
|
||||
expect(path).toEqual(
|
||||
`/rooms/${encodeURIComponent(roomId)}/state/` +
|
||||
`${encodeURIComponent(M_BEACON_INFO.name)}/${encodeURIComponent(userId)}`,
|
||||
`${encodeURIComponent(M_BEACON_INFO.name)}/${encodeURIComponent(userId)}`,
|
||||
);
|
||||
expect(requestContent).toEqual(content);
|
||||
});
|
||||
|
||||
describe('processBeaconEvents()', () => {
|
||||
it('does nothing when events is falsy', () => {
|
||||
describe("processBeaconEvents()", () => {
|
||||
it("does nothing when events is falsy", () => {
|
||||
const room = new Room(roomId, client, userId);
|
||||
const roomStateProcessSpy = jest.spyOn(room.currentState, 'processBeaconEvents');
|
||||
const roomStateProcessSpy = jest.spyOn(room.currentState, "processBeaconEvents");
|
||||
|
||||
client.processBeaconEvents(room, undefined);
|
||||
expect(roomStateProcessSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does nothing when events is of length 0', () => {
|
||||
it("does nothing when events is of length 0", () => {
|
||||
const room = new Room(roomId, client, userId);
|
||||
const roomStateProcessSpy = jest.spyOn(room.currentState, 'processBeaconEvents');
|
||||
const roomStateProcessSpy = jest.spyOn(room.currentState, "processBeaconEvents");
|
||||
|
||||
client.processBeaconEvents(room, []);
|
||||
expect(roomStateProcessSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls room states processBeaconEvents with events', () => {
|
||||
it("calls room states processBeaconEvents with events", () => {
|
||||
const room = new Room(roomId, client, userId);
|
||||
const roomStateProcessSpy = jest.spyOn(room.currentState, 'processBeaconEvents');
|
||||
const roomStateProcessSpy = jest.spyOn(room.currentState, "processBeaconEvents");
|
||||
|
||||
const messageEvent = testUtils.mkMessage({ room: roomId, user: userId, event: true });
|
||||
const beaconEvent = makeBeaconEvent(userId);
|
||||
@ -1402,14 +1449,13 @@ describe("MatrixClient", function() {
|
||||
describe("setRoomTopic", () => {
|
||||
const roomId = "!foofoofoofoofoofoo:matrix.org";
|
||||
const createSendStateEventMock = (topic: string, htmlTopic?: string) => {
|
||||
return jest.fn()
|
||||
.mockImplementation((roomId: string, eventType: string, content: any, stateKey: string) => {
|
||||
expect(roomId).toEqual(roomId);
|
||||
expect(eventType).toEqual(EventType.RoomTopic);
|
||||
expect(content).toMatchObject(ContentHelpers.makeTopicContent(topic, htmlTopic));
|
||||
expect(stateKey).toBeUndefined();
|
||||
return Promise.resolve();
|
||||
});
|
||||
return jest.fn().mockImplementation((roomId: string, eventType: string, content: any, stateKey: string) => {
|
||||
expect(roomId).toEqual(roomId);
|
||||
expect(eventType).toEqual(EventType.RoomTopic);
|
||||
expect(content).toMatchObject(ContentHelpers.makeTopicContent(topic, htmlTopic));
|
||||
expect(stateKey).toBeUndefined();
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
it("is called with plain text topic and sends state event", async () => {
|
||||
@ -1435,13 +1481,13 @@ describe("MatrixClient", function() {
|
||||
});
|
||||
|
||||
describe("setPassword", () => {
|
||||
const auth = { session: 'abcdef', type: 'foo' };
|
||||
const newPassword = 'newpassword';
|
||||
const auth = { session: "abcdef", type: "foo" };
|
||||
const newPassword = "newpassword";
|
||||
|
||||
const passwordTest = (expectedRequestContent: any) => {
|
||||
const [method, path, queryParams, requestContent] = mocked(client.http.authedRequest).mock.calls[0];
|
||||
expect(method).toBe('POST');
|
||||
expect(path).toEqual('/account/password');
|
||||
expect(method).toBe("POST");
|
||||
expect(path).toEqual("/account/password");
|
||||
expect(queryParams).toBeFalsy();
|
||||
expect(requestContent).toEqual(expectedRequestContent);
|
||||
};
|
||||
@ -1494,7 +1540,7 @@ describe("MatrixClient", function() {
|
||||
// Current version of the endpoint we support is v3
|
||||
const [method, path, queryParams, data, opts] = mocked(client.http.authedRequest).mock.calls[0];
|
||||
expect(data).toBeFalsy();
|
||||
expect(method).toBe('GET');
|
||||
expect(method).toBe("GET");
|
||||
expect(path).toEqual(`/rooms/${encodeURIComponent(roomId)}/aliases`);
|
||||
expect(opts).toMatchObject({ prefix: "/_matrix/client/v3" });
|
||||
expect(queryParams).toBeFalsy();
|
||||
@ -1557,11 +1603,17 @@ describe("MatrixClient", function() {
|
||||
client.on(ClientEvent.TurnServers, onTurnServers);
|
||||
expect(await client.checkTurnServers()).toBe(true);
|
||||
client.off(ClientEvent.TurnServers, onTurnServers);
|
||||
expect(events).toEqual([[[{
|
||||
urls: turnServer.uris,
|
||||
username: turnServer.username,
|
||||
credential: turnServer.password,
|
||||
}]]]);
|
||||
expect(events).toEqual([
|
||||
[
|
||||
[
|
||||
{
|
||||
urls: turnServer.uris,
|
||||
username: turnServer.username,
|
||||
credential: turnServer.password,
|
||||
},
|
||||
],
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it("emits an event when an error occurs", async () => {
|
||||
@ -1608,11 +1660,11 @@ describe("MatrixClient", function() {
|
||||
beforeEach(() => {
|
||||
// Mockup `getAccountData`/`setAccountData`.
|
||||
const dataStore = new Map();
|
||||
client.setAccountData = function(eventType, content) {
|
||||
client.setAccountData = function (eventType, content) {
|
||||
dataStore.set(eventType, content);
|
||||
return Promise.resolve({});
|
||||
};
|
||||
client.getAccountData = function(eventType) {
|
||||
client.getAccountData = function (eventType) {
|
||||
const data = dataStore.get(eventType);
|
||||
return new MatrixEvent({
|
||||
content: data,
|
||||
@ -1621,23 +1673,23 @@ describe("MatrixClient", function() {
|
||||
|
||||
// Mockup `createRoom`/`getRoom`/`joinRoom`, including state.
|
||||
const rooms = new Map();
|
||||
client.createRoom = function(options: Options = {}) {
|
||||
client.createRoom = function (options: Options = {}) {
|
||||
const roomId = options["_roomId"] || `!room-${rooms.size}:example.org`;
|
||||
const state = new Map<string, any>();
|
||||
const room = {
|
||||
roomId,
|
||||
_options: options,
|
||||
_state: state,
|
||||
getUnfilteredTimelineSet: function() {
|
||||
getUnfilteredTimelineSet: function () {
|
||||
return {
|
||||
getLiveTimeline: function() {
|
||||
getLiveTimeline: function () {
|
||||
return {
|
||||
getState: function(direction) {
|
||||
getState: function (direction) {
|
||||
expect(direction).toBe(EventTimeline.FORWARDS);
|
||||
return {
|
||||
getStateEvents: function(type) {
|
||||
getStateEvents: function (type) {
|
||||
const store = state.get(type) || {};
|
||||
return Object.keys(store).map(key => store[key]);
|
||||
return Object.keys(store).map((key) => store[key]);
|
||||
},
|
||||
};
|
||||
},
|
||||
@ -1649,15 +1701,15 @@ describe("MatrixClient", function() {
|
||||
rooms.set(roomId, room);
|
||||
return Promise.resolve({ room_id: roomId });
|
||||
};
|
||||
client.getRoom = function(roomId) {
|
||||
client.getRoom = function (roomId) {
|
||||
return rooms.get(roomId);
|
||||
};
|
||||
client.joinRoom = async function(roomId) {
|
||||
client.joinRoom = async function (roomId) {
|
||||
return this.getRoom(roomId)! || this.createRoom({ _roomId: roomId } as ICreateRoomOpts);
|
||||
};
|
||||
|
||||
// Mockup state events
|
||||
client.sendStateEvent = function(roomId, type, content) {
|
||||
client.sendStateEvent = function (roomId, type, content) {
|
||||
const room = this.getRoom(roomId) as WrappedRoom;
|
||||
const state: Map<string, any> = room._state;
|
||||
let store = state.get(type);
|
||||
@ -1667,19 +1719,19 @@ describe("MatrixClient", function() {
|
||||
}
|
||||
const eventId = `$event-${Math.random()}:example.org`;
|
||||
store[eventId] = {
|
||||
getId: function() {
|
||||
getId: function () {
|
||||
return eventId;
|
||||
},
|
||||
getRoomId: function() {
|
||||
getRoomId: function () {
|
||||
return roomId;
|
||||
},
|
||||
getContent: function() {
|
||||
getContent: function () {
|
||||
return content;
|
||||
},
|
||||
};
|
||||
return Promise.resolve({ event_id: eventId });
|
||||
};
|
||||
client.redactEvent = function(roomId, eventId) {
|
||||
client.redactEvent = function (roomId, eventId) {
|
||||
const room = this.getRoom(roomId) as WrappedRoom;
|
||||
const state: Map<string, any> = room._state;
|
||||
for (const store of state.values()) {
|
||||
|
Reference in New Issue
Block a user