Skip to content
Merged
2 changes: 1 addition & 1 deletion spec/integ/crypto/cross-signing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe("cross-signing", () => {
);

afterEach(async () => {
await aliceClient.stopClient();
aliceClient.stopClient();
fetchMock.mockReset();
});

Expand Down
7 changes: 3 additions & 4 deletions spec/integ/crypto/crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ describe("crypto", () => {
);

afterEach(async () => {
await aliceClient.stopClient();
aliceClient.stopClient();

// Allow in-flight things to complete before we tear down the test
await jest.runAllTimersAsync();
Expand Down Expand Up @@ -724,7 +724,7 @@ describe("crypto", () => {
syncResponder.sendOrQueueSyncResponse(syncResponse);
await syncPromise(aliceClient);

await awaitDecryptionError;
await expect(awaitDecryptionError).resolves.toBeUndefined();
});
});

Expand Down Expand Up @@ -1448,7 +1448,7 @@ describe("crypto", () => {

await syncPromise(aliceClient);

// Verify that `/upload` is called on Alice's homesever
// Verify that `/upload` is called on Alice's homeserver
const { keysCount, fallbackKeysCount } = await uploadPromise;
expect(keysCount).toBeGreaterThan(0);
expect(fallbackKeysCount).toBe(0);
Expand Down Expand Up @@ -1718,7 +1718,6 @@ describe("crypto", () => {
* @param backupVersion - The version of the created backup
*/
async function bootstrapSecurity(backupVersion: string): Promise<void> {
mockSetupCrossSigningRequests();
mockSetupMegolmBackupRequests(backupVersion);

// promise which will resolve when a `KeyBackupStatus` event is emitted with `enabled: true`
Expand Down
4 changes: 1 addition & 3 deletions spec/integ/crypto/megolm-backup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,7 @@ describe("megolm-keys backup", () => {
});

afterEach(async () => {
if (aliceClient !== undefined) {
await aliceClient.stopClient();
}
aliceClient?.stopClient();

// Allow in-flight things to complete before we tear down the test
await jest.runAllTimersAsync();
Expand Down
3 changes: 1 addition & 2 deletions spec/integ/crypto/state-events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ describe("Encrypted State Events", () => {
}, 10000);

afterEach(async () => {
await aliceClient.stopClient();
await jest.runAllTimersAsync();
aliceClient.stopClient();
fetchMock.mockReset();
});

Expand Down
4 changes: 1 addition & 3 deletions spec/integ/crypto/verification.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,7 @@ describe("verification", () => {
});

afterEach(async () => {
if (aliceClient !== undefined) {
await aliceClient.stopClient();
}
aliceClient?.stopClient();

// Allow in-flight things to complete before we tear down the test
await jest.runAllTimersAsync();
Expand Down
2 changes: 1 addition & 1 deletion spec/unit/autodiscovery.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ describe("AutoDiscovery", function () {
};
return Promise.all([
httpBackend.flushAllExpected(),
AutoDiscovery.findClientConfig("example.org").then(expect(expected).toEqual),
AutoDiscovery.findClientConfig("example.org").then((config) => expect(config).toEqual(expected)),
]);
});

Expand Down
4 changes: 2 additions & 2 deletions spec/unit/event-timeline-set.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ describe("EventTimelineSet", () => {
let thread: Thread;

beforeEach(() => {
(client.supportsThreads as jest.Mock).mockReturnValue(true);
mocked(client.supportsThreads).mockReturnValue(true);
thread = new Thread("!thread_id:server", messageEvent, { room, client });
});

Expand Down Expand Up @@ -384,7 +384,7 @@ describe("EventTimelineSet", () => {
let thread: Thread;

beforeEach(() => {
(client.supportsThreads as jest.Mock).mockReturnValue(true);
mocked(client.supportsThreads).mockReturnValue(true);
thread = new Thread("!thread_id:server", messageEvent, { room, client });
});

Expand Down
12 changes: 8 additions & 4 deletions spec/unit/interactive-auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.

import { type MatrixClient } from "../../src/client";
import { logger } from "../../src/logger";
import { InteractiveAuth, AuthType } from "../../src/interactive-auth";
import { InteractiveAuth, AuthType, NoAuthFlowFoundError } from "../../src/interactive-auth";
import { HTTPError, MatrixError } from "../../src/http-api";
import { sleep } from "../../src/utils";
import { secureRandomString } from "../../src/randomstring";
Expand Down Expand Up @@ -337,7 +337,9 @@ describe("InteractiveAuth", () => {
throw err;
});

await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(new Error("No appropriate authentication flow found"));
await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(
new NoAuthFlowFoundError("No appropriate authentication flow found", [], []),
);
});

it("should start an auth stage and reject if no auth flow but has session", async () => {
Expand Down Expand Up @@ -372,7 +374,9 @@ describe("InteractiveAuth", () => {
throw err;
});

await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(new Error("No appropriate authentication flow found"));
await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(
new NoAuthFlowFoundError("No appropriate authentication flow found", [], []),
);
});

it("should handle unexpected error types without data property set", async () => {
Expand All @@ -397,7 +401,7 @@ describe("InteractiveAuth", () => {
throw err;
});

await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(new Error("myerror"));
await expect(ia.attemptAuth.bind(ia)).rejects.toThrow(new HTTPError("myerror", 401));
});

it("should allow dummy auth", async () => {
Expand Down
12 changes: 7 additions & 5 deletions spec/unit/matrixrtc/CallMembership.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { type MatrixEvent } from "../../../src";
import { mocked } from "jest-mock";

import { type IContent, type MatrixEvent } from "../../../src";
import {
CallMembership,
type SessionMembershipData,
Expand All @@ -32,8 +34,8 @@ function makeMockEvent(originTs = 0): MatrixEvent {
} as unknown as MatrixEvent;
}

function createCallMembership(ev: MatrixEvent, content: unknown): CallMembership {
(ev.getContent as jest.Mock).mockReturnValue(content);
function createCallMembership(ev: MatrixEvent, content: IContent): CallMembership {
mocked(ev.getContent).mockReturnValue(content);
const data = CallMembership.membershipDataFromMatrixEvent(ev);
return new CallMembership(ev, data, "xx");
}
Expand Down Expand Up @@ -307,11 +309,11 @@ describe("CallMembership", () => {
}).toThrow();
});

it("considers memberships unexpired if local age low enough", () => {
it.skip("considers memberships unexpired if local age low enough", () => {
// TODO link prev event
});

it("considers memberships expired if local age large enough", () => {
it.skip("considers memberships expired if local age large enough", () => {
// TODO link prev event
});

Expand Down
7 changes: 7 additions & 0 deletions spec/unit/matrixrtc/MatrixRTCSession.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1345,6 +1345,13 @@ describe("MatrixRTCSession", () => {
});

describe("receiving", () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});

it("collects keys from encryption events", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForSlot(client, mockRoom, callSession);
Expand Down
8 changes: 4 additions & 4 deletions spec/unit/matrixrtc/MembershipManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ describe("MembershipManager", () => {
// Spys/Mocks

const restartScheduledDelayedEventHandle = createAsyncHandle<void>(
client._unstable_restartScheduledDelayedEvent as Mock,
client._unstable_restartScheduledDelayedEvent,
);

// Test
Expand Down Expand Up @@ -293,7 +293,7 @@ describe("MembershipManager", () => {

describe("delayed leave event", () => {
it("does not try again to schedule a delayed leave event if not supported", () => {
const delayedHandle = createAsyncHandle(client._unstable_sendDelayedStateEvent as Mock);
const delayedHandle = createAsyncHandle(client._unstable_sendDelayedStateEvent);
const manager = new MembershipManager({}, room, client, callSession);
manager.join([focus]);
delayedHandle.reject?.(
Expand All @@ -305,7 +305,7 @@ describe("MembershipManager", () => {
expect(client._unstable_sendDelayedStateEvent).toHaveBeenCalledTimes(1);
});
it("does try to schedule a delayed leave event again if rate limited", async () => {
const delayedHandle = createAsyncHandle(client._unstable_sendDelayedStateEvent as Mock);
const delayedHandle = createAsyncHandle(client._unstable_sendDelayedStateEvent);
const manager = new MembershipManager({}, room, client, callSession);
manager.join([focus]);
delayedHandle.reject?.(new HTTPError("rate limited", 429, undefined));
Expand Down Expand Up @@ -916,7 +916,7 @@ describe("MembershipManager", () => {
describe("sends an rtc membership event", () => {
it("sends a membership event and schedules delayed leave when joining a call", async () => {
const restartScheduledDelayedEventHandle = createAsyncHandle<void>(
client._unstable_restartScheduledDelayedEvent as Mock,
client._unstable_restartScheduledDelayedEvent,
);
const memberManager = new StickyEventMembershipManager(
undefined,
Expand Down
8 changes: 4 additions & 4 deletions spec/unit/matrixrtc/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ limitations under the License.
*/

import { EventEmitter } from "stream";
import { type Mocked } from "jest-mock";
import { mocked, type Mocked } from "jest-mock";

import { EventType, type Room, RoomEvent, type MatrixClient, type MatrixEvent } from "../../../src";
import { CallMembership, type SessionMembershipData } from "../../../src/matrixrtc";
Expand Down Expand Up @@ -72,8 +72,8 @@ export type MockClient = Pick<
*/
export function makeMockClient(userId: string, deviceId: string): MockClient {
return {
getDeviceId: () => deviceId,
getUserId: () => userId,
getDeviceId: jest.fn(() => deviceId),
getUserId: jest.fn(() => userId),
sendEvent: jest.fn(),
sendStateEvent: jest.fn(),
cancelPendingEvent: jest.fn(),
Expand Down Expand Up @@ -194,7 +194,7 @@ export function mockCallMembership(
rtcBackendIdentity?: string,
): CallMembership {
const ev = mockRTCEvent(membershipData, roomId);
(ev.getContent as jest.Mock).mockReturnValue(membershipData);
mocked(ev.getContent).mockReturnValue(membershipData);
const data = CallMembership.membershipDataFromMatrixEvent(ev);
return new CallMembership(ev, data, rtcBackendIdentity ?? "xx", logger);
}
Expand Down
18 changes: 15 additions & 3 deletions spec/unit/models/event.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ describe("MatrixEvent", () => {

// Then it disappears from the thread and appears in the main timeline
expect(ev.threadRootId).toBeUndefined();
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId(), ev.getId()]);
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId(), ev.getId(), redaction.getId()]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is strange.. Isn't it more that redaction.getId() is undefined?
like expect([1,2]).toEqual([1,2, undefined]);

Maybe these test could use things like expect.arrayContaining([threadRoot.getId(), ev.getId()]) ?

Copy link
Copy Markdown
Member Author

@t3chguy t3chguy Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, redaction before this PR had an undefined ID which jest allows you to skip in toEqual - vitest was unhappy and I thought that given real redactions have event IDs it'd make sense to make them have IDs in test too and assert them correctly

arrayContaining wouldn't assert order

expect(threadLiveEventIds(room, 0)).not.toContain(ev.getId());
});

Expand All @@ -183,7 +183,12 @@ describe("MatrixEvent", () => {

// Then the reaction moves into the main timeline
expect(reaction.threadRootId).toBeUndefined();
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId(), ev.getId(), reaction.getId()]);
expect(mainTimelineLiveEventIds(room)).toEqual([
threadRoot.getId(),
ev.getId(),
reaction.getId(),
redaction.getId(),
]);
expect(threadLiveEventIds(room, 0)).not.toContain(reaction.getId());
});

Expand All @@ -207,7 +212,12 @@ describe("MatrixEvent", () => {

// Then the edit moves into the main timeline
expect(edit.threadRootId).toBeUndefined();
expect(mainTimelineLiveEventIds(room)).toEqual([threadRoot.getId(), ev.getId(), edit.getId()]);
expect(mainTimelineLiveEventIds(room)).toEqual([
threadRoot.getId(),
ev.getId(),
edit.getId(),
redaction.getId(),
]);
expect(threadLiveEventIds(room, 0)).not.toContain(edit.getId());
});

Expand Down Expand Up @@ -245,6 +255,7 @@ describe("MatrixEvent", () => {
reply1.getId(),
reply2.getId(),
reaction.getId(),
redaction.getId(),
]);
expect(threadLiveEventIds(room, 0)).not.toContain(reply1.getId());
expect(threadLiveEventIds(room, 0)).not.toContain(reply2.getId());
Expand Down Expand Up @@ -330,6 +341,7 @@ describe("MatrixEvent", () => {

function createRedaction(redactedEventid: string): MatrixEvent {
return new MatrixEvent({
event_id: `$redact-${redactedEventid}`,
type: "m.room.redaction",
redacts: redactedEventid,
});
Expand Down
18 changes: 1 addition & 17 deletions spec/unit/oidc/authorize.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ describe("oidc authorization", () => {

beforeAll(() => {
jest.spyOn(logger, "warn");
jest.useFakeTimers();
jest.setSystemTime(now);

fetchMock.get(delegatedAuthConfig.issuer + ".well-known/openid-configuration", mockOpenIdConfiguration());
Expand Down Expand Up @@ -212,21 +213,6 @@ describe("oidc authorization", () => {
sub: "123",
};

const mockSessionStorage = (state: Record<string, unknown>): void => {
jest.spyOn(sessionStorage.__proto__, "getItem").mockImplementation((key: unknown) => {
return state[key as string] ?? null;
});
jest.spyOn(sessionStorage.__proto__, "setItem").mockImplementation(
// @ts-ignore mock type
(key: string, value: unknown) => (state[key] = value),
);
jest.spyOn(sessionStorage.__proto__, "removeItem").mockImplementation((key: unknown) => {
const { [key as string]: value, ...newState } = state;
state = newState;
return value;
});
};

const getValueFromStorage = <T = string>(state: string, key: string): T => {
const storedState = window.sessionStorage.getItem(`mx_oidc_${state}`)!;
return JSON.parse(storedState)[key] as unknown as T;
Expand Down Expand Up @@ -279,8 +265,6 @@ describe("oidc authorization", () => {
keys: [],
});

mockSessionStorage({});

mocked(jwtDecode).mockReturnValue(validDecodedIdToken);
});

Expand Down
Loading