Avoid closing the widget in returnToLobby mode

If returnToLobby is enabled then we obviously want to keep the widget open once the user leaves the call.
This commit is contained in:
Robin
2025-03-04 15:09:59 -05:00
parent b5f5edba09
commit 28c45c6107
4 changed files with 42 additions and 24 deletions

View File

@@ -110,8 +110,8 @@ describe("UrlParams", () => {
}); });
describe("returnToLobby", () => { describe("returnToLobby", () => {
it("is true in SPA mode", () => { it("is false in SPA mode", () => {
expect(getUrlParams("?returnToLobby=false").returnToLobby).toBe(true); expect(getUrlParams("?returnToLobby=true").returnToLobby).toBe(false);
}); });
it("defaults to false in widget mode", () => { it("defaults to false in widget mode", () => {

View File

@@ -264,7 +264,7 @@ export const getUrlParams = (
"skipLobby", "skipLobby",
isWidget && intent === UserIntent.StartNewCall, isWidget && intent === UserIntent.StartNewCall,
), ),
returnToLobby: isWidget ? parser.getFlagParam("returnToLobby") : true, returnToLobby: isWidget ? parser.getFlagParam("returnToLobby") : false,
theme: parser.getParam("theme"), theme: parser.getParam("theme"),
viaServers: !isWidget ? parser.getParam("viaServers") : null, viaServers: !isWidget ? parser.getParam("viaServers") : null,
homeserver: !isWidget ? parser.getParam("homeserver") : null, homeserver: !isWidget ? parser.getParam("homeserver") : null,

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/ */
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { expect, test, vi } from "vitest"; import { expect, onTestFinished, test, vi } from "vitest";
import { AutoDiscovery } from "matrix-js-sdk/src/autodiscovery"; import { AutoDiscovery } from "matrix-js-sdk/src/autodiscovery";
import EventEmitter from "events"; import EventEmitter from "events";
@@ -15,11 +15,17 @@ import { mockConfig } from "./utils/test";
import { ElementWidgetActions, widget } from "./widget"; import { ElementWidgetActions, widget } from "./widget";
import { ErrorCode } from "./utils/errors.ts"; import { ErrorCode } from "./utils/errors.ts";
const getUrlParams = vi.hoisted(() => vi.fn(() => ({})));
vi.mock("./UrlParams", () => ({ getUrlParams }));
const actualWidget = await vi.hoisted(async () => vi.importActual("./widget")); const actualWidget = await vi.hoisted(async () => vi.importActual("./widget"));
vi.mock("./widget", () => ({ vi.mock("./widget", () => ({
...actualWidget, ...actualWidget,
widget: { widget: {
api: { transport: { send: vi.fn(), reply: vi.fn(), stop: vi.fn() } }, api: {
setAlwaysOnScreen: (): void => {},
transport: { send: vi.fn(), reply: vi.fn(), stop: vi.fn() },
},
lazyActions: new EventEmitter(), lazyActions: new EventEmitter(),
}, },
})); }));
@@ -109,34 +115,45 @@ test("It joins the correct Session", async () => {
); );
}); });
test("leaveRTCSession closes the widget on a normal hangup", async () => { async function testLeaveRTCSession(
cause: "user" | "error",
expectClose: boolean,
): Promise<void> {
vi.clearAllMocks(); vi.clearAllMocks();
const session = { leaveRoomSession: vi.fn() } as unknown as MatrixRTCSession; const session = { leaveRoomSession: vi.fn() } as unknown as MatrixRTCSession;
await leaveRTCSession(session, "user"); await leaveRTCSession(session, cause);
expect(session.leaveRoomSession).toHaveBeenCalled(); expect(session.leaveRoomSession).toHaveBeenCalled();
expect(widget!.api.transport.send).toHaveBeenCalledWith( expect(widget!.api.transport.send).toHaveBeenCalledWith(
ElementWidgetActions.HangupCall, ElementWidgetActions.HangupCall,
expect.anything(), expect.anything(),
); );
expect(widget!.api.transport.send).toHaveBeenCalledWith( if (expectClose) {
ElementWidgetActions.Close, expect(widget!.api.transport.send).toHaveBeenCalledWith(
expect.anything(), ElementWidgetActions.Close,
); expect.anything(),
);
expect(widget!.api.transport.stop).toHaveBeenCalled();
} else {
expect(widget!.api.transport.send).not.toHaveBeenCalledWith(
ElementWidgetActions.Close,
expect.anything(),
);
expect(widget!.api.transport.stop).not.toHaveBeenCalled();
}
}
test("leaveRTCSession closes the widget on a normal hangup", async () => {
await testLeaveRTCSession("user", true);
}); });
test("leaveRTCSession doesn't close the widget on a fatal error", async () => { test("leaveRTCSession doesn't close the widget on a fatal error", async () => {
vi.clearAllMocks(); await testLeaveRTCSession("error", false);
const session = { leaveRoomSession: vi.fn() } as unknown as MatrixRTCSession; });
await leaveRTCSession(session, "error");
expect(session.leaveRoomSession).toHaveBeenCalled(); test("leaveRTCSession doesn't close the widget when returning to lobby", async () => {
expect(widget!.api.transport.send).toHaveBeenCalledWith( getUrlParams.mockReturnValue({ returnToLobby: true });
ElementWidgetActions.HangupCall, onTestFinished(() => void getUrlParams.mockReset());
expect.anything(), await testLeaveRTCSession("user", false);
);
expect(widget!.api.transport.send).not.toHaveBeenCalledWith(
ElementWidgetActions.Close,
expect.anything(),
);
}); });
test("It fails with configuration error if no live kit url config is set in fallback", async () => { test("It fails with configuration error if no live kit url config is set in fallback", async () => {

View File

@@ -19,6 +19,7 @@ import { PosthogAnalytics } from "./analytics/PosthogAnalytics";
import { Config } from "./config/Config"; import { Config } from "./config/Config";
import { ElementWidgetActions, widget, type WidgetHelpers } from "./widget"; import { ElementWidgetActions, widget, type WidgetHelpers } from "./widget";
import { MatrixRTCFocusMissingError } from "./utils/errors.ts"; import { MatrixRTCFocusMissingError } from "./utils/errors.ts";
import { getUrlParams } from "./UrlParams.ts";
const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci"; const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci";
@@ -149,7 +150,7 @@ const widgetPostHangupProcedure = async (
} }
// On a normal user hangup we can shut down and close the widget. But if an // On a normal user hangup we can shut down and close the widget. But if an
// error occurs we should keep the widget open until the user reads it. // error occurs we should keep the widget open until the user reads it.
if (cause === "user") { if (cause === "user" && !getUrlParams().returnToLobby) {
try { try {
await widget.api.transport.send(ElementWidgetActions.Close, {}); await widget.api.transport.send(ElementWidgetActions.Close, {});
} catch (e) { } catch (e) {