diff --git a/src/room/GroupCallView.test.tsx b/src/room/GroupCallView.test.tsx index 1c4f2462a..92c27077f 100644 --- a/src/room/GroupCallView.test.tsx +++ b/src/room/GroupCallView.test.tsx @@ -38,7 +38,6 @@ import { useAudioContext } from "../useAudioContext"; import { ActiveCall } from "./InCallView"; import { flushPromises, - mockConfig, mockEmitter, mockMatrixRoom, mockMatrixRoomMember, @@ -51,7 +50,6 @@ import { GroupCallErrorBoundary } from "./GroupCallErrorBoundary"; import { ElementWidgetActions, type WidgetHelpers } from "../widget"; import { LazyEventEmitter } from "../LazyEventEmitter"; import { MatrixRTCTransportMissingError } from "../utils/errors"; -import { MatrixRTCMode } from "../config/ConfigOptions"; import { ProcessorProvider } from "../livekit/TrackProcessorContext"; import { MediaDevicesContext } from "../MediaDevicesContext"; import { constant } from "../state/Behavior"; @@ -134,7 +132,6 @@ function createGroupCallView( widget: WidgetHelpers | null, joined = true, options: { - doesServerSupportUnstableFeature?: (feature: string) => Promise; withErrorBoundary?: boolean; } = {}, ): { @@ -146,9 +143,6 @@ function createGroupCallView( getUserId: () => localRtcMember.userId, getDeviceId: () => localRtcMember.deviceId, getRoom: (rId) => (rId === roomId ? room : null), - doesServerSupportUnstableFeature: - options.doesServerSupportUnstableFeature ?? - vi.fn().mockResolvedValue(true), } as Partial as MatrixClient; const room = mockMatrixRoom({ relations: { @@ -416,28 +410,37 @@ test.skip("GroupCallView shows errors that occur during joining", async () => { screen.getByText("Call is not supported"); }); -test("shows StickyEventsRequiredError when matrix_2_0 is forced but homeserver lacks MSC4354", async () => { - mockConfig({ matrix_rtc_mode: MatrixRTCMode.Matrix_2_0 }); - createGroupCallView(null, true, { - doesServerSupportUnstableFeature: vi.fn().mockResolvedValue(false), +test("translates UnsupportedStickyEventsEndpointError to the StickyEventsRequiredError screen", async () => { + // Match the shape the SDK emits on + // MatrixRTCSessionEvent.MembershipManagerError when matrix_2_0 mode is + // configured but the homeserver does not advertise MSC4354. + const stickyError = new Error("Server does not support the sticky events"); + stickyError.name = "UnsupportedStickyEventsEndpointError"; + + const { rtcSession } = createGroupCallView(null, true, { withErrorBoundary: true, }); + + await act(() => + rtcSession.emit(MatrixRTCSessionEvent.MembershipManagerError, stickyError), + ); + await screen.findByText("Homeserver does not support Matrix 2.0 calls"); }); -test("does not show StickyEventsRequiredError when homeserver supports MSC4354", async () => { - mockConfig({ matrix_rtc_mode: MatrixRTCMode.Matrix_2_0 }); - const { getByText } = createGroupCallView(null, true, { - doesServerSupportUnstableFeature: vi.fn().mockResolvedValue(true), +test("falls back to ConnectionLostError for unrecognised membership manager errors", async () => { + const { rtcSession } = createGroupCallView(null, true, { withErrorBoundary: true, }); - // Give the async support check a chance to resolve. - await flushPromises(); - expect( - screen.queryByText("Homeserver does not support Matrix 2.0 calls"), - ).toBeNull(); - // The normal call UI (mocked ActiveCall) renders instead. - expect(getByText("Leave")).toBeInTheDocument(); + + await act(() => + rtcSession.emit( + MatrixRTCSessionEvent.MembershipManagerError, + new Error("something else broke"), + ), + ); + + await screen.findByText("Connection lost"); }); test("user can reconnect after a membership manager error", async () => { diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 7fa47551e..0879efda8 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -13,12 +13,7 @@ import { useMemo, useState, } from "react"; -import { - type MatrixClient, - JoinRule, - type Room, - UNSTABLE_MSC4354_STICKY_EVENTS, -} from "matrix-js-sdk"; +import { type MatrixClient, JoinRule, type Room } from "matrix-js-sdk"; import { Room as LivekitRoom, isE2EESupported as isE2EESupportedBrowser, @@ -75,8 +70,6 @@ import { StickyEventsRequiredError, UnknownCallError, } from "../utils/errors.ts"; -import { Config } from "../config/Config.ts"; -import { MatrixRTCMode } from "../config/ConfigOptions.ts"; import { GroupCallErrorBoundary } from "./GroupCallErrorBoundary.tsx"; import { useTypedEventEmitter } from "../useEvents"; import { muteAllAudio$ } from "../state/MuteAllAudioModel.ts"; @@ -170,30 +163,21 @@ export const GroupCallView: FC = ({ useTypedEventEmitter( rtcSession, MatrixRTCSessionEvent.MembershipManagerError, - (error) => setExternalError(new ConnectionLostError()), + (error) => { + // The SDK throws this typed error when matrix_rtc_mode=matrix_2_0 is in + // effect but the homeserver does not advertise MSC4354 (sticky events). + // Surface the actual cause instead of a generic connection-lost screen. + if ( + error instanceof Error && + error.name === "UnsupportedStickyEventsEndpointError" + ) { + setExternalError(new StickyEventsRequiredError()); + } else { + setExternalError(new ConnectionLostError()); + } + }, ); - // If the deployment pins matrix_rtc_mode=matrix_2_0 but this homeserver - // doesn't advertise MSC4354 (sticky events), the call will fail to connect - // with a generic "Connection lost" message. Surface the real cause up front. - useEffect(() => { - if (Config.get().matrix_rtc_mode !== MatrixRTCMode.Matrix_2_0) return; - let cancelled = false; - client - .doesServerSupportUnstableFeature(UNSTABLE_MSC4354_STICKY_EVENTS) - .then((supported) => { - if (!cancelled && !supported) { - setExternalError(new StickyEventsRequiredError()); - } - }) - .catch((e) => { - logger.warn("Failed to check sticky-events homeserver support", e); - }); - return (): void => { - cancelled = true; - }; - }, [client]); - useEffect(() => { // Sanity check the room object if (client.getRoom(rtcSession.room.roomId) !== rtcSession.room)