1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-07-31 15:24:23 +03:00

Add matrix-org/jest linting (#2973)

This commit is contained in:
Eric Eastwood
2023-02-10 05:05:40 -06:00
committed by GitHub
parent a063ae8ce7
commit c67325ba07
33 changed files with 416 additions and 518 deletions

View File

@ -1,6 +1,6 @@
module.exports = { module.exports = {
plugins: ["matrix-org", "import", "jsdoc"], plugins: ["matrix-org", "import", "jsdoc"],
extends: ["plugin:matrix-org/babel", "plugin:import/typescript"], extends: ["plugin:matrix-org/babel", "plugin:matrix-org/jest", "plugin:import/typescript"],
parserOptions: { parserOptions: {
project: ["./tsconfig.json"], project: ["./tsconfig.json"],
}, },
@ -63,6 +63,23 @@ module.exports = {
], ],
}, },
], ],
// Disabled tests are a reality for now but as soon as all of the xits are
// eliminated, we should enforce this.
"jest/no-disabled-tests": "off",
// TODO: There are many tests with invalid expects that should be fixed,
// https://github.com/matrix-org/matrix-js-sdk/issues/2976
"jest/valid-expect": "off",
// TODO: There are many cases to refactor away,
// https://github.com/matrix-org/matrix-js-sdk/issues/2978
"jest/no-conditional-expect": "off",
// Also treat "oldBackendOnly" as a test function.
// Used in some crypto tests.
"jest/no-standalone-expect": [
"error",
{
additionalTestBlockFunctions: ["beforeAll", "beforeEach", "oldBackendOnly"],
},
],
}, },
overrides: [ overrides: [
{ {

View File

@ -103,8 +103,9 @@
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.5.1", "eslint-import-resolver-typescript": "^3.5.1",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^27.1.6",
"eslint-plugin-jsdoc": "^39.6.4", "eslint-plugin-jsdoc": "^39.6.4",
"eslint-plugin-matrix-org": "^0.10.0", "eslint-plugin-matrix-org": "^1.0.0",
"eslint-plugin-tsdoc": "^0.2.17", "eslint-plugin-tsdoc": "^0.2.17",
"eslint-plugin-unicorn": "^45.0.0", "eslint-plugin-unicorn": "^45.0.0",
"exorcist": "^2.0.0", "exorcist": "^2.0.0",

View File

@ -16,6 +16,9 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// `expect` is allowed in helper functions which are called within `test`/`it` blocks
/* eslint-disable jest/no-standalone-expect */
// load olm before the sdk if possible // load olm before the sdk if possible
import "./olm-loader"; import "./olm-loader";

View File

@ -743,10 +743,8 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm (%s)", (backend: string,
describe("get|setGlobalErrorOnUnknownDevices", () => { describe("get|setGlobalErrorOnUnknownDevices", () => {
it("should raise an error if crypto is disabled", () => { it("should raise an error if crypto is disabled", () => {
aliceTestClient.client["cryptoBackend"] = undefined; aliceTestClient.client["cryptoBackend"] = undefined;
expect(() => aliceTestClient.client.setGlobalErrorOnUnknownDevices(true)).toThrowError( expect(() => aliceTestClient.client.setGlobalErrorOnUnknownDevices(true)).toThrow("encryption disabled");
"encryption disabled", expect(() => aliceTestClient.client.getGlobalErrorOnUnknownDevices()).toThrow("encryption disabled");
);
expect(() => aliceTestClient.client.getGlobalErrorOnUnknownDevices()).toThrowError("encryption disabled");
}); });
oldBackendOnly("should permit sending to unknown devices", async () => { oldBackendOnly("should permit sending to unknown devices", async () => {
@ -799,12 +797,10 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm (%s)", (backend: string,
describe("get|setGlobalBlacklistUnverifiedDevices", () => { describe("get|setGlobalBlacklistUnverifiedDevices", () => {
it("should raise an error if crypto is disabled", () => { it("should raise an error if crypto is disabled", () => {
aliceTestClient.client["cryptoBackend"] = undefined; aliceTestClient.client["cryptoBackend"] = undefined;
expect(() => aliceTestClient.client.setGlobalBlacklistUnverifiedDevices(true)).toThrowError( expect(() => aliceTestClient.client.setGlobalBlacklistUnverifiedDevices(true)).toThrow(
"encryption disabled",
);
expect(() => aliceTestClient.client.getGlobalBlacklistUnverifiedDevices()).toThrowError(
"encryption disabled", "encryption disabled",
); );
expect(() => aliceTestClient.client.getGlobalBlacklistUnverifiedDevices()).toThrow("encryption disabled");
}); });
oldBackendOnly("should disable sending to unverified devices", async () => { oldBackendOnly("should disable sending to unverified devices", async () => {

View File

@ -175,7 +175,7 @@ describe("MatrixClient events", function () {
}); });
}); });
it("should emit User events", function (done) { it("should emit User events", async () => {
httpBackend!.when("GET", "/sync").respond(200, SYNC_DATA); httpBackend!.when("GET", "/sync").respond(200, SYNC_DATA);
httpBackend!.when("GET", "/sync").respond(200, NEXT_SYNC_DATA); httpBackend!.when("GET", "/sync").respond(200, NEXT_SYNC_DATA);
let fired = false; let fired = false;
@ -192,10 +192,8 @@ describe("MatrixClient events", function () {
}); });
client!.startClient(); client!.startClient();
httpBackend!.flushAllExpected().then(function () { await httpBackend!.flushAllExpected();
expect(fired).toBe(true); expect(fired).toBe(true);
done();
});
}); });
it("should emit Room events", function () { it("should emit Room events", function () {

View File

@ -205,19 +205,17 @@ describe("MatrixClient", function () {
describe("getFilter", function () { describe("getFilter", function () {
const filterId = "f1lt3r1d"; const filterId = "f1lt3r1d";
it("should return a filter from the store if allowCached", function (done) { it("should return a filter from the store if allowCached", async () => {
const filter = Filter.fromJson(userId, filterId, { const filter = Filter.fromJson(userId, filterId, {
event_format: "client", event_format: "client",
}); });
store!.storeFilter(filter); store!.storeFilter(filter);
client!.getFilter(userId, filterId, true).then(function (gotFilter) { const gotFilter = await client!.getFilter(userId, filterId, true);
expect(gotFilter).toEqual(filter); expect(gotFilter).toEqual(filter);
done();
});
httpBackend!.verifyNoOutstandingRequests(); httpBackend!.verifyNoOutstandingRequests();
}); });
it("should do an HTTP request if !allowCached even if one exists", function (done) { it("should do an HTTP request if !allowCached even if one exists", async () => {
const httpFilterDefinition = { const httpFilterDefinition = {
event_format: "federation", event_format: "federation",
}; };
@ -230,15 +228,11 @@ describe("MatrixClient", function () {
event_format: "client", event_format: "client",
}); });
store!.storeFilter(storeFilter); store!.storeFilter(storeFilter);
client!.getFilter(userId, filterId, false).then(function (gotFilter) { const [gotFilter] = await Promise.all([client!.getFilter(userId, filterId, false), httpBackend!.flush("")]);
expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition); expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
done();
}); });
httpBackend!.flush(""); it("should do an HTTP request if nothing is in the cache and then store it", async () => {
});
it("should do an HTTP request if nothing is in the cache and then store it", function (done) {
const httpFilterDefinition = { const httpFilterDefinition = {
event_format: "federation", event_format: "federation",
}; };
@ -247,20 +241,16 @@ describe("MatrixClient", function () {
httpBackend! httpBackend!
.when("GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId) .when("GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId)
.respond(200, httpFilterDefinition); .respond(200, httpFilterDefinition);
client!.getFilter(userId, filterId, true).then(function (gotFilter) { const [gotFilter] = await Promise.all([client!.getFilter(userId, filterId, true), httpBackend!.flush("")]);
expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition); expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
expect(store!.getFilter(userId, filterId)).toBeTruthy(); expect(store!.getFilter(userId, filterId)).toBeTruthy();
done();
});
httpBackend!.flush("");
}); });
}); });
describe("createFilter", function () { describe("createFilter", function () {
const filterId = "f1llllllerid"; const filterId = "f1llllllerid";
it("should do an HTTP request and then store the filter", function (done) { it("should do an HTTP request and then store the filter", async () => {
expect(store!.getFilter(userId, filterId)).toBe(null); expect(store!.getFilter(userId, filterId)).toBe(null);
const filterDefinition = { const filterDefinition = {
@ -276,13 +266,9 @@ describe("MatrixClient", function () {
filter_id: filterId, filter_id: filterId,
}); });
client!.createFilter(filterDefinition).then(function (gotFilter) { const [gotFilter] = await Promise.all([client!.createFilter(filterDefinition), httpBackend!.flush("")]);
expect(gotFilter.getDefinition()).toEqual(filterDefinition); expect(gotFilter.getDefinition()).toEqual(filterDefinition);
expect(store!.getFilter(userId, filterId)).toEqual(gotFilter); expect(store!.getFilter(userId, filterId)).toEqual(gotFilter);
done();
});
httpBackend!.flush("");
}); });
}); });

View File

@ -94,16 +94,16 @@ describe("MatrixClient opts", function () {
client.stopClient(); client.stopClient();
}); });
it("should be able to send messages", function (done) { it("should be able to send messages", async () => {
const eventId = "$flibble:wibble"; const eventId = "$flibble:wibble";
httpBackend.when("PUT", "/txn1").respond(200, { httpBackend.when("PUT", "/txn1").respond(200, {
event_id: eventId, event_id: eventId,
}); });
client.sendTextMessage("!foo:bar", "a body", "txn1").then(function (res) { const [res] = await Promise.all([
client.sendTextMessage("!foo:bar", "a body", "txn1"),
httpBackend.flush("/txn1", 1),
]);
expect(res.event_id).toEqual(eventId); expect(res.event_id).toEqual(eventId);
done();
});
httpBackend.flush("/txn1", 1);
}); });
it("should be able to sync / get new events", async function () { it("should be able to sync / get new events", async function () {
@ -149,7 +149,7 @@ describe("MatrixClient opts", function () {
client.stopClient(); client.stopClient();
}); });
it("shouldn't retry sending events", function (done) { it("shouldn't retry sending events", async () => {
httpBackend.when("PUT", "/txn1").respond( httpBackend.when("PUT", "/txn1").respond(
500, 500,
new MatrixError({ new MatrixError({
@ -157,19 +157,17 @@ describe("MatrixClient opts", function () {
error: "Ruh roh", error: "Ruh roh",
}), }),
); );
client.sendTextMessage("!foo:bar", "a body", "txn1").then( try {
function (res) { await Promise.all([
expect(false).toBe(true); expect(client.sendTextMessage("!foo:bar", "a body", "txn1")).rejects.toThrow(),
}, httpBackend.flush("/txn1", 1),
function (err) { ]);
expect(err.errcode).toEqual("M_SOMETHING"); } catch (err) {
done(); expect((<MatrixError>err).errcode).toEqual("M_SOMETHING");
}, }
);
httpBackend.flush("/txn1", 1);
}); });
it("shouldn't queue events", function (done) { it("shouldn't queue events", async () => {
httpBackend.when("PUT", "/txn1").respond(200, { httpBackend.when("PUT", "/txn1").respond(200, {
event_id: "AAA", event_id: "AAA",
}); });
@ -178,30 +176,38 @@ describe("MatrixClient opts", function () {
}); });
let sentA = false; let sentA = false;
let sentB = false; let sentB = false;
client.sendTextMessage("!foo:bar", "a body", "txn1").then(function (res) { const messageASendPromise = client.sendTextMessage("!foo:bar", "a body", "txn1").then(function (res) {
sentA = true; sentA = true;
// We expect messageB to be sent before messageA to ensure as we're
// testing that there is no queueing that blocks each other
expect(sentB).toBe(true); expect(sentB).toBe(true);
}); });
client.sendTextMessage("!foo:bar", "b body", "txn2").then(function (res) { const messageBSendPromise = client.sendTextMessage("!foo:bar", "b body", "txn2").then(function (res) {
sentB = true; sentB = true;
// We expect messageB to be sent before messageA to ensure as we're
// testing that there is no queueing that blocks each other
expect(sentA).toBe(false); expect(sentA).toBe(false);
}); });
httpBackend.flush("/txn2", 1).then(function () { // Allow messageB to succeed first
httpBackend.flush("/txn1", 1).then(function () { await httpBackend.flush("/txn2", 1);
done(); // Then allow messageA to succeed
}); await httpBackend.flush("/txn1", 1);
});
// Now await the message send promises to
await messageBSendPromise;
await messageASendPromise;
}); });
it("should be able to send messages", function (done) { it("should be able to send messages", async () => {
httpBackend.when("PUT", "/txn1").respond(200, { httpBackend.when("PUT", "/txn1").respond(200, {
event_id: "foo", event_id: "foo",
}); });
client.sendTextMessage("!foo:bar", "a body", "txn1").then(function (res) { const [res] = await Promise.all([
client.sendTextMessage("!foo:bar", "a body", "txn1"),
httpBackend.flush("/txn1", 1),
]);
expect(res.event_id).toEqual("foo"); expect(res.event_id).toEqual("foo");
done();
});
httpBackend.flush("/txn1", 1);
}); });
}); });
}); });

View File

@ -48,13 +48,13 @@ describe("MatrixClient retrying", function () {
return httpBackend!.stop(); return httpBackend!.stop();
}); });
xit("should retry according to MatrixScheduler.retryFn", function () {}); it.skip("should retry according to MatrixScheduler.retryFn", function () {});
xit("should queue according to MatrixScheduler.queueFn", function () {}); it.skip("should queue according to MatrixScheduler.queueFn", function () {});
xit("should mark events as EventStatus.NOT_SENT when giving up", function () {}); it.skip("should mark events as EventStatus.NOT_SENT when giving up", function () {});
xit("should mark events as EventStatus.QUEUED when queued", function () {}); it.skip("should mark events as EventStatus.QUEUED when queued", function () {});
it("should mark events as EventStatus.CANCELLED when cancelled", function () { it("should mark events as EventStatus.CANCELLED when cancelled", function () {
// send a couple of events; the second will be queued // send a couple of events; the second will be queued
@ -130,7 +130,7 @@ describe("MatrixClient retrying", function () {
}); });
describe("resending", function () { describe("resending", function () {
xit("should be able to resend a NOT_SENT event", function () {}); it.skip("should be able to resend a NOT_SENT event", function () {});
xit("should be able to resend a sent event", function () {}); it.skip("should be able to resend a sent event", function () {});
}); });
}); });

View File

@ -163,8 +163,9 @@ describe("MatrixClient room timelines", function () {
it( it(
"should be added immediately after calling MatrixClient.sendEvent " + "should be added immediately after calling MatrixClient.sendEvent " +
"with EventStatus.SENDING and the right event.sender", "with EventStatus.SENDING and the right event.sender",
function (done) { async () => {
client!.on(ClientEvent.Sync, function (state) { const wasMessageAddedPromise = new Promise((resolve) => {
client!.on(ClientEvent.Sync, async (state) => {
if (state !== "PREPARED") { if (state !== "PREPARED") {
return; return;
} }
@ -181,18 +182,19 @@ describe("MatrixClient room timelines", function () {
expect(member?.userId).toEqual(userId); expect(member?.userId).toEqual(userId);
expect(member?.name).toEqual(userName); expect(member?.name).toEqual(userName);
httpBackend!.flush("/sync", 1).then(function () { await httpBackend!.flush("/sync", 1);
done(); resolve(null);
}); });
}); });
httpBackend!.flush("/sync", 1); await httpBackend!.flush("/sync", 1);
await wasMessageAddedPromise;
}, },
); );
it( it(
"should be updated correctly when the send request finishes " + "should be updated correctly when the send request finishes " +
"BEFORE the event comes down the event stream", "BEFORE the event comes down the event stream",
function (done) { async () => {
const eventId = "$foo:bar"; const eventId = "$foo:bar";
httpBackend!.when("PUT", "/txn1").respond(200, { httpBackend!.when("PUT", "/txn1").respond(200, {
event_id: eventId, event_id: eventId,
@ -207,28 +209,30 @@ describe("MatrixClient room timelines", function () {
ev.unsigned = { transaction_id: "txn1" }; ev.unsigned = { transaction_id: "txn1" };
setNextSyncData([ev]); setNextSyncData([ev]);
const wasMessageAddedPromise = new Promise((resolve) => {
client!.on(ClientEvent.Sync, function (state) { client!.on(ClientEvent.Sync, function (state) {
if (state !== "PREPARED") { if (state !== "PREPARED") {
return; return;
} }
const room = client!.getRoom(roomId)!; const room = client!.getRoom(roomId)!;
client!.sendTextMessage(roomId, "I am a fish", "txn1").then(function () { client!.sendTextMessage(roomId, "I am a fish", "txn1").then(async () => {
expect(room.timeline[1].getId()).toEqual(eventId); expect(room.timeline[1].getId()).toEqual(eventId);
httpBackend!.flush("/sync", 1).then(function () { await httpBackend!.flush("/sync", 1);
expect(room.timeline[1].getId()).toEqual(eventId); expect(room.timeline[1].getId()).toEqual(eventId);
done(); resolve(null);
});
}); });
httpBackend!.flush("/txn1", 1); httpBackend!.flush("/txn1", 1);
}); });
httpBackend!.flush("/sync", 1); });
await httpBackend!.flush("/sync", 1);
await wasMessageAddedPromise;
}, },
); );
it( it(
"should be updated correctly when the send request finishes " + "should be updated correctly when the send request finishes " +
"AFTER the event comes down the event stream", "AFTER the event comes down the event stream",
function (done) { async () => {
const eventId = "$foo:bar"; const eventId = "$foo:bar";
httpBackend!.when("PUT", "/txn1").respond(200, { httpBackend!.when("PUT", "/txn1").respond(200, {
event_id: eventId, event_id: eventId,
@ -243,23 +247,24 @@ describe("MatrixClient room timelines", function () {
ev.unsigned = { transaction_id: "txn1" }; ev.unsigned = { transaction_id: "txn1" };
setNextSyncData([ev]); setNextSyncData([ev]);
client!.on(ClientEvent.Sync, function (state) { const wasMessageAddedPromise = new Promise((resolve) => {
client!.on(ClientEvent.Sync, async (state) => {
if (state !== "PREPARED") { if (state !== "PREPARED") {
return; return;
} }
const room = client!.getRoom(roomId)!; const room = client!.getRoom(roomId)!;
const promise = client!.sendTextMessage(roomId, "I am a fish", "txn1"); const messageSendPromise = client!.sendTextMessage(roomId, "I am a fish", "txn1");
httpBackend!.flush("/sync", 1).then(function () { await httpBackend!.flush("/sync", 1);
expect(room.timeline.length).toEqual(2); expect(room.timeline.length).toEqual(2);
httpBackend!.flush("/txn1", 1); httpBackend!.flush("/txn1", 1);
promise.then(function () { await messageSendPromise;
expect(room.timeline.length).toEqual(2); expect(room.timeline.length).toEqual(2);
expect(room.timeline[1].getId()).toEqual(eventId); expect(room.timeline[1].getId()).toEqual(eventId);
done(); resolve(null);
}); });
}); });
}); await httpBackend!.flush("/sync", 1);
httpBackend!.flush("/sync", 1); await wasMessageAddedPromise;
}, },
); );
}); });
@ -279,30 +284,29 @@ describe("MatrixClient room timelines", function () {
}); });
}); });
it("should set Room.oldState.paginationToken to null at the start" + " of the timeline.", function (done) { it("should set Room.oldState.paginationToken to null at the start of the timeline.", async () => {
client!.on(ClientEvent.Sync, function (state) { const didPaginatePromise = new Promise((resolve) => {
client!.on(ClientEvent.Sync, async (state) => {
if (state !== "PREPARED") { if (state !== "PREPARED") {
return; return;
} }
const room = client!.getRoom(roomId)!; const room = client!.getRoom(roomId)!;
expect(room.timeline.length).toEqual(1); expect(room.timeline.length).toEqual(1);
client!.scrollback(room).then(function () { await Promise.all([client!.scrollback(room), httpBackend!.flush("/messages", 1)]);
expect(room.timeline.length).toEqual(1); expect(room.timeline.length).toEqual(1);
expect(room.oldState.paginationToken).toBe(null); expect(room.oldState.paginationToken).toBe(null);
// still have a sync to flush // still have a sync to flush
httpBackend!.flush("/sync", 1).then(() => { await httpBackend!.flush("/sync", 1);
done(); resolve(null);
}); });
}); });
await httpBackend!.flush("/sync", 1);
await didPaginatePromise;
});
httpBackend!.flush("/messages", 1); it("should set the right event.sender values", async () => {
});
httpBackend!.flush("/sync", 1);
});
it("should set the right event.sender values", function (done) {
// We're aiming for an eventual timeline of: // We're aiming for an eventual timeline of:
// //
// 'Old Alice' joined the room // 'Old Alice' joined the room
@ -353,7 +357,8 @@ describe("MatrixClient room timelines", function () {
joinMshipEvent, joinMshipEvent,
]; ];
client!.on(ClientEvent.Sync, function (state) { const didPaginatePromise = new Promise((resolve) => {
client!.on(ClientEvent.Sync, async (state) => {
if (state !== "PREPARED") { if (state !== "PREPARED") {
return; return;
} }
@ -361,7 +366,8 @@ describe("MatrixClient room timelines", function () {
// sync response // sync response
expect(room.timeline.length).toEqual(1); expect(room.timeline.length).toEqual(1);
client!.scrollback(room).then(function () { await Promise.all([client!.scrollback(room), httpBackend!.flush("/messages", 1)]);
expect(room.timeline.length).toEqual(5); expect(room.timeline.length).toEqual(5);
const joinMsg = room.timeline[0]; const joinMsg = room.timeline[0];
expect(joinMsg.sender?.name).toEqual("Old Alice"); expect(joinMsg.sender?.name).toEqual("Old Alice");
@ -371,17 +377,15 @@ describe("MatrixClient room timelines", function () {
expect(newMsg.sender?.name).toEqual(userName); expect(newMsg.sender?.name).toEqual(userName);
// still have a sync to flush // still have a sync to flush
httpBackend!.flush("/sync", 1).then(() => { await httpBackend!.flush("/sync", 1);
done(); resolve(null);
}); });
}); });
await httpBackend!.flush("/sync", 1);
await didPaginatePromise;
});
httpBackend!.flush("/messages", 1); it("should add it them to the right place in the timeline", async () => {
});
httpBackend!.flush("/sync", 1);
});
it("should add it them to the right place in the timeline", function (done) {
// set the list of events to return on scrollback // set the list of events to return on scrollback
sbEvents = [ sbEvents = [
utils.mkMessage({ utils.mkMessage({
@ -396,30 +400,30 @@ describe("MatrixClient room timelines", function () {
}), }),
]; ];
client!.on(ClientEvent.Sync, function (state) { const didPaginatePromise = new Promise((resolve) => {
client!.on(ClientEvent.Sync, async (state) => {
if (state !== "PREPARED") { if (state !== "PREPARED") {
return; return;
} }
const room = client!.getRoom(roomId)!; const room = client!.getRoom(roomId)!;
expect(room.timeline.length).toEqual(1); expect(room.timeline.length).toEqual(1);
client!.scrollback(room).then(function () { await Promise.all([client!.scrollback(room), httpBackend!.flush("/messages", 1)]);
expect(room.timeline.length).toEqual(3); expect(room.timeline.length).toEqual(3);
expect(room.timeline[0].event).toEqual(sbEvents[1]); expect(room.timeline[0].event).toEqual(sbEvents[1]);
expect(room.timeline[1].event).toEqual(sbEvents[0]); expect(room.timeline[1].event).toEqual(sbEvents[0]);
// still have a sync to flush // still have a sync to flush
httpBackend!.flush("/sync", 1).then(() => { await httpBackend!.flush("/sync", 1);
done(); resolve(null);
}); });
}); });
await httpBackend!.flush("/sync", 1);
await didPaginatePromise;
});
httpBackend!.flush("/messages", 1); it("should use 'end' as the next pagination token", async () => {
});
httpBackend!.flush("/sync", 1);
});
it("should use 'end' as the next pagination token", function (done) {
// set the list of events to return on scrollback // set the list of events to return on scrollback
sbEvents = [ sbEvents = [
utils.mkMessage({ utils.mkMessage({
@ -429,25 +433,24 @@ describe("MatrixClient room timelines", function () {
}), }),
]; ];
client!.on(ClientEvent.Sync, function (state) { const didPaginatePromise = new Promise((resolve) => {
client!.on(ClientEvent.Sync, async (state) => {
if (state !== "PREPARED") { if (state !== "PREPARED") {
return; return;
} }
const room = client!.getRoom(roomId)!; const room = client!.getRoom(roomId)!;
expect(room.oldState.paginationToken).toBeTruthy(); expect(room.oldState.paginationToken).toBeTruthy();
client!.scrollback(room, 1).then(function () { await Promise.all([client!.scrollback(room, 1), httpBackend!.flush("/messages", 1)]);
expect(room.oldState.paginationToken).toEqual(sbEndTok); expect(room.oldState.paginationToken).toEqual(sbEndTok);
});
httpBackend!.flush("/messages", 1).then(function () {
// still have a sync to flush // still have a sync to flush
httpBackend!.flush("/sync", 1).then(() => { await httpBackend!.flush("/sync", 1);
done(); resolve(null);
}); });
}); });
}); await httpBackend!.flush("/sync", 1);
httpBackend!.flush("/sync", 1); await didPaginatePromise;
}); });
}); });

View File

@ -81,17 +81,15 @@ describe("MatrixClient syncing", () => {
presence: {}, presence: {},
}; };
it("should /sync after /pushrules and /filter.", (done) => { it("should /sync after /pushrules and /filter.", async () => {
httpBackend!.when("GET", "/sync").respond(200, syncData); httpBackend!.when("GET", "/sync").respond(200, syncData);
client!.startClient(); client!.startClient();
httpBackend!.flushAllExpected().then(() => { await httpBackend!.flushAllExpected();
done();
});
}); });
it("should pass the 'next_batch' token from /sync to the since= param of the next /sync", (done) => { it("should pass the 'next_batch' token from /sync to the since= param of the next /sync", async () => {
httpBackend!.when("GET", "/sync").respond(200, syncData); httpBackend!.when("GET", "/sync").respond(200, syncData);
httpBackend! httpBackend!
.when("GET", "/sync") .when("GET", "/sync")
@ -102,9 +100,7 @@ describe("MatrixClient syncing", () => {
client!.startClient(); client!.startClient();
httpBackend!.flushAllExpected().then(() => { await httpBackend!.flushAllExpected();
done();
});
}); });
it("should emit RoomEvent.MyMembership for invite->leave->invite cycles", async () => { it("should emit RoomEvent.MyMembership for invite->leave->invite cycles", async () => {
@ -724,7 +720,7 @@ describe("MatrixClient syncing", () => {
// events that arrive in the incremental sync as if they preceeded the // events that arrive in the incremental sync as if they preceeded the
// timeline events, however this breaks peeking, so it's disabled // timeline events, however this breaks peeking, so it's disabled
// (see sync.js) // (see sync.js)
xit("should correctly interpret state in incremental sync.", () => { it.skip("should correctly interpret state in incremental sync.", () => {
httpBackend!.when("GET", "/sync").respond(200, syncData); httpBackend!.when("GET", "/sync").respond(200, syncData);
httpBackend!.when("GET", "/sync").respond(200, nextSyncData); httpBackend!.when("GET", "/sync").respond(200, nextSyncData);
@ -741,9 +737,9 @@ describe("MatrixClient syncing", () => {
}); });
}); });
xit("should update power levels for users in a room", () => {}); it.skip("should update power levels for users in a room", () => {});
xit("should update the room topic", () => {}); it.skip("should update the room topic", () => {});
describe("onMarkerStateEvent", () => { describe("onMarkerStateEvent", () => {
const normalMessageEvent = utils.mkMessage({ const normalMessageEvent = utils.mkMessage({
@ -840,6 +836,7 @@ describe("MatrixClient syncing", () => {
roomVersion: "org.matrix.msc2716v3", roomVersion: "org.matrix.msc2716v3",
}, },
].forEach((testMeta) => { ].forEach((testMeta) => {
// eslint-disable-next-line jest/valid-title
describe(testMeta.label, () => { describe(testMeta.label, () => {
const roomCreateEvent = utils.mkEvent({ const roomCreateEvent = utils.mkEvent({
type: "m.room.create", type: "m.room.create",
@ -1592,27 +1589,24 @@ describe("MatrixClient syncing", () => {
}); });
describe("of a room", () => { describe("of a room", () => {
xit( it.skip(
"should sync when a join event (which changes state) for the user" + "should sync when a join event (which changes state) for the user" +
" arrives down the event stream (e.g. join from another device)", " arrives down the event stream (e.g. join from another device)",
() => {}, () => {},
); );
xit("should sync when the user explicitly calls joinRoom", () => {}); it.skip("should sync when the user explicitly calls joinRoom", () => {});
}); });
describe("syncLeftRooms", () => { describe("syncLeftRooms", () => {
beforeEach((done) => { beforeEach(async () => {
client!.startClient(); client!.startClient();
httpBackend!.flushAllExpected().then(() => { await httpBackend!.flushAllExpected();
// the /sync call from syncLeftRooms ends up in the request // the /sync call from syncLeftRooms ends up in the request
// queue behind the call from the running client; add a response // queue behind the call from the running client; add a response
// to flush the client's one out. // to flush the client's one out.
httpBackend!.when("GET", "/sync").respond(200, {}); await httpBackend!.when("GET", "/sync").respond(200, {});
done();
});
}); });
it("should create and use an appropriate filter", () => { it("should create and use an appropriate filter", () => {

View File

@ -153,11 +153,11 @@ describe("SlidingSyncSdk", () => {
const hasSynced = sdk!.sync(); const hasSynced = sdk!.sync();
await httpBackend!.flushAllExpected(); await httpBackend!.flushAllExpected();
await hasSynced; await hasSynced;
expect(mockSlidingSync!.start).toBeCalled(); expect(mockSlidingSync!.start).toHaveBeenCalled();
}); });
it("can stop()", async () => { it("can stop()", async () => {
sdk!.stop(); sdk!.stop();
expect(mockSlidingSync!.stop).toBeCalled(); expect(mockSlidingSync!.stop).toHaveBeenCalled();
}); });
}); });
@ -584,7 +584,7 @@ describe("SlidingSyncSdk", () => {
}); });
it("emits SyncState.Error immediately when receiving M_UNKNOWN_TOKEN and stops syncing", async () => { it("emits SyncState.Error immediately when receiving M_UNKNOWN_TOKEN and stops syncing", async () => {
expect(mockSlidingSync!.stop).not.toBeCalled(); expect(mockSlidingSync!.stop).not.toHaveBeenCalled();
mockSlidingSync!.emit( mockSlidingSync!.emit(
SlidingSyncEvent.Lifecycle, SlidingSyncEvent.Lifecycle,
SlidingSyncState.RequestFinished, SlidingSyncState.RequestFinished,
@ -595,7 +595,7 @@ describe("SlidingSyncSdk", () => {
}), }),
); );
expect(sdk!.getSyncState()).toEqual(SyncState.Error); expect(sdk!.getSyncState()).toEqual(SyncState.Error);
expect(mockSlidingSync!.stop).toBeCalled(); expect(mockSlidingSync!.stop).toHaveBeenCalled();
}); });
}); });

View File

@ -5,6 +5,7 @@ import { getMockClientWithEventEmitter } from "../test-utils/client";
import { StubStore } from "../../src/store/stub"; import { StubStore } from "../../src/store/stub";
import { IndexedToDeviceBatch } from "../../src/models/ToDeviceMessage"; import { IndexedToDeviceBatch } from "../../src/models/ToDeviceMessage";
import { SyncState } from "../../src/sync"; import { SyncState } from "../../src/sync";
import { defer } from "../../src/utils";
describe("onResumedSync", () => { describe("onResumedSync", () => {
let batch: IndexedToDeviceBatch | null; let batch: IndexedToDeviceBatch | null;
@ -58,7 +59,9 @@ describe("onResumedSync", () => {
queue = new ToDeviceMessageQueue(mockClient); queue = new ToDeviceMessageQueue(mockClient);
}); });
it("resends queue after connectivity restored", (done) => { it("resends queue after connectivity restored", async () => {
const deferred = defer();
onSendToDeviceFailure = () => { onSendToDeviceFailure = () => {
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1); expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
expect(store.removeToDeviceBatch).not.toHaveBeenCalled(); expect(store.removeToDeviceBatch).not.toHaveBeenCalled();
@ -70,26 +73,32 @@ describe("onResumedSync", () => {
onSendToDeviceSuccess = () => { onSendToDeviceSuccess = () => {
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(3); expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(3);
expect(store.removeToDeviceBatch).toHaveBeenCalled(); expect(store.removeToDeviceBatch).toHaveBeenCalled();
done(); deferred.resolve();
}; };
queue.start(); queue.start();
return deferred.promise;
}); });
it("does not resend queue if client sync still catching up", (done) => { it("does not resend queue if client sync still catching up", async () => {
const deferred = defer();
onSendToDeviceFailure = () => { onSendToDeviceFailure = () => {
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1); expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
expect(store.removeToDeviceBatch).not.toHaveBeenCalled(); expect(store.removeToDeviceBatch).not.toHaveBeenCalled();
resumeSync(SyncState.Catchup, SyncState.Catchup); resumeSync(SyncState.Catchup, SyncState.Catchup);
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1); expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
done(); deferred.resolve();
}; };
queue.start(); queue.start();
return deferred.promise;
}); });
it("does not resend queue if connectivity restored after queue stopped", (done) => { it("does not resend queue if connectivity restored after queue stopped", async () => {
const deferred = defer();
onSendToDeviceFailure = () => { onSendToDeviceFailure = () => {
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1); expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
expect(store.removeToDeviceBatch).not.toHaveBeenCalled(); expect(store.removeToDeviceBatch).not.toHaveBeenCalled();
@ -98,9 +107,10 @@ describe("onResumedSync", () => {
resumeSync(SyncState.Syncing, SyncState.Catchup); resumeSync(SyncState.Syncing, SyncState.Catchup);
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1); expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
done(); deferred.resolve();
}; };
queue.start(); queue.start();
return deferred.promise;
}); });
}); });

View File

@ -550,7 +550,7 @@ describe("Crypto", function () {
aliceClient.crypto!.outgoingRoomKeyRequestManager.sendQueuedRequests(); aliceClient.crypto!.outgoingRoomKeyRequestManager.sendQueuedRequests();
jest.runAllTimers(); jest.runAllTimers();
await Promise.resolve(); await Promise.resolve();
expect(aliceSendToDevice).toBeCalledTimes(1); expect(aliceSendToDevice).toHaveBeenCalledTimes(1);
const txnId = aliceSendToDevice.mock.calls[0][2]; const txnId = aliceSendToDevice.mock.calls[0][2];
// give the room key request manager time to update the state // give the room key request manager time to update the state
@ -564,7 +564,7 @@ describe("Crypto", function () {
// cancelAndResend will call sendToDevice twice: // cancelAndResend will call sendToDevice twice:
// the first call to sendToDevice will be the cancellation // the first call to sendToDevice will be the cancellation
// the second call to sendToDevice will be the key request // the second call to sendToDevice will be the key request
expect(aliceSendToDevice).toBeCalledTimes(3); expect(aliceSendToDevice).toHaveBeenCalledTimes(3);
expect(aliceSendToDevice.mock.calls[2][2]).not.toBe(txnId); expect(aliceSendToDevice.mock.calls[2][2]).not.toBe(txnId);
}); });

View File

@ -148,6 +148,10 @@ describe("DeviceList", function () {
dl.invalidateUserDeviceList("@test1:sw1v.org"); dl.invalidateUserDeviceList("@test1:sw1v.org");
dl.refreshOutdatedDeviceLists(); dl.refreshOutdatedDeviceLists();
// TODO: Fix this test so we actually await the call and assertions and remove
// the eslint disable, https://github.com/matrix-org/matrix-js-sdk/issues/2977
//
// eslint-disable-next-line jest/valid-expect-in-promise
dl.saveIfDirty() dl.saveIfDirty()
.then(() => { .then(() => {
// the first request completes // the first request completes
@ -196,7 +200,7 @@ describe("DeviceList", function () {
downloadSpy.mockReturnValueOnce(queryDefer2.promise); downloadSpy.mockReturnValueOnce(queryDefer2.promise);
const prom1 = dl.refreshOutdatedDeviceLists(); const prom1 = dl.refreshOutdatedDeviceLists();
expect(downloadSpy).toBeCalledTimes(2); expect(downloadSpy).toHaveBeenCalledTimes(2);
expect(downloadSpy).toHaveBeenNthCalledWith(1, ["@test1:sw1v.org"], {}); expect(downloadSpy).toHaveBeenNthCalledWith(1, ["@test1:sw1v.org"], {});
expect(downloadSpy).toHaveBeenNthCalledWith(2, ["@test2:sw1v.org"], {}); expect(downloadSpy).toHaveBeenNthCalledWith(2, ["@test2:sw1v.org"], {});
queryDefer1.resolve(utils.deepCopy(signedDeviceList)); queryDefer1.resolve(utils.deepCopy(signedDeviceList));

View File

@ -211,7 +211,7 @@ describe("MegolmDecryption", function () {
.then(() => { .then(() => {
// check that it called encryptMessageForDevice with // check that it called encryptMessageForDevice with
// appropriate args. // appropriate args.
expect(mockOlmLib.encryptMessageForDevice).toBeCalledTimes(1); expect(mockOlmLib.encryptMessageForDevice).toHaveBeenCalledTimes(1);
const call = mockOlmLib.encryptMessageForDevice.mock.calls[0]; const call = mockOlmLib.encryptMessageForDevice.mock.calls[0];
const payload = call[6]; const payload = call[6];

View File

@ -1148,6 +1148,6 @@ describe("userHasCrossSigningKeys", function () {
it("throws an error if crypto is disabled", () => { it("throws an error if crypto is disabled", () => {
aliceClient["cryptoBackend"] = undefined; aliceClient["cryptoBackend"] = undefined;
expect(() => aliceClient.userHasCrossSigningKeys()).toThrowError("encryption disabled"); expect(() => aliceClient.userHasCrossSigningKeys()).toThrow("encryption disabled");
}); });
}); });

View File

@ -179,7 +179,7 @@ describe("EventTimelineSet", () => {
eventTimelineSet.addEventToTimeline(messageEvent, liveTimeline2, { eventTimelineSet.addEventToTimeline(messageEvent, liveTimeline2, {
toStartOfTimeline: true, toStartOfTimeline: true,
}); });
}).toThrowError(); }).toThrow();
}); });
it("should not add a threaded reply to the main room timeline", () => { it("should not add a threaded reply to the main room timeline", () => {
@ -399,7 +399,7 @@ describe("EventTimelineSet", () => {
it("should throw if timeline set has no room", () => { it("should throw if timeline set has no room", () => {
const eventTimelineSet = new EventTimelineSet(undefined, {}, client); const eventTimelineSet = new EventTimelineSet(undefined, {}, client);
expect(() => eventTimelineSet.canContain(messageEvent)).toThrowError(); expect(() => eventTimelineSet.canContain(messageEvent)).toThrow();
}); });
it("should return false if timeline set is for thread but event is not threaded", () => { it("should return false if timeline set is for thread but event is not threaded", () => {

View File

@ -150,26 +150,6 @@ describe("PollResponseEvent", () => {
expect(response.spoiled).toBe(true); expect(response.spoiled).toBe(true);
}); });
it("should spoil the vote when answers are empty", () => {
const input: IPartialEvent<PollResponseEventContent> = {
type: M_POLL_RESPONSE.name,
content: {
"m.relates_to": {
rel_type: REFERENCE_RELATION.name,
event_id: "$poll",
},
[M_POLL_RESPONSE.name]: {
answers: [],
},
},
};
const response = new PollResponseEvent(input);
expect(response.spoiled).toBe(true);
response.validateAgainst(SAMPLE_POLL);
expect(response.spoiled).toBe(true);
});
it("should spoil the vote when answers are not strings", () => { it("should spoil the vote when answers are not strings", () => {
const input: IPartialEvent<PollResponseEventContent> = { const input: IPartialEvent<PollResponseEventContent> = {
type: M_POLL_RESPONSE.name, type: M_POLL_RESPONSE.name,

View File

@ -78,8 +78,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth(); const res = await ia.attemptAuth();
expect(res).toBe(requestRes); expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(1); expect(doRequest).toHaveBeenCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(1); expect(stateUpdated).toHaveBeenCalledTimes(1);
}); });
it("should handle auth errcode presence", async () => { it("should handle auth errcode presence", async () => {
@ -128,8 +128,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth(); const res = await ia.attemptAuth();
expect(res).toBe(requestRes); expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(1); expect(doRequest).toHaveBeenCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(1); expect(stateUpdated).toHaveBeenCalledTimes(1);
}); });
it("should handle set emailSid for email flow", async () => { it("should handle set emailSid for email flow", async () => {
@ -180,9 +180,9 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth(); const res = await ia.attemptAuth();
expect(res).toBe(requestRes); expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(1); expect(doRequest).toHaveBeenCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(1); expect(stateUpdated).toHaveBeenCalledTimes(1);
expect(requestEmailToken).toBeCalledTimes(0); expect(requestEmailToken).toHaveBeenCalledTimes(0);
expect(ia.getEmailSid()).toBe("myEmailSid"); expect(ia.getEmailSid()).toBe("myEmailSid");
}); });
@ -244,8 +244,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth(); const res = await ia.attemptAuth();
expect(res).toBe(requestRes); expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(2); expect(doRequest).toHaveBeenCalledTimes(2);
expect(stateUpdated).toBeCalledTimes(1); expect(stateUpdated).toHaveBeenCalledTimes(1);
}); });
it("should make a request if authdata is null", async () => { it("should make a request if authdata is null", async () => {
@ -306,8 +306,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth(); const res = await ia.attemptAuth();
expect(res).toBe(requestRes); expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(2); expect(doRequest).toHaveBeenCalledTimes(2);
expect(stateUpdated).toBeCalledTimes(1); expect(stateUpdated).toHaveBeenCalledTimes(1);
}); });
it("should start an auth stage and reject if no auth flow", async () => { it("should start an auth stage and reject if no auth flow", async () => {
@ -430,8 +430,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth(); const res = await ia.attemptAuth();
expect(res).toBe(requestRes); expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(1); expect(doRequest).toHaveBeenCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(0); expect(stateUpdated).toHaveBeenCalledTimes(0);
}); });
describe("requestEmailToken", () => { describe("requestEmailToken", () => {
@ -464,35 +464,6 @@ describe("InteractiveAuth", () => {
expect(requestEmailToken).toHaveBeenLastCalledWith(undefined, ia.getClientSecret(), 5, undefined); expect(requestEmailToken).toHaveBeenLastCalledWith(undefined, ia.getClientSecret(), 5, undefined);
}); });
it("increases auth attempts", async () => {
const doRequest = jest.fn();
const stateUpdated = jest.fn();
const requestEmailToken = jest.fn();
requestEmailToken.mockImplementation(async () => ({ sid: "" }));
const ia = new InteractiveAuth({
matrixClient: getFakeClient(),
doRequest,
stateUpdated,
requestEmailToken,
});
await ia.requestEmailToken();
expect(requestEmailToken).toHaveBeenLastCalledWith(undefined, ia.getClientSecret(), 1, undefined);
requestEmailToken.mockClear();
await ia.requestEmailToken();
expect(requestEmailToken).toHaveBeenLastCalledWith(undefined, ia.getClientSecret(), 2, undefined);
requestEmailToken.mockClear();
await ia.requestEmailToken();
expect(requestEmailToken).toHaveBeenLastCalledWith(undefined, ia.getClientSecret(), 3, undefined);
requestEmailToken.mockClear();
await ia.requestEmailToken();
expect(requestEmailToken).toHaveBeenLastCalledWith(undefined, ia.getClientSecret(), 4, undefined);
requestEmailToken.mockClear();
await ia.requestEmailToken();
expect(requestEmailToken).toHaveBeenLastCalledWith(undefined, ia.getClientSecret(), 5, undefined);
});
it("passes errors through", async () => { it("passes errors through", async () => {
const doRequest = jest.fn(); const doRequest = jest.fn();
const stateUpdated = jest.fn(); const stateUpdated = jest.fn();
@ -508,7 +479,7 @@ describe("InteractiveAuth", () => {
requestEmailToken, requestEmailToken,
}); });
await expect(ia.requestEmailToken.bind(ia)).rejects.toThrowError("unspecific network error"); await expect(ia.requestEmailToken.bind(ia)).rejects.toThrow("unspecific network error");
}); });
it("only starts one request at a time", async () => { it("only starts one request at a time", async () => {

View File

@ -893,7 +893,7 @@ describe("MatrixClient", function () {
describe("getOrCreateFilter", function () { describe("getOrCreateFilter", function () {
it("should POST createFilter if no id is present in localStorage", 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 use an existing filter if id is present in localStorage", function () {});
it("should handle localStorage filterId missing from the server", function (done) { it("should handle localStorage filterId missing from the server", async () => {
function getFilterName(userId: string, suffix?: string) { function getFilterName(userId: string, suffix?: string) {
// scope this on the user ID because people may login on many accounts // scope this on the user ID because people may login on many accounts
// and they all need to be stored! // and they all need to be stored!
@ -919,10 +919,8 @@ describe("MatrixClient", function () {
client.store.setFilterIdByName(filterName, invalidFilterId); client.store.setFilterIdByName(filterName, invalidFilterId);
const filter = new Filter(client.credentials.userId); const filter = new Filter(client.credentials.userId);
client.getOrCreateFilter(filterName, filter).then(function (filterId) { const filterId = await client.getOrCreateFilter(filterName, filter);
expect(filterId).toEqual(FILTER_RESPONSE.data?.filter_id); expect(filterId).toEqual(FILTER_RESPONSE.data?.filter_id);
done();
});
}); });
}); });
@ -933,7 +931,7 @@ describe("MatrixClient", function () {
expect(client.retryImmediately()).toBe(false); expect(client.retryImmediately()).toBe(false);
}); });
it("should work on /filter", function (done) { it("should work on /filter", async () => {
httpLookups = []; httpLookups = [];
httpLookups.push(PUSH_RULES_RESPONSE); httpLookups.push(PUSH_RULES_RESPONSE);
httpLookups.push({ httpLookups.push({
@ -944,6 +942,7 @@ describe("MatrixClient", function () {
httpLookups.push(FILTER_RESPONSE); httpLookups.push(FILTER_RESPONSE);
httpLookups.push(SYNC_RESPONSE); httpLookups.push(SYNC_RESPONSE);
const wasPreparedPromise = new Promise((resolve) => {
client.on(ClientEvent.Sync, function syncListener(state) { client.on(ClientEvent.Sync, function syncListener(state) {
if (state === "ERROR" && httpLookups.length > 0) { if (state === "ERROR" && httpLookups.length > 0) {
expect(httpLookups.length).toEqual(2); expect(httpLookups.length).toEqual(2);
@ -951,16 +950,18 @@ describe("MatrixClient", function () {
jest.advanceTimersByTime(1); jest.advanceTimersByTime(1);
} else if (state === "PREPARED" && httpLookups.length === 0) { } else if (state === "PREPARED" && httpLookups.length === 0) {
client.removeListener(ClientEvent.Sync, syncListener); client.removeListener(ClientEvent.Sync, syncListener);
done(); resolve(null);
} else { } else {
// unexpected state transition! // unexpected state transition!
expect(state).toEqual(null); expect(state).toEqual(null);
} }
}); });
client.startClient(); });
await client.startClient();
await wasPreparedPromise;
}); });
it("should work on /sync", function (done) { it("should work on /sync", async () => {
httpLookups.push({ httpLookups.push({
method: "GET", method: "GET",
path: "/sync", path: "/sync",
@ -972,6 +973,7 @@ describe("MatrixClient", function () {
data: SYNC_DATA, data: SYNC_DATA,
}); });
const isSyncingPromise = new Promise((resolve) => {
client.on(ClientEvent.Sync, function syncListener(state) { client.on(ClientEvent.Sync, function syncListener(state) {
if (state === "ERROR" && httpLookups.length > 0) { if (state === "ERROR" && httpLookups.length > 0) {
expect(httpLookups.length).toEqual(1); expect(httpLookups.length).toEqual(1);
@ -981,13 +983,15 @@ describe("MatrixClient", function () {
jest.advanceTimersByTime(10000); jest.advanceTimersByTime(10000);
} else if (state === "SYNCING" && httpLookups.length === 0) { } else if (state === "SYNCING" && httpLookups.length === 0) {
client.removeListener(ClientEvent.Sync, syncListener); client.removeListener(ClientEvent.Sync, syncListener);
done(); resolve(null);
} }
}); });
client.startClient(); });
await client.startClient();
await isSyncingPromise;
}); });
it("should work on /pushrules", function (done) { it("should work on /pushrules", async () => {
httpLookups = []; httpLookups = [];
httpLookups.push({ httpLookups.push({
method: "GET", method: "GET",
@ -998,6 +1002,7 @@ describe("MatrixClient", function () {
httpLookups.push(FILTER_RESPONSE); httpLookups.push(FILTER_RESPONSE);
httpLookups.push(SYNC_RESPONSE); httpLookups.push(SYNC_RESPONSE);
const wasPreparedPromise = new Promise((resolve) => {
client.on(ClientEvent.Sync, function syncListener(state) { client.on(ClientEvent.Sync, function syncListener(state) {
if (state === "ERROR" && httpLookups.length > 0) { if (state === "ERROR" && httpLookups.length > 0) {
expect(httpLookups.length).toEqual(3); expect(httpLookups.length).toEqual(3);
@ -1005,13 +1010,15 @@ describe("MatrixClient", function () {
jest.advanceTimersByTime(1); jest.advanceTimersByTime(1);
} else if (state === "PREPARED" && httpLookups.length === 0) { } else if (state === "PREPARED" && httpLookups.length === 0) {
client.removeListener(ClientEvent.Sync, syncListener); client.removeListener(ClientEvent.Sync, syncListener);
done(); resolve(null);
} else { } else {
// unexpected state transition! // unexpected state transition!
expect(state).toEqual(null); expect(state).toEqual(null);
} }
}); });
client.startClient(); });
await client.startClient();
await wasPreparedPromise;
}); });
}); });
@ -1035,14 +1042,17 @@ describe("MatrixClient", function () {
}; };
} }
it("should transition null -> PREPARED after the first /sync", function (done) { it("should transition null -> PREPARED after the first /sync", async () => {
const expectedStates: [string, string | null][] = []; const expectedStates: [string, string | null][] = [];
expectedStates.push(["PREPARED", null]); expectedStates.push(["PREPARED", null]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done)); const didSyncPromise = new Promise((resolve) => {
client.startClient(); client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
}); });
it("should transition null -> ERROR after a failed /filter", function (done) { it("should transition null -> ERROR after a failed /filter", async () => {
const expectedStates: [string, string | null][] = []; const expectedStates: [string, string | null][] = [];
httpLookups = []; httpLookups = [];
httpLookups.push(PUSH_RULES_RESPONSE); httpLookups.push(PUSH_RULES_RESPONSE);
@ -1052,14 +1062,17 @@ describe("MatrixClient", function () {
error: { errcode: "NOPE_NOPE_NOPE" }, error: { errcode: "NOPE_NOPE_NOPE" },
}); });
expectedStates.push(["ERROR", null]); expectedStates.push(["ERROR", null]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done)); const didSyncPromise = new Promise((resolve) => {
client.startClient(); client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
}); });
// Disabled because now `startClient` makes a legit call to `/versions` // Disabled because now `startClient` makes a legit call to `/versions`
// And those tests are really unhappy about it... Not possible to figure // And those tests are really unhappy about it... Not possible to figure
// out what a good resolution would look like // out what a good resolution would look like
xit("should transition ERROR -> CATCHUP after /sync if prev failed", function (done) { it.skip("should transition ERROR -> CATCHUP after /sync if prev failed", async () => {
const expectedStates: [string, string | null][] = []; const expectedStates: [string, string | null][] = [];
acceptKeepalives = false; acceptKeepalives = false;
httpLookups = []; httpLookups = [];
@ -1089,19 +1102,25 @@ describe("MatrixClient", function () {
expectedStates.push(["RECONNECTING", null]); expectedStates.push(["RECONNECTING", null]);
expectedStates.push(["ERROR", "RECONNECTING"]); expectedStates.push(["ERROR", "RECONNECTING"]);
expectedStates.push(["CATCHUP", "ERROR"]); expectedStates.push(["CATCHUP", "ERROR"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done)); const didSyncPromise = new Promise((resolve) => {
client.startClient(); client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
}); });
it("should transition PREPARED -> SYNCING after /sync", function (done) { it("should transition PREPARED -> SYNCING after /sync", async () => {
const expectedStates: [string, string | null][] = []; const expectedStates: [string, string | null][] = [];
expectedStates.push(["PREPARED", null]); expectedStates.push(["PREPARED", null]);
expectedStates.push(["SYNCING", "PREPARED"]); expectedStates.push(["SYNCING", "PREPARED"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done)); const didSyncPromise = new Promise((resolve) => {
client.startClient(); client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
}); });
xit("should transition SYNCING -> ERROR after a failed /sync", function (done) { it.skip("should transition SYNCING -> ERROR after a failed /sync", async () => {
acceptKeepalives = false; acceptKeepalives = false;
const expectedStates: [string, string | null][] = []; const expectedStates: [string, string | null][] = [];
httpLookups.push({ httpLookups.push({
@ -1119,11 +1138,14 @@ describe("MatrixClient", function () {
expectedStates.push(["SYNCING", "PREPARED"]); expectedStates.push(["SYNCING", "PREPARED"]);
expectedStates.push(["RECONNECTING", "SYNCING"]); expectedStates.push(["RECONNECTING", "SYNCING"]);
expectedStates.push(["ERROR", "RECONNECTING"]); expectedStates.push(["ERROR", "RECONNECTING"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done)); const didSyncPromise = new Promise((resolve) => {
client.startClient(); client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
}); });
xit("should transition ERROR -> SYNCING after /sync if prev failed", function (done) { it.skip("should transition ERROR -> SYNCING after /sync if prev failed", async () => {
const expectedStates: [string, string | null][] = []; const expectedStates: [string, string | null][] = [];
httpLookups.push({ httpLookups.push({
method: "GET", method: "GET",
@ -1135,11 +1157,14 @@ describe("MatrixClient", function () {
expectedStates.push(["PREPARED", null]); expectedStates.push(["PREPARED", null]);
expectedStates.push(["SYNCING", "PREPARED"]); expectedStates.push(["SYNCING", "PREPARED"]);
expectedStates.push(["ERROR", "SYNCING"]); expectedStates.push(["ERROR", "SYNCING"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done)); const didSyncPromise = new Promise((resolve) => {
client.startClient(); client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
}); });
it("should transition SYNCING -> SYNCING on subsequent /sync successes", function (done) { it("should transition SYNCING -> SYNCING on subsequent /sync successes", async () => {
const expectedStates: [string, string | null][] = []; const expectedStates: [string, string | null][] = [];
httpLookups.push(SYNC_RESPONSE); httpLookups.push(SYNC_RESPONSE);
httpLookups.push(SYNC_RESPONSE); httpLookups.push(SYNC_RESPONSE);
@ -1147,11 +1172,14 @@ describe("MatrixClient", function () {
expectedStates.push(["PREPARED", null]); expectedStates.push(["PREPARED", null]);
expectedStates.push(["SYNCING", "PREPARED"]); expectedStates.push(["SYNCING", "PREPARED"]);
expectedStates.push(["SYNCING", "SYNCING"]); expectedStates.push(["SYNCING", "SYNCING"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done)); const didSyncPromise = new Promise((resolve) => {
client.startClient(); client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
}); });
xit("should transition ERROR -> ERROR if keepalive keeps failing", function (done) { it.skip("should transition ERROR -> ERROR if keepalive keeps failing", async () => {
acceptKeepalives = false; acceptKeepalives = false;
const expectedStates: [string, string | null][] = []; const expectedStates: [string, string | null][] = [];
httpLookups.push({ httpLookups.push({
@ -1175,8 +1203,11 @@ describe("MatrixClient", function () {
expectedStates.push(["RECONNECTING", "SYNCING"]); expectedStates.push(["RECONNECTING", "SYNCING"]);
expectedStates.push(["ERROR", "RECONNECTING"]); expectedStates.push(["ERROR", "RECONNECTING"]);
expectedStates.push(["ERROR", "ERROR"]); expectedStates.push(["ERROR", "ERROR"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done)); const didSyncPromise = new Promise((resolve) => {
client.startClient(); client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
}); });
}); });
@ -1214,7 +1245,7 @@ describe("MatrixClient", function () {
expect(httpLookups.length).toBe(0); expect(httpLookups.length).toBe(0);
}); });
xit("should be able to peek into a room using peekInRoom", function (done) {}); it.skip("should be able to peek into a room using peekInRoom", function () {});
}); });
describe("getPresence", function () { describe("getPresence", function () {
@ -1334,7 +1365,7 @@ describe("MatrixClient", function () {
client.redactEvent(roomId, eventId, txnId, { client.redactEvent(roomId, eventId, txnId, {
with_relations: [RelationType.Reference], with_relations: [RelationType.Reference],
}); });
}).toThrowError( }).toThrow(
new Error( new Error(
"Server does not support relation based redactions " + "Server does not support relation based redactions " +
`roomId ${roomId} eventId ${eventId} txnId: ${txnId} threadId null`, `roomId ${roomId} eventId ${eventId} txnId: ${txnId} threadId null`,
@ -2410,31 +2441,6 @@ describe("MatrixClient", function () {
expect(rooms).toContain(room1); expect(rooms).toContain(room1);
expect(rooms).toContain(room2); expect(rooms).toContain(room2);
}); });
it("Ignores m.predecessor if we don't ask to use it", () => {
// Given 6 rooms, 2 of which have been replaced, and 2 of which WERE
// replaced by create events, but are now NOT replaced, because an
// m.predecessor event has changed the room's predecessor.
const {
room1,
room2,
replacedByCreate1,
replacedByCreate2,
replacedByDynamicPredecessor1,
replacedByDynamicPredecessor2,
} = setUpReplacedRooms();
// When we ask for the visible rooms
const rooms = client.getVisibleRooms(); // Don't supply msc3946ProcessDynamicPredecessor
// Then we only get the ones that have not been replaced
expect(rooms).not.toContain(replacedByCreate1);
expect(rooms).not.toContain(replacedByCreate2);
expect(rooms).toContain(replacedByDynamicPredecessor1);
expect(rooms).toContain(replacedByDynamicPredecessor2);
expect(rooms).toContain(room1);
expect(rooms).toContain(room2);
});
}); });
describe("getRoomUpgradeHistory", () => { describe("getRoomUpgradeHistory", () => {
@ -2619,7 +2625,7 @@ describe("MatrixClient", function () {
expect(history.map((room) => room.roomId)).toEqual([room1.roomId]); expect(history.map((room) => room.roomId)).toEqual([room1.roomId]);
}); });
it("Without verify links, includes predecessors that don't point forwards", () => { it("Without verify links, includes successors that don't point backwards", () => {
// Given predecessors point forwards with tombstones, but // Given predecessors point forwards with tombstones, but
// successors do not point back with create events. // successors do not point back with create events.
const [room1, room2, room3, room4] = createRoomHistory(false, true); const [room1, room2, room3, room4] = createRoomHistory(false, true);

View File

@ -80,7 +80,7 @@ describe("Poll", () => {
const pollStartEvent = new MatrixEvent( const pollStartEvent = new MatrixEvent(
PollStartEvent.from("What?", ["a", "b"], M_POLL_KIND_DISCLOSED.name).serialize(), PollStartEvent.from("What?", ["a", "b"], M_POLL_KIND_DISCLOSED.name).serialize(),
); );
expect(() => new Poll(pollStartEvent, mockClient, room)).toThrowError("Invalid poll start event."); expect(() => new Poll(pollStartEvent, mockClient, room)).toThrow("Invalid poll start event.");
}); });
it("throws when poll start has no event id", () => { it("throws when poll start has no event id", () => {
@ -88,7 +88,7 @@ describe("Poll", () => {
...PollStartEvent.from("What?", ["a", "b"], M_POLL_KIND_DISCLOSED.name).serialize(), ...PollStartEvent.from("What?", ["a", "b"], M_POLL_KIND_DISCLOSED.name).serialize(),
room_id: roomId, room_id: roomId,
}); });
expect(() => new Poll(pollStartEvent, mockClient, room)).toThrowError("Invalid poll start event."); expect(() => new Poll(pollStartEvent, mockClient, room)).toThrow("Invalid poll start event.");
}); });
describe("fetching responses", () => { describe("fetching responses", () => {
@ -292,33 +292,6 @@ describe("Poll", () => {
expect(maySendRedactionForEventSpy).toHaveBeenCalledWith(basePollStartEvent, "@charlie:server.org"); expect(maySendRedactionForEventSpy).toHaveBeenCalledWith(basePollStartEvent, "@charlie:server.org");
}); });
it("does not set poll end event when an earlier end event already exists", async () => {
const earlierPollEndEvent = makeRelatedEvent(
{ type: M_POLL_END.stable!, sender: "@valid:server.org" },
now,
);
const laterPollEndEvent = makeRelatedEvent(
{ type: M_POLL_END.stable!, sender: "@valid:server.org" },
now + 2000,
);
const poll = new Poll(basePollStartEvent, mockClient, room);
await poll.getResponses();
poll.onNewRelation(earlierPollEndEvent);
// first end event set correctly
expect(poll.isEnded).toBeTruthy();
// reset spy count
jest.spyOn(poll, "emit").mockClear();
poll.onNewRelation(laterPollEndEvent);
// didn't set new end event, didn't refilter responses
expect(poll.emit).not.toHaveBeenCalled();
expect(poll.isEnded).toBeTruthy();
});
it("replaces poll end event and refilters when an older end event already exists", async () => { it("replaces poll end event and refilters when an older end event already exists", async () => {
const earlierPollEndEvent = makeRelatedEvent( const earlierPollEndEvent = makeRelatedEvent(
{ type: M_POLL_END.stable!, sender: "@valid:server.org" }, { type: M_POLL_END.stable!, sender: "@valid:server.org" },
@ -356,25 +329,6 @@ describe("Poll", () => {
expect(responses.getRelations()).toEqual([responseEventAtEnd, responseEventBeforeEnd]); expect(responses.getRelations()).toEqual([responseEventAtEnd, responseEventBeforeEnd]);
}); });
it("does not set poll end event when sent by invalid user", async () => {
maySendRedactionForEventSpy.mockReturnValue(false);
const stablePollEndEvent = makeRelatedEvent({ type: M_POLL_END.stable!, sender: "@charlie:server.org" });
const responseEventAfterEnd = makeRelatedEvent({ type: M_POLL_RESPONSE.name }, now + 1000);
mockClient.relations.mockResolvedValue({
events: [responseEventAfterEnd],
});
const poll = new Poll(basePollStartEvent, mockClient, room);
await poll.getResponses();
jest.spyOn(poll, "emit");
poll.onNewRelation(stablePollEndEvent);
// didn't end, didn't refilter responses
expect(poll.emit).not.toHaveBeenCalled();
expect(poll.isEnded).toBeFalsy();
expect(maySendRedactionForEventSpy).toHaveBeenCalledWith(basePollStartEvent, "@charlie:server.org");
});
it("does not set poll end event when an earlier end event already exists", async () => { it("does not set poll end event when an earlier end event already exists", async () => {
const earlierPollEndEvent = makeRelatedEvent( const earlierPollEndEvent = makeRelatedEvent(
{ type: M_POLL_END.stable!, sender: "@valid:server.org" }, { type: M_POLL_END.stable!, sender: "@valid:server.org" },
@ -402,43 +356,6 @@ describe("Poll", () => {
expect(poll.isEnded).toBeTruthy(); expect(poll.isEnded).toBeTruthy();
}); });
it("replaces poll end event and refilters when an older end event already exists", async () => {
const earlierPollEndEvent = makeRelatedEvent(
{ type: M_POLL_END.stable!, sender: "@valid:server.org" },
now,
);
const laterPollEndEvent = makeRelatedEvent(
{ type: M_POLL_END.stable!, sender: "@valid:server.org" },
now + 2000,
);
const responseEventBeforeEnd = makeRelatedEvent({ type: M_POLL_RESPONSE.name }, now - 1000);
const responseEventAtEnd = makeRelatedEvent({ type: M_POLL_RESPONSE.name }, now);
const responseEventAfterEnd = makeRelatedEvent({ type: M_POLL_RESPONSE.name }, now + 1000);
mockClient.relations.mockResolvedValue({
events: [responseEventAfterEnd, responseEventAtEnd, responseEventBeforeEnd, laterPollEndEvent],
});
const poll = new Poll(basePollStartEvent, mockClient, room);
const responses = await poll.getResponses();
// all responses have a timestamp < laterPollEndEvent
expect(responses.getRelations().length).toEqual(3);
// first end event set correctly
expect(poll.isEnded).toBeTruthy();
// reset spy count
jest.spyOn(poll, "emit").mockClear();
// add a valid end event with earlier timestamp
poll.onNewRelation(earlierPollEndEvent);
// emitted new end event
expect(poll.emit).toHaveBeenCalledWith(PollEvent.End);
// filtered responses and emitted
expect(poll.emit).toHaveBeenCalledWith(PollEvent.Responses, responses);
expect(responses.getRelations()).toEqual([responseEventAtEnd, responseEventBeforeEnd]);
});
it("sets poll end event and refilters responses based on timestamp", async () => { it("sets poll end event and refilters responses based on timestamp", async () => {
const stablePollEndEvent = makeRelatedEvent({ type: M_POLL_END.stable!, sender: userId }); const stablePollEndEvent = makeRelatedEvent({ type: M_POLL_END.stable!, sender: userId });
const responseEventBeforeEnd = makeRelatedEvent({ type: M_POLL_RESPONSE.name }, now - 1000); const responseEventBeforeEnd = makeRelatedEvent({ type: M_POLL_RESPONSE.name }, now - 1000);

View File

@ -159,7 +159,7 @@ describe("fixNotificationCountOnDecryption", () => {
expect(room.getThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight)).toBe(1); expect(room.getThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight)).toBe(1);
}); });
it("does not change the room count when there's no unread count", () => { it("does not change the thread count when there's no unread count", () => {
room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Total, 0); room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Total, 0);
room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight, 0); room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight, 0);

View File

@ -146,7 +146,7 @@ describe("ECDHv1", function () {
// send a message without encryption // send a message without encryption
await aliceTransport.send({ iv: "dummy", ciphertext: "dummy" }); await aliceTransport.send({ iv: "dummy", ciphertext: "dummy" });
expect(bob.receive()).rejects.toThrowError(); expect(bob.receive()).rejects.toThrow();
await alice.cancel(RendezvousFailureReason.Unknown); await alice.cancel(RendezvousFailureReason.Unknown);
await bob.cancel(RendezvousFailureReason.Unknown); await bob.cancel(RendezvousFailureReason.Unknown);
@ -164,7 +164,7 @@ describe("ECDHv1", function () {
await bobTransport.send({ iv: "dummy", ciphertext: "dummy" }); await bobTransport.send({ iv: "dummy", ciphertext: "dummy" });
expect(alice.receive()).rejects.toThrowError(); expect(alice.receive()).rejects.toThrow();
await alice.cancel(RendezvousFailureReason.Unknown); await alice.cancel(RendezvousFailureReason.Unknown);
}); });

View File

@ -220,7 +220,7 @@ describe("Rendezvous", function () {
await bobStartPromise; await bobStartPromise;
}); });
it("new device declines protocol", async function () { it("new device declines protocol with outcome unsupported", async function () {
const aliceTransport = makeTransport("Alice", "https://test.rz/123456"); const aliceTransport = makeTransport("Alice", "https://test.rz/123456");
const bobTransport = makeTransport("Bob", "https://test.rz/999999"); const bobTransport = makeTransport("Bob", "https://test.rz/999999");
transports.push(aliceTransport, bobTransport); transports.push(aliceTransport, bobTransport);
@ -278,7 +278,7 @@ describe("Rendezvous", function () {
expect(aliceOnFailure).toHaveBeenCalledWith(RendezvousFailureReason.UnsupportedAlgorithm); expect(aliceOnFailure).toHaveBeenCalledWith(RendezvousFailureReason.UnsupportedAlgorithm);
}); });
it("new device declines protocol", async function () { it("new device requests an invalid protocol", async function () {
const aliceTransport = makeTransport("Alice", "https://test.rz/123456"); const aliceTransport = makeTransport("Alice", "https://test.rz/123456");
const bobTransport = makeTransport("Bob", "https://test.rz/999999"); const bobTransport = makeTransport("Bob", "https://test.rz/999999");
transports.push(aliceTransport, bobTransport); transports.push(aliceTransport, bobTransport);
@ -570,7 +570,7 @@ describe("Rendezvous", function () {
it("device not online within timeout", async function () { it("device not online within timeout", async function () {
const { aliceRz } = await completeLogin({}); const { aliceRz } = await completeLogin({});
expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrowError(); expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrow();
}); });
it("device appears online within timeout", async function () { it("device appears online within timeout", async function () {
@ -594,7 +594,7 @@ describe("Rendezvous", function () {
getFingerprint: () => "bbbb", getFingerprint: () => "bbbb",
}; };
}, 1500); }, 1500);
expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrowError(); expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrow();
}); });
it("mismatched device key", async function () { it("mismatched device key", async function () {
@ -603,6 +603,6 @@ describe("Rendezvous", function () {
getFingerprint: () => "XXXX", getFingerprint: () => "XXXX",
}, },
}); });
expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrowError(/different key/); expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrow(/different key/);
}); });
}); });

View File

@ -98,7 +98,7 @@ describe("SimpleHttpRendezvousTransport", function () {
it("should throw an error when no server available", function () { it("should throw an error when no server available", function () {
const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc3886Enabled: false }); const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc3886Enabled: false });
const simpleHttpTransport = new MSC3886SimpleHttpRendezvousTransport({ client, fetchFn }); const simpleHttpTransport = new MSC3886SimpleHttpRendezvousTransport({ client, fetchFn });
expect(simpleHttpTransport.send({})).rejects.toThrowError("Invalid rendezvous URI"); expect(simpleHttpTransport.send({})).rejects.toThrow("Invalid rendezvous URI");
}); });
it("POST to fallback server", async function () { it("POST to fallback server", async function () {
@ -130,7 +130,7 @@ describe("SimpleHttpRendezvousTransport", function () {
fetchFn, fetchFn,
}); });
const prom = simpleHttpTransport.send({}); const prom = simpleHttpTransport.send({});
expect(prom).rejects.toThrowError(); expect(prom).rejects.toThrow();
httpBackend.when("POST", "https://fallbackserver/rz").response = { httpBackend.when("POST", "https://fallbackserver/rz").response = {
body: null, body: null,
response: { response: {
@ -163,15 +163,6 @@ describe("SimpleHttpRendezvousTransport", function () {
); );
}); });
it("POST with relative path response including parent", async function () {
await postAndCheckLocation(
false,
"https://fallbackserver/rz/abc",
"../xyz/123",
"https://fallbackserver/rz/xyz/123",
);
});
it("POST to follow 307 to other server", async function () { it("POST to follow 307 to other server", async function () {
const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc3886Enabled: false }); const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc3886Enabled: false });
const simpleHttpTransport = new MSC3886SimpleHttpRendezvousTransport({ const simpleHttpTransport = new MSC3886SimpleHttpRendezvousTransport({
@ -373,7 +364,7 @@ describe("SimpleHttpRendezvousTransport", function () {
fallbackRzServer: "https://fallbackserver/rz", fallbackRzServer: "https://fallbackserver/rz",
fetchFn, fetchFn,
}); });
expect(simpleHttpTransport.details()).rejects.toThrowError(); expect(simpleHttpTransport.details()).rejects.toThrow();
}); });
it("send after cancelled", async function () { it("send after cancelled", async function () {
@ -394,7 +385,7 @@ describe("SimpleHttpRendezvousTransport", function () {
fallbackRzServer: "https://fallbackserver/rz", fallbackRzServer: "https://fallbackserver/rz",
fetchFn, fetchFn,
}); });
expect(simpleHttpTransport.receive()).rejects.toThrowError(); expect(simpleHttpTransport.receive()).rejects.toThrow();
}); });
it("404 failure callback", async function () { it("404 failure callback", async function () {
@ -416,7 +407,7 @@ describe("SimpleHttpRendezvousTransport", function () {
}, },
}; };
await httpBackend.flush("", 1); await httpBackend.flush("", 1);
expect(onFailure).toBeCalledWith(RendezvousFailureReason.Unknown); expect(onFailure).toHaveBeenCalledWith(RendezvousFailureReason.Unknown);
}); });
it("404 failure callback mapped to expired", async function () { it("404 failure callback mapped to expired", async function () {
@ -456,7 +447,7 @@ describe("SimpleHttpRendezvousTransport", function () {
}, },
}; };
await httpBackend.flush(""); await httpBackend.flush("");
expect(onFailure).toBeCalledWith(RendezvousFailureReason.Expired); expect(onFailure).toHaveBeenCalledWith(RendezvousFailureReason.Expired);
} }
}); });
}); });

View File

@ -788,8 +788,12 @@ describe("Room", function () {
}); });
}; };
describe("resetLiveTimeline with timeline support enabled", resetTimelineTests.bind(null, true)); describe("resetLiveTimeline with timeline support enabled", () => {
describe("resetLiveTimeline with timeline support disabled", resetTimelineTests.bind(null, false)); resetTimelineTests.bind(null, true);
});
describe("resetLiveTimeline with timeline support disabled", () => {
resetTimelineTests.bind(null, false);
});
describe("compareEventOrdering", function () { describe("compareEventOrdering", function () {
beforeEach(function () { beforeEach(function () {

View File

@ -150,7 +150,7 @@ describe("MatrixScheduler", function () {
expect(procCount).toEqual(1); expect(procCount).toEqual(1);
}); });
it("should treat each queue separately", function (done) { it("should treat each queue separately", async () => {
// Queue messages A B C D. // Queue messages A B C D.
// Bucket A&D into queue_A // Bucket A&D into queue_A
// Bucket B&C into queue_B // Bucket B&C into queue_B
@ -175,14 +175,16 @@ describe("MatrixScheduler", function () {
const expectOrder = [eventA.getId(), eventB.getId(), eventD.getId()]; const expectOrder = [eventA.getId(), eventB.getId(), eventD.getId()];
const deferA = defer<Record<string, boolean>>(); const deferA = defer<Record<string, boolean>>();
const allExpectedEventsSeenInOrderPromise = new Promise((resolve) => {
scheduler.setProcessFunction(function (event) { scheduler.setProcessFunction(function (event) {
const id = expectOrder.shift(); const id = expectOrder.shift();
expect(id).toEqual(event.getId()); expect(id).toEqual(event.getId());
if (expectOrder.length === 0) { if (expectOrder.length === 0) {
done(); resolve(null);
} }
return id === eventA.getId() ? deferA.promise : deferred.promise; return id === eventA.getId() ? deferA.promise : deferred.promise;
}); });
});
scheduler.queueEvent(eventA); scheduler.queueEvent(eventA);
scheduler.queueEvent(eventB); scheduler.queueEvent(eventB);
scheduler.queueEvent(eventC); scheduler.queueEvent(eventC);
@ -193,6 +195,7 @@ describe("MatrixScheduler", function () {
deferA.resolve({}); deferA.resolve({});
}, 1000); }, 1000);
jest.advanceTimersByTime(1000); jest.advanceTimersByTime(1000);
await allExpectedEventsSeenInOrderPromise;
}); });
describe("queueEvent", function () { describe("queueEvent", function () {
@ -290,7 +293,7 @@ describe("MatrixScheduler", function () {
}); });
describe("setProcessFunction", function () { describe("setProcessFunction", function () {
it("should call the processFn if there are queued events", function () { it("should call the processFn if there are queued events", async () => {
queueFn = function () { queueFn = function () {
return "yep"; return "yep";
}; };
@ -303,10 +306,9 @@ describe("MatrixScheduler", function () {
}); });
// as queueing doesn't start processing synchronously anymore (see commit bbdb5ac) // as queueing doesn't start processing synchronously anymore (see commit bbdb5ac)
// wait just long enough before it does // wait just long enough before it does
Promise.resolve().then(() => { await Promise.resolve();
expect(procCount).toEqual(1); expect(procCount).toEqual(1);
}); });
});
it("should not call the processFn if there are no queued events", function () { it("should not call the processFn if there are no queued events", function () {
queueFn = function () { queueFn = function () {

View File

@ -145,9 +145,11 @@ describe("utils", function () {
describe("deepCompare", function () { describe("deepCompare", function () {
const assert = { const assert = {
isTrue: function (x: any) { isTrue: function (x: any) {
// eslint-disable-next-line jest/no-standalone-expect
expect(x).toBe(true); expect(x).toBe(true);
}, },
isFalse: function (x: any) { isFalse: function (x: any) {
// eslint-disable-next-line jest/no-standalone-expect
expect(x).toBe(false); expect(x).toBe(false);
}, },
}; };

View File

@ -1579,7 +1579,7 @@ describe("Call", function () {
hasAdvancedBy += advanceBy; hasAdvancedBy += advanceBy;
expect(lengthChangedListener).toHaveBeenCalledTimes(hasAdvancedBy); expect(lengthChangedListener).toHaveBeenCalledTimes(hasAdvancedBy);
expect(lengthChangedListener).toBeCalledWith(hasAdvancedBy); expect(lengthChangedListener).toHaveBeenCalledWith(hasAdvancedBy);
} }
}); });

View File

@ -147,7 +147,7 @@ describe("Group Call", function () {
async (state: GroupCallState) => { async (state: GroupCallState) => {
// @ts-ignore // @ts-ignore
groupCall.state = state; groupCall.state = state;
await expect(groupCall.initLocalCallFeed()).rejects.toThrowError(); await expect(groupCall.initLocalCallFeed()).rejects.toThrow();
}, },
); );
@ -389,7 +389,7 @@ describe("Group Call", function () {
jest.spyOn(call, "getOpponentMember").mockReturnValue({ userId: undefined }); jest.spyOn(call, "getOpponentMember").mockReturnValue({ userId: undefined });
// @ts-ignore Mock // @ts-ignore Mock
expect(() => groupCall.onCallFeedsChanged(call)).toThrowError(); expect(() => groupCall.onCallFeedsChanged(call)).toThrow();
}); });
describe("usermedia feeds", () => { describe("usermedia feeds", () => {

View File

@ -401,7 +401,7 @@ describe("Media Handler", function () {
}); });
}); });
describe("stopUserMediaStream", () => { describe("stopScreensharingStream", () => {
let stream: MediaStream; let stream: MediaStream;
beforeEach(async () => { beforeEach(async () => {

View File

@ -1869,7 +1869,7 @@
semver "^7.3.7" semver "^7.3.7"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/utils@5.51.0": "@typescript-eslint/utils@5.51.0", "@typescript-eslint/utils@^5.10.0":
version "5.51.0" version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.51.0.tgz#074f4fabd5b12afe9c8aa6fdee881c050f8b4d47" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.51.0.tgz#074f4fabd5b12afe9c8aa6fdee881c050f8b4d47"
integrity sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw== integrity sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==
@ -3414,6 +3414,13 @@ eslint-plugin-import@^2.26.0:
semver "^6.3.0" semver "^6.3.0"
tsconfig-paths "^3.14.1" tsconfig-paths "^3.14.1"
eslint-plugin-jest@^27.1.6:
version "27.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz#b85b4adf41c682ea29f1f01c8b11ccc39b5c672c"
integrity sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==
dependencies:
"@typescript-eslint/utils" "^5.10.0"
eslint-plugin-jsdoc@^39.6.4: eslint-plugin-jsdoc@^39.6.4:
version "39.8.0" version "39.8.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.8.0.tgz#9ca38ae31fb6e6de6268c5c041fa175fe1190469" resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.8.0.tgz#9ca38ae31fb6e6de6268c5c041fa175fe1190469"
@ -3427,10 +3434,10 @@ eslint-plugin-jsdoc@^39.6.4:
semver "^7.3.8" semver "^7.3.8"
spdx-expression-parse "^3.0.1" spdx-expression-parse "^3.0.1"
eslint-plugin-matrix-org@^0.10.0: eslint-plugin-matrix-org@^1.0.0:
version "0.10.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-0.10.0.tgz#8d0998641a4d276343cae2abf253a01bb4d4cc60" resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-1.0.0.tgz#cead71391e2a36d63cb8f8018a38305ecf81b4b8"
integrity sha512-L7ail0x1yUlF006kn4mHc+OT8/aYZI++i852YXPHxCbM1EY7jeg/fYAQ8tCx5+x08LyqXeS7inAVSL784m0C6Q== integrity sha512-JSjw+hswEcFR+N4N2JXZttK65cK6huykZKkbnwcITxPTelsaOfZ8qXG0Az9BfmVADaLgY3MGmHK1YYKbykUfBQ==
eslint-plugin-tsdoc@^0.2.17: eslint-plugin-tsdoc@^0.2.17:
version "0.2.17" version "0.2.17"