1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-07-30 04:23:07 +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 = {
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: {
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: [
{

View File

@ -103,8 +103,9 @@
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.5.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^27.1.6",
"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-unicorn": "^45.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.
*/
// `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
import "./olm-loader";

View File

@ -743,10 +743,8 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm (%s)", (backend: string,
describe("get|setGlobalErrorOnUnknownDevices", () => {
it("should raise an error if crypto is disabled", () => {
aliceTestClient.client["cryptoBackend"] = undefined;
expect(() => aliceTestClient.client.setGlobalErrorOnUnknownDevices(true)).toThrowError(
"encryption disabled",
);
expect(() => aliceTestClient.client.getGlobalErrorOnUnknownDevices()).toThrowError("encryption disabled");
expect(() => aliceTestClient.client.setGlobalErrorOnUnknownDevices(true)).toThrow("encryption disabled");
expect(() => aliceTestClient.client.getGlobalErrorOnUnknownDevices()).toThrow("encryption disabled");
});
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", () => {
it("should raise an error if crypto is disabled", () => {
aliceTestClient.client["cryptoBackend"] = undefined;
expect(() => aliceTestClient.client.setGlobalBlacklistUnverifiedDevices(true)).toThrowError(
"encryption disabled",
);
expect(() => aliceTestClient.client.getGlobalBlacklistUnverifiedDevices()).toThrowError(
expect(() => aliceTestClient.client.setGlobalBlacklistUnverifiedDevices(true)).toThrow(
"encryption disabled",
);
expect(() => aliceTestClient.client.getGlobalBlacklistUnverifiedDevices()).toThrow("encryption disabled");
});
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, NEXT_SYNC_DATA);
let fired = false;
@ -192,10 +192,8 @@ describe("MatrixClient events", function () {
});
client!.startClient();
httpBackend!.flushAllExpected().then(function () {
await httpBackend!.flushAllExpected();
expect(fired).toBe(true);
done();
});
});
it("should emit Room events", function () {

View File

@ -205,19 +205,17 @@ describe("MatrixClient", function () {
describe("getFilter", function () {
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, {
event_format: "client",
});
store!.storeFilter(filter);
client!.getFilter(userId, filterId, true).then(function (gotFilter) {
const gotFilter = await client!.getFilter(userId, filterId, true);
expect(gotFilter).toEqual(filter);
done();
});
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 = {
event_format: "federation",
};
@ -230,15 +228,11 @@ describe("MatrixClient", function () {
event_format: "client",
});
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);
done();
});
httpBackend!.flush("");
});
it("should do an HTTP request if nothing is in the cache and then store it", function (done) {
it("should do an HTTP request if nothing is in the cache and then store it", async () => {
const httpFilterDefinition = {
event_format: "federation",
};
@ -247,20 +241,16 @@ describe("MatrixClient", function () {
httpBackend!
.when("GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId)
.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(store!.getFilter(userId, filterId)).toBeTruthy();
done();
});
httpBackend!.flush("");
});
});
describe("createFilter", function () {
const filterId = "f1llllllerid";
it("should do an HTTP request and then store the filter", function (done) {
it("should do an HTTP request and then store the filter", async () => {
expect(store!.getFilter(userId, filterId)).toBe(null);
const filterDefinition = {
@ -276,13 +266,9 @@ describe("MatrixClient", function () {
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(store!.getFilter(userId, filterId)).toEqual(gotFilter);
done();
});
httpBackend!.flush("");
});
});

View File

@ -94,16 +94,16 @@ describe("MatrixClient opts", function () {
client.stopClient();
});
it("should be able to send messages", function (done) {
it("should be able to send messages", async () => {
const eventId = "$flibble:wibble";
httpBackend.when("PUT", "/txn1").respond(200, {
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);
done();
});
httpBackend.flush("/txn1", 1);
});
it("should be able to sync / get new events", async function () {
@ -149,7 +149,7 @@ describe("MatrixClient opts", function () {
client.stopClient();
});
it("shouldn't retry sending events", function (done) {
it("shouldn't retry sending events", async () => {
httpBackend.when("PUT", "/txn1").respond(
500,
new MatrixError({
@ -157,19 +157,17 @@ describe("MatrixClient opts", function () {
error: "Ruh roh",
}),
);
client.sendTextMessage("!foo:bar", "a body", "txn1").then(
function (res) {
expect(false).toBe(true);
},
function (err) {
expect(err.errcode).toEqual("M_SOMETHING");
done();
},
);
httpBackend.flush("/txn1", 1);
try {
await Promise.all([
expect(client.sendTextMessage("!foo:bar", "a body", "txn1")).rejects.toThrow(),
httpBackend.flush("/txn1", 1),
]);
} catch (err) {
expect((<MatrixError>err).errcode).toEqual("M_SOMETHING");
}
});
it("shouldn't queue events", function (done) {
it("shouldn't queue events", async () => {
httpBackend.when("PUT", "/txn1").respond(200, {
event_id: "AAA",
});
@ -178,30 +176,38 @@ describe("MatrixClient opts", function () {
});
let sentA = 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;
// 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);
});
client.sendTextMessage("!foo:bar", "b body", "txn2").then(function (res) {
const messageBSendPromise = client.sendTextMessage("!foo:bar", "b body", "txn2").then(function (res) {
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);
});
httpBackend.flush("/txn2", 1).then(function () {
httpBackend.flush("/txn1", 1).then(function () {
done();
});
});
// Allow messageB to succeed first
await httpBackend.flush("/txn2", 1);
// 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, {
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");
done();
});
httpBackend.flush("/txn1", 1);
});
});
});

View File

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

View File

@ -81,17 +81,15 @@ describe("MatrixClient syncing", () => {
presence: {},
};
it("should /sync after /pushrules and /filter.", (done) => {
it("should /sync after /pushrules and /filter.", async () => {
httpBackend!.when("GET", "/sync").respond(200, syncData);
client!.startClient();
httpBackend!.flushAllExpected().then(() => {
done();
});
await httpBackend!.flushAllExpected();
});
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")
@ -102,9 +100,7 @@ describe("MatrixClient syncing", () => {
client!.startClient();
httpBackend!.flushAllExpected().then(() => {
done();
});
await httpBackend!.flushAllExpected();
});
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
// timeline events, however this breaks peeking, so it's disabled
// (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, 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", () => {
const normalMessageEvent = utils.mkMessage({
@ -840,6 +836,7 @@ describe("MatrixClient syncing", () => {
roomVersion: "org.matrix.msc2716v3",
},
].forEach((testMeta) => {
// eslint-disable-next-line jest/valid-title
describe(testMeta.label, () => {
const roomCreateEvent = utils.mkEvent({
type: "m.room.create",
@ -1592,27 +1589,24 @@ describe("MatrixClient syncing", () => {
});
describe("of a room", () => {
xit(
it.skip(
"should sync when a join event (which changes state) for the user" +
" 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", () => {
beforeEach((done) => {
beforeEach(async () => {
client!.startClient();
httpBackend!.flushAllExpected().then(() => {
await httpBackend!.flushAllExpected();
// the /sync call from syncLeftRooms ends up in the request
// queue behind the call from the running client; add a response
// to flush the client's one out.
httpBackend!.when("GET", "/sync").respond(200, {});
done();
});
await httpBackend!.when("GET", "/sync").respond(200, {});
});
it("should create and use an appropriate filter", () => {

View File

@ -153,11 +153,11 @@ describe("SlidingSyncSdk", () => {
const hasSynced = sdk!.sync();
await httpBackend!.flushAllExpected();
await hasSynced;
expect(mockSlidingSync!.start).toBeCalled();
expect(mockSlidingSync!.start).toHaveBeenCalled();
});
it("can stop()", async () => {
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 () => {
expect(mockSlidingSync!.stop).not.toBeCalled();
expect(mockSlidingSync!.stop).not.toHaveBeenCalled();
mockSlidingSync!.emit(
SlidingSyncEvent.Lifecycle,
SlidingSyncState.RequestFinished,
@ -595,7 +595,7 @@ describe("SlidingSyncSdk", () => {
}),
);
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 { IndexedToDeviceBatch } from "../../src/models/ToDeviceMessage";
import { SyncState } from "../../src/sync";
import { defer } from "../../src/utils";
describe("onResumedSync", () => {
let batch: IndexedToDeviceBatch | null;
@ -58,7 +59,9 @@ describe("onResumedSync", () => {
queue = new ToDeviceMessageQueue(mockClient);
});
it("resends queue after connectivity restored", (done) => {
it("resends queue after connectivity restored", async () => {
const deferred = defer();
onSendToDeviceFailure = () => {
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
expect(store.removeToDeviceBatch).not.toHaveBeenCalled();
@ -70,26 +73,32 @@ describe("onResumedSync", () => {
onSendToDeviceSuccess = () => {
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(3);
expect(store.removeToDeviceBatch).toHaveBeenCalled();
done();
deferred.resolve();
};
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 = () => {
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
expect(store.removeToDeviceBatch).not.toHaveBeenCalled();
resumeSync(SyncState.Catchup, SyncState.Catchup);
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
done();
deferred.resolve();
};
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 = () => {
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
expect(store.removeToDeviceBatch).not.toHaveBeenCalled();
@ -98,9 +107,10 @@ describe("onResumedSync", () => {
resumeSync(SyncState.Syncing, SyncState.Catchup);
expect(store.getOldestToDeviceBatch).toHaveBeenCalledTimes(1);
done();
deferred.resolve();
};
queue.start();
return deferred.promise;
});
});

View File

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

View File

@ -148,6 +148,10 @@ describe("DeviceList", function () {
dl.invalidateUserDeviceList("@test1:sw1v.org");
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()
.then(() => {
// the first request completes
@ -196,7 +200,7 @@ describe("DeviceList", function () {
downloadSpy.mockReturnValueOnce(queryDefer2.promise);
const prom1 = dl.refreshOutdatedDeviceLists();
expect(downloadSpy).toBeCalledTimes(2);
expect(downloadSpy).toHaveBeenCalledTimes(2);
expect(downloadSpy).toHaveBeenNthCalledWith(1, ["@test1:sw1v.org"], {});
expect(downloadSpy).toHaveBeenNthCalledWith(2, ["@test2:sw1v.org"], {});
queryDefer1.resolve(utils.deepCopy(signedDeviceList));

View File

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

View File

@ -1148,6 +1148,6 @@ describe("userHasCrossSigningKeys", function () {
it("throws an error if crypto is disabled", () => {
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, {
toStartOfTimeline: true,
});
}).toThrowError();
}).toThrow();
});
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", () => {
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", () => {

View File

@ -150,26 +150,6 @@ describe("PollResponseEvent", () => {
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", () => {
const input: IPartialEvent<PollResponseEventContent> = {
type: M_POLL_RESPONSE.name,

View File

@ -78,8 +78,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth();
expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(1);
expect(doRequest).toHaveBeenCalledTimes(1);
expect(stateUpdated).toHaveBeenCalledTimes(1);
});
it("should handle auth errcode presence", async () => {
@ -128,8 +128,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth();
expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(1);
expect(doRequest).toHaveBeenCalledTimes(1);
expect(stateUpdated).toHaveBeenCalledTimes(1);
});
it("should handle set emailSid for email flow", async () => {
@ -180,9 +180,9 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth();
expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(1);
expect(requestEmailToken).toBeCalledTimes(0);
expect(doRequest).toHaveBeenCalledTimes(1);
expect(stateUpdated).toHaveBeenCalledTimes(1);
expect(requestEmailToken).toHaveBeenCalledTimes(0);
expect(ia.getEmailSid()).toBe("myEmailSid");
});
@ -244,8 +244,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth();
expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(2);
expect(stateUpdated).toBeCalledTimes(1);
expect(doRequest).toHaveBeenCalledTimes(2);
expect(stateUpdated).toHaveBeenCalledTimes(1);
});
it("should make a request if authdata is null", async () => {
@ -306,8 +306,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth();
expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(2);
expect(stateUpdated).toBeCalledTimes(1);
expect(doRequest).toHaveBeenCalledTimes(2);
expect(stateUpdated).toHaveBeenCalledTimes(1);
});
it("should start an auth stage and reject if no auth flow", async () => {
@ -430,8 +430,8 @@ describe("InteractiveAuth", () => {
const res = await ia.attemptAuth();
expect(res).toBe(requestRes);
expect(doRequest).toBeCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(0);
expect(doRequest).toHaveBeenCalledTimes(1);
expect(stateUpdated).toHaveBeenCalledTimes(0);
});
describe("requestEmailToken", () => {
@ -464,35 +464,6 @@ describe("InteractiveAuth", () => {
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 () => {
const doRequest = jest.fn();
const stateUpdated = jest.fn();
@ -508,7 +479,7 @@ describe("InteractiveAuth", () => {
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 () => {

View File

@ -893,7 +893,7 @@ 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) {
it("should handle localStorage filterId missing from the server", async () => {
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!
@ -919,10 +919,8 @@ describe("MatrixClient", function () {
client.store.setFilterIdByName(filterName, invalidFilterId);
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);
done();
});
});
});
@ -933,7 +931,7 @@ describe("MatrixClient", function () {
expect(client.retryImmediately()).toBe(false);
});
it("should work on /filter", function (done) {
it("should work on /filter", async () => {
httpLookups = [];
httpLookups.push(PUSH_RULES_RESPONSE);
httpLookups.push({
@ -944,6 +942,7 @@ describe("MatrixClient", function () {
httpLookups.push(FILTER_RESPONSE);
httpLookups.push(SYNC_RESPONSE);
const wasPreparedPromise = new Promise((resolve) => {
client.on(ClientEvent.Sync, function syncListener(state) {
if (state === "ERROR" && httpLookups.length > 0) {
expect(httpLookups.length).toEqual(2);
@ -951,16 +950,18 @@ describe("MatrixClient", function () {
jest.advanceTimersByTime(1);
} else if (state === "PREPARED" && httpLookups.length === 0) {
client.removeListener(ClientEvent.Sync, syncListener);
done();
resolve(null);
} else {
// unexpected state transition!
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({
method: "GET",
path: "/sync",
@ -972,6 +973,7 @@ describe("MatrixClient", function () {
data: SYNC_DATA,
});
const isSyncingPromise = new Promise((resolve) => {
client.on(ClientEvent.Sync, function syncListener(state) {
if (state === "ERROR" && httpLookups.length > 0) {
expect(httpLookups.length).toEqual(1);
@ -981,13 +983,15 @@ describe("MatrixClient", function () {
jest.advanceTimersByTime(10000);
} else if (state === "SYNCING" && httpLookups.length === 0) {
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.push({
method: "GET",
@ -998,6 +1002,7 @@ describe("MatrixClient", function () {
httpLookups.push(FILTER_RESPONSE);
httpLookups.push(SYNC_RESPONSE);
const wasPreparedPromise = new Promise((resolve) => {
client.on(ClientEvent.Sync, function syncListener(state) {
if (state === "ERROR" && httpLookups.length > 0) {
expect(httpLookups.length).toEqual(3);
@ -1005,13 +1010,15 @@ describe("MatrixClient", function () {
jest.advanceTimersByTime(1);
} else if (state === "PREPARED" && httpLookups.length === 0) {
client.removeListener(ClientEvent.Sync, syncListener);
done();
resolve(null);
} else {
// unexpected state transition!
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][] = [];
expectedStates.push(["PREPARED", null]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
client.startClient();
const didSyncPromise = new Promise((resolve) => {
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][] = [];
httpLookups = [];
httpLookups.push(PUSH_RULES_RESPONSE);
@ -1052,14 +1062,17 @@ describe("MatrixClient", function () {
error: { errcode: "NOPE_NOPE_NOPE" },
});
expectedStates.push(["ERROR", null]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
client.startClient();
const didSyncPromise = new Promise((resolve) => {
client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
});
// 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) {
it.skip("should transition ERROR -> CATCHUP after /sync if prev failed", async () => {
const expectedStates: [string, string | null][] = [];
acceptKeepalives = false;
httpLookups = [];
@ -1089,19 +1102,25 @@ describe("MatrixClient", function () {
expectedStates.push(["RECONNECTING", null]);
expectedStates.push(["ERROR", "RECONNECTING"]);
expectedStates.push(["CATCHUP", "ERROR"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
client.startClient();
const didSyncPromise = new Promise((resolve) => {
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][] = [];
expectedStates.push(["PREPARED", null]);
expectedStates.push(["SYNCING", "PREPARED"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
client.startClient();
const didSyncPromise = new Promise((resolve) => {
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;
const expectedStates: [string, string | null][] = [];
httpLookups.push({
@ -1119,11 +1138,14 @@ describe("MatrixClient", function () {
expectedStates.push(["SYNCING", "PREPARED"]);
expectedStates.push(["RECONNECTING", "SYNCING"]);
expectedStates.push(["ERROR", "RECONNECTING"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
client.startClient();
const didSyncPromise = new Promise((resolve) => {
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][] = [];
httpLookups.push({
method: "GET",
@ -1135,11 +1157,14 @@ describe("MatrixClient", function () {
expectedStates.push(["PREPARED", null]);
expectedStates.push(["SYNCING", "PREPARED"]);
expectedStates.push(["ERROR", "SYNCING"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
client.startClient();
const didSyncPromise = new Promise((resolve) => {
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][] = [];
httpLookups.push(SYNC_RESPONSE);
httpLookups.push(SYNC_RESPONSE);
@ -1147,11 +1172,14 @@ describe("MatrixClient", function () {
expectedStates.push(["PREPARED", null]);
expectedStates.push(["SYNCING", "PREPARED"]);
expectedStates.push(["SYNCING", "SYNCING"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
client.startClient();
const didSyncPromise = new Promise((resolve) => {
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;
const expectedStates: [string, string | null][] = [];
httpLookups.push({
@ -1175,8 +1203,11 @@ describe("MatrixClient", function () {
expectedStates.push(["RECONNECTING", "SYNCING"]);
expectedStates.push(["ERROR", "RECONNECTING"]);
expectedStates.push(["ERROR", "ERROR"]);
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
client.startClient();
const didSyncPromise = new Promise((resolve) => {
client.on(ClientEvent.Sync, syncChecker(expectedStates, resolve));
});
await client.startClient();
await didSyncPromise;
});
});
@ -1214,7 +1245,7 @@ describe("MatrixClient", function () {
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 () {
@ -1334,7 +1365,7 @@ describe("MatrixClient", function () {
client.redactEvent(roomId, eventId, txnId, {
with_relations: [RelationType.Reference],
});
}).toThrowError(
}).toThrow(
new Error(
"Server does not support relation based redactions " +
`roomId ${roomId} eventId ${eventId} txnId: ${txnId} threadId null`,
@ -2410,31 +2441,6 @@ describe("MatrixClient", function () {
expect(rooms).toContain(room1);
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", () => {
@ -2619,7 +2625,7 @@ describe("MatrixClient", function () {
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
// successors do not point back with create events.
const [room1, room2, room3, room4] = createRoomHistory(false, true);

View File

@ -80,7 +80,7 @@ describe("Poll", () => {
const pollStartEvent = new MatrixEvent(
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", () => {
@ -88,7 +88,7 @@ describe("Poll", () => {
...PollStartEvent.from("What?", ["a", "b"], M_POLL_KIND_DISCLOSED.name).serialize(),
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", () => {
@ -292,33 +292,6 @@ describe("Poll", () => {
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 () => {
const earlierPollEndEvent = makeRelatedEvent(
{ type: M_POLL_END.stable!, sender: "@valid:server.org" },
@ -356,25 +329,6 @@ describe("Poll", () => {
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 () => {
const earlierPollEndEvent = makeRelatedEvent(
{ type: M_POLL_END.stable!, sender: "@valid:server.org" },
@ -402,43 +356,6 @@ describe("Poll", () => {
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 () => {
const stablePollEndEvent = makeRelatedEvent({ type: M_POLL_END.stable!, sender: userId });
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);
});
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.Highlight, 0);

View File

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

View File

@ -220,7 +220,7 @@ describe("Rendezvous", function () {
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 bobTransport = makeTransport("Bob", "https://test.rz/999999");
transports.push(aliceTransport, bobTransport);
@ -278,7 +278,7 @@ describe("Rendezvous", function () {
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 bobTransport = makeTransport("Bob", "https://test.rz/999999");
transports.push(aliceTransport, bobTransport);
@ -570,7 +570,7 @@ describe("Rendezvous", function () {
it("device not online within timeout", async function () {
const { aliceRz } = await completeLogin({});
expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrowError();
expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrow();
});
it("device appears online within timeout", async function () {
@ -594,7 +594,7 @@ describe("Rendezvous", function () {
getFingerprint: () => "bbbb",
};
}, 1500);
expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrowError();
expect(aliceRz.verifyNewDeviceOnExistingDevice(1000)).rejects.toThrow();
});
it("mismatched device key", async function () {
@ -603,6 +603,6 @@ describe("Rendezvous", function () {
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 () {
const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc3886Enabled: false });
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 () {
@ -130,7 +130,7 @@ describe("SimpleHttpRendezvousTransport", function () {
fetchFn,
});
const prom = simpleHttpTransport.send({});
expect(prom).rejects.toThrowError();
expect(prom).rejects.toThrow();
httpBackend.when("POST", "https://fallbackserver/rz").response = {
body: null,
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 () {
const client = makeMockClient({ userId: "@alice:example.com", deviceId: "DEVICEID", msc3886Enabled: false });
const simpleHttpTransport = new MSC3886SimpleHttpRendezvousTransport({
@ -373,7 +364,7 @@ describe("SimpleHttpRendezvousTransport", function () {
fallbackRzServer: "https://fallbackserver/rz",
fetchFn,
});
expect(simpleHttpTransport.details()).rejects.toThrowError();
expect(simpleHttpTransport.details()).rejects.toThrow();
});
it("send after cancelled", async function () {
@ -394,7 +385,7 @@ describe("SimpleHttpRendezvousTransport", function () {
fallbackRzServer: "https://fallbackserver/rz",
fetchFn,
});
expect(simpleHttpTransport.receive()).rejects.toThrowError();
expect(simpleHttpTransport.receive()).rejects.toThrow();
});
it("404 failure callback", async function () {
@ -416,7 +407,7 @@ describe("SimpleHttpRendezvousTransport", function () {
},
};
await httpBackend.flush("", 1);
expect(onFailure).toBeCalledWith(RendezvousFailureReason.Unknown);
expect(onFailure).toHaveBeenCalledWith(RendezvousFailureReason.Unknown);
});
it("404 failure callback mapped to expired", async function () {
@ -456,7 +447,7 @@ describe("SimpleHttpRendezvousTransport", function () {
},
};
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 disabled", resetTimelineTests.bind(null, false));
describe("resetLiveTimeline with timeline support enabled", () => {
resetTimelineTests.bind(null, true);
});
describe("resetLiveTimeline with timeline support disabled", () => {
resetTimelineTests.bind(null, false);
});
describe("compareEventOrdering", function () {
beforeEach(function () {

View File

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

View File

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

View File

@ -1579,7 +1579,7 @@ describe("Call", function () {
hasAdvancedBy += advanceBy;
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) => {
// @ts-ignore
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 });
// @ts-ignore Mock
expect(() => groupCall.onCallFeedsChanged(call)).toThrowError();
expect(() => groupCall.onCallFeedsChanged(call)).toThrow();
});
describe("usermedia feeds", () => {

View File

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

View File

@ -1869,7 +1869,7 @@
semver "^7.3.7"
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"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.51.0.tgz#074f4fabd5b12afe9c8aa6fdee881c050f8b4d47"
integrity sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==
@ -3414,6 +3414,13 @@ eslint-plugin-import@^2.26.0:
semver "^6.3.0"
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:
version "39.8.0"
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"
spdx-expression-parse "^3.0.1"
eslint-plugin-matrix-org@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-0.10.0.tgz#8d0998641a4d276343cae2abf253a01bb4d4cc60"
integrity sha512-L7ail0x1yUlF006kn4mHc+OT8/aYZI++i852YXPHxCbM1EY7jeg/fYAQ8tCx5+x08LyqXeS7inAVSL784m0C6Q==
eslint-plugin-matrix-org@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-1.0.0.tgz#cead71391e2a36d63cb8f8018a38305ecf81b4b8"
integrity sha512-JSjw+hswEcFR+N4N2JXZttK65cK6huykZKkbnwcITxPTelsaOfZ8qXG0Az9BfmVADaLgY3MGmHK1YYKbykUfBQ==
eslint-plugin-tsdoc@^0.2.17:
version "0.2.17"