diff --git a/src/button/ReactionToggleButton.test.tsx b/src/button/ReactionToggleButton.test.tsx index 269eabed..b1af7ec8 100644 --- a/src/button/ReactionToggleButton.test.tsx +++ b/src/button/ReactionToggleButton.test.tsx @@ -10,7 +10,6 @@ import { expect, test } from "vitest"; import { TooltipProvider } from "@vector-im/compound-web"; import { userEvent } from "@testing-library/user-event"; import { type ReactNode } from "react"; -import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc"; import { ReactionToggleButton } from "./ReactionToggleButton"; import { ElementCallReactionEventType } from "../reactions"; @@ -33,7 +32,7 @@ function TestComponent({ diff --git a/src/reactions/ReactionsReader.test.tsx b/src/reactions/ReactionsReader.test.tsx index b8acf5c7..01815c82 100644 --- a/src/reactions/ReactionsReader.test.tsx +++ b/src/reactions/ReactionsReader.test.tsx @@ -7,7 +7,6 @@ Please see LICENSE in the repository root for full details. import { renderHook } from "@testing-library/react"; import { afterEach, test, vitest } from "vitest"; -import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc"; import { RoomEvent as MatrixRoomEvent, MatrixEvent, @@ -38,7 +37,7 @@ test("handles a hand raised reaction", () => { withTestScheduler(({ schedule, expectObservable }) => { renderHook(() => { const { raisedHands$ } = new ReactionsReader( - rtcSession as unknown as MatrixRTCSession, + rtcSession.asMockedSession(), ); schedule("ab", { a: () => {}, @@ -86,7 +85,7 @@ test("handles a redaction", () => { withTestScheduler(({ schedule, expectObservable }) => { renderHook(() => { const { raisedHands$ } = new ReactionsReader( - rtcSession as unknown as MatrixRTCSession, + rtcSession.asMockedSession(), ); schedule("abc", { a: () => {}, @@ -149,7 +148,7 @@ test("handles waiting for event decryption", () => { withTestScheduler(({ schedule, expectObservable }) => { renderHook(() => { const { raisedHands$ } = new ReactionsReader( - rtcSession as unknown as MatrixRTCSession, + rtcSession.asMockedSession(), ); schedule("abc", { a: () => {}, @@ -218,7 +217,7 @@ test("hands rejecting events without a proper membership", () => { withTestScheduler(({ schedule, expectObservable }) => { renderHook(() => { const { raisedHands$ } = new ReactionsReader( - rtcSession as unknown as MatrixRTCSession, + rtcSession.asMockedSession(), ); schedule("ab", { a: () => {}, @@ -262,9 +261,7 @@ test("handles a reaction", () => { withTestScheduler(({ schedule, time, expectObservable }) => { renderHook(() => { - const { reactions$ } = new ReactionsReader( - rtcSession as unknown as MatrixRTCSession, - ); + const { reactions$ } = new ReactionsReader(rtcSession.asMockedSession()); schedule(`abc`, { a: () => {}, b: () => { @@ -320,9 +317,7 @@ test("ignores bad reaction events", () => { withTestScheduler(({ schedule, expectObservable }) => { renderHook(() => { - const { reactions$ } = new ReactionsReader( - rtcSession as unknown as MatrixRTCSession, - ); + const { reactions$ } = new ReactionsReader(rtcSession.asMockedSession()); schedule("ab", { a: () => {}, b: () => { @@ -444,9 +439,7 @@ test("that reactions cannot be spammed", () => { withTestScheduler(({ schedule, expectObservable }) => { renderHook(() => { - const { reactions$ } = new ReactionsReader( - rtcSession as unknown as MatrixRTCSession, - ); + const { reactions$ } = new ReactionsReader(rtcSession.asMockedSession()); schedule("abcd", { a: () => {}, b: () => { diff --git a/src/room/GroupCallView.test.tsx b/src/room/GroupCallView.test.tsx index ea14f5cf..37f5c850 100644 --- a/src/room/GroupCallView.test.tsx +++ b/src/room/GroupCallView.test.tsx @@ -117,7 +117,7 @@ function createGroupCallView( widget: WidgetHelpers | null, joined = true, ): { - rtcSession: MockRTCSession; + rtcSession: MatrixRTCSession; getByText: ReturnType["getByText"]; } { const client = { @@ -164,7 +164,7 @@ function createGroupCallView( preload={false} skipLobby={false} header={HeaderStyle.Standard} - rtcSession={rtcSession as unknown as MatrixRTCSession} + rtcSession={rtcSession.asMockedSession()} muteStates={muteState} widget={widget} // TODO-MULTI-SFU: Make joined and setJoined work @@ -178,7 +178,7 @@ function createGroupCallView( ); return { getByText, - rtcSession, + rtcSession: rtcSession.asMockedSession(), }; } diff --git a/src/room/InCallView.test.tsx b/src/room/InCallView.test.tsx index 131259da..6b897c0d 100644 --- a/src/room/InCallView.test.tsx +++ b/src/room/InCallView.test.tsx @@ -15,7 +15,6 @@ import { } from "vitest"; import { act, render, type RenderResult } from "@testing-library/react"; import { type MatrixClient, JoinRule, type RoomState } from "matrix-js-sdk"; -import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc"; import { type RelationsContainer } from "matrix-js-sdk/lib/models/relations-container"; import { type LocalParticipant } from "livekit-client"; import { of } from "rxjs"; @@ -154,14 +153,14 @@ function createInCallView(): RenderResult & { >({}); const vm = new CallViewModel( - rtcSession as unknown as MatrixRTCSession, + rtcSession.asMockedSession(), room, mediaDevices, muteStates, diff --git a/src/state/CallViewModel.ts b/src/state/CallViewModel.ts index 4cb97519..c3cf7ff3 100644 --- a/src/state/CallViewModel.ts +++ b/src/state/CallViewModel.ts @@ -541,7 +541,9 @@ export class CallViewModel extends ViewModel { const oldest = this.matrixRTCSession.getOldestMembership(); if (oldest !== undefined) { const selection = oldest.getTransport(oldest); - if (isLivekitTransport(selection)) local = ready(selection); + // TODO selection can be null if no transport is configured should we report an error? + if (selection && isLivekitTransport(selection)) + local = ready(selection); } } return { local, remote }; @@ -721,8 +723,8 @@ export class CallViewModel extends ViewModel { ), ); - private readonly userId = this.matrixRoom.client.getUserId(); - private readonly deviceId = this.matrixRoom.client.getDeviceId(); + private readonly userId = this.matrixRoom.client.getUserId()!; + private readonly deviceId = this.matrixRoom.client.getDeviceId()!; private readonly matrixConnected$ = this.scope.behavior( // To consider ourselves connected to MatrixRTC, we check the following: @@ -906,7 +908,11 @@ export class CallViewModel extends ViewModel { ], (memberships, _displaynames) => { const displaynameMap = new Map([ - ["local", this.matrixRoom.getMember(this.userId!)!.rawDisplayName], + [ + "local", + this.matrixRoom.getMember(this.userId)?.rawDisplayName ?? + this.userId, + ], ]); const room = this.matrixRoom; diff --git a/src/utils/test-viewmodel.ts b/src/utils/test-viewmodel.ts index 785cbe1b..1b4d0cf0 100644 --- a/src/utils/test-viewmodel.ts +++ b/src/utils/test-viewmodel.ts @@ -5,10 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ -import { - type CallMembership, - type MatrixRTCSession, -} from "matrix-js-sdk/lib/matrixrtc"; +import { type CallMembership } from "matrix-js-sdk/lib/matrixrtc"; import { BehaviorSubject, of } from "rxjs"; import { vitest } from "vitest"; import { type RelationsContainer } from "matrix-js-sdk/lib/models/relations-container"; @@ -99,12 +96,12 @@ export function getBasicRTCSession( initialRtcMemberships, ); - const rtcSession = new MockRTCSession(matrixRoom).withMemberships( + const fakeRtcSession = new MockRTCSession(matrixRoom).withMemberships( rtcMemberships$, ); return { - rtcSession, + rtcSession: fakeRtcSession, matrixRoom, rtcMemberships$, }; @@ -137,7 +134,7 @@ export function getBasicCallViewModelEnvironment( // const remoteParticipants$ = of([aliceParticipant]); const vm = new CallViewModel( - rtcSession as unknown as MatrixRTCSession, + rtcSession.asMockedSession(), matrixRoom, mockMediaDevices({}), mockMuteStates(), diff --git a/src/utils/test.ts b/src/utils/test.ts index 508559c2..cc057532 100644 --- a/src/utils/test.ts +++ b/src/utils/test.ts @@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details. */ import { map, type Observable, of, type SchedulerLike } from "rxjs"; import { type RunHelpers, TestScheduler } from "rxjs/testing"; -import { expect, vi, vitest } from "vitest"; +import { expect, type MockedObject, vi, vitest } from "vitest"; import { type RoomMember, type Room as MatrixRoom, @@ -23,6 +23,7 @@ import { type SessionMembershipData, Status, type LivekitFocusSelection, + type MatrixRTCSession, } from "matrix-js-sdk/lib/matrixrtc"; import { type MembershipManagerEventHandlerMap } from "matrix-js-sdk/lib/matrixrtc/IMembershipManager"; import { @@ -193,7 +194,9 @@ export function mockRtcMembership( sender: typeof user === "string" ? user : user.userId, event_id: `$-ev-${randomUUID()}:example.org`, }); - return new CallMembership(event, data); + const cms = new CallMembership(event, data); + vi.mocked(cms).getTransport = vi.fn().mockReturnValue(fociPreferred[0]); + return cms; } // Maybe it'd be good to move this to matrix-js-sdk? Our testing needs are @@ -209,6 +212,7 @@ export function mockMatrixRoomMember( getMxcAvatarUrl(): string | undefined { return undefined; }, + rawDisplayName: rtcMembership.sender, ...member, } as RoomMember; } @@ -335,6 +339,22 @@ export class MockRTCSession extends TypedEventEmitter< RoomAndToDeviceEventsHandlerMap & MembershipManagerEventHandlerMap > { + public asMockedSession(): MockedObject { + const session = this as unknown as MockedObject; + + vi.mocked(session).reemitEncryptionKeys = vi + .fn<() => void>() + .mockReturnValue(undefined); + vi.mocked(session).resolveActiveFocus = vi + .fn<(member?: CallMembership) => Transport | undefined>() + .mockReturnValue(undefined); + vi.mocked(session).getOldestMembership = vi + .fn<() => CallMembership | undefined>() + .mockReturnValue(this.memberships[0]); + + return session; + } + public readonly statistics = { counters: {}, };