mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-22 22:29:30 +00:00
Element Call reached the widget API through a mutable module-level binding, which every consumer imported directly. Nothing outside the app shell needs it any more, so hand it back from initializeWidget and thread it through: the initializer returns it, main passes it to App, and App uses it to build the host bridge and to await the client the host is lending us. ClientContext's loadClient is now only about restoring or creating a session of Element Call's own, since a widget's client arrives as a prop like any other host's would. Also fixes an early return added in the previous commit, which skipped starting the analytics settings listener when a client was supplied. That was harmless until now, but would have stopped analytics following the user's choices in widget mode. sdk/main.ts asked the host to close by hand; it now uses the bridge, which also stops the transport as the app does.
164 lines
4.9 KiB
TypeScript
164 lines
4.9 KiB
TypeScript
/*
|
|
Copyright 2026 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import { describe, expect, vi, it, beforeEach } from "vitest";
|
|
import { createRoomWidgetClient, EventType } from "matrix-js-sdk";
|
|
|
|
import { getUrlParams } from "./UrlParams";
|
|
import { initializeWidget } from "./widget";
|
|
import { Config } from "./config/Config";
|
|
import { ElementCallReactionEventType } from "./reactions";
|
|
|
|
vi.mock("matrix-js-sdk", { spy: true });
|
|
const createRoomWidgetClientSpy = vi.mocked(createRoomWidgetClient);
|
|
|
|
vi.mock("./config/Config", () => ({
|
|
Config: {
|
|
init: vi.fn().mockImplementation(async () => Promise.resolve()),
|
|
get: vi.fn().mockReturnValue({}),
|
|
},
|
|
}));
|
|
const configInitSpy = vi.mocked(Config.init);
|
|
|
|
vi.mock("./UrlParams", () => ({
|
|
getUrlParams: vi.fn(() => ({
|
|
widgetId: "id",
|
|
parentUrl: "http://parentUrl",
|
|
roomId: "room",
|
|
userId: "myYser",
|
|
deviceId: "AAAAA",
|
|
baseUrl: "http://baseUrl",
|
|
e2eEnabled: true,
|
|
})),
|
|
}));
|
|
|
|
beforeEach(() => {
|
|
createRoomWidgetClientSpy.mockClear();
|
|
});
|
|
|
|
describe("widget", () => {
|
|
it("should create an embedded client with the correct params", () => {
|
|
const widget = initializeWidget("ANYRTCAPP");
|
|
|
|
expect(getUrlParams()).toStrictEqual({
|
|
widgetId: "id",
|
|
parentUrl: "http://parentUrl",
|
|
roomId: "room",
|
|
userId: "myYser",
|
|
deviceId: "AAAAA",
|
|
baseUrl: "http://baseUrl",
|
|
e2eEnabled: true,
|
|
});
|
|
expect(widget).toBeDefined();
|
|
expect(configInitSpy).toHaveBeenCalled();
|
|
const sendEvent = [
|
|
EventType.CallNotify, // Sent as a deprecated fallback
|
|
EventType.RTCNotification,
|
|
];
|
|
const sendRecvEvent = [
|
|
"org.matrix.rageshake_request",
|
|
EventType.CallEncryptionKeysPrefix,
|
|
EventType.Reaction,
|
|
EventType.RoomRedaction,
|
|
ElementCallReactionEventType,
|
|
EventType.RTCDecline,
|
|
EventType.RTCMembership,
|
|
];
|
|
|
|
const sendState = [
|
|
{ eventType: "org.matrix.msc3401.call.member", stateKey: "myYser" }, // Legacy call membership events
|
|
{
|
|
eventType: "org.matrix.msc3401.call.member",
|
|
stateKey: `_myYser_AAAAA_ANYRTCAPP`,
|
|
}, // Session membership events
|
|
{
|
|
eventType: "org.matrix.msc3401.call.member",
|
|
stateKey: `myYser_AAAAA_ANYRTCAPP`,
|
|
}, // The above with no leading underscore, for room versions whose auth rules allow it
|
|
];
|
|
const receiveState = [
|
|
{ eventType: EventType.RoomCreate },
|
|
{ eventType: EventType.RoomName },
|
|
{ eventType: EventType.RoomMember },
|
|
{ eventType: EventType.RoomEncryption },
|
|
{ eventType: EventType.GroupCallMemberPrefix },
|
|
];
|
|
|
|
const sendRecvToDevice = [
|
|
EventType.CallInvite,
|
|
EventType.CallCandidates,
|
|
EventType.CallAnswer,
|
|
EventType.CallHangup,
|
|
EventType.CallReject,
|
|
EventType.CallSelectAnswer,
|
|
EventType.CallNegotiate,
|
|
EventType.CallSDPStreamMetadataChanged,
|
|
EventType.CallSDPStreamMetadataChangedPrefix,
|
|
EventType.CallReplaces,
|
|
EventType.CallEncryptionKeysPrefix,
|
|
];
|
|
|
|
expect(createRoomWidgetClientSpy.mock.calls[0][1]).toStrictEqual({
|
|
sendEvent: [...sendEvent, ...sendRecvEvent],
|
|
receiveEvent: sendRecvEvent,
|
|
sendState,
|
|
receiveState,
|
|
sendToDevice: sendRecvToDevice,
|
|
receiveToDevice: sendRecvToDevice,
|
|
turnServers: false,
|
|
rtcTransports: true,
|
|
sendDelayedEvents: true,
|
|
updateDelayedEvents: true,
|
|
sendSticky: true,
|
|
receiveSticky: true,
|
|
});
|
|
|
|
expect(createRoomWidgetClientSpy.mock.calls[0][2]).toStrictEqual("room");
|
|
expect(createRoomWidgetClientSpy.mock.calls[0][3]).toStrictEqual({
|
|
baseUrl: "http://baseUrl",
|
|
userId: "myYser",
|
|
deviceId: "AAAAA",
|
|
timelineSupport: true,
|
|
useE2eForGroupCall: true,
|
|
fallbackICEServerAllowed: undefined,
|
|
store: expect.any(Object),
|
|
cryptoStore: expect.any(Object),
|
|
idBaseUrl: undefined,
|
|
scheduler: expect.any(Object),
|
|
});
|
|
expect(createRoomWidgetClientSpy.mock.calls[0][4]).toStrictEqual(false);
|
|
});
|
|
|
|
it("should request send message permission if requested", () => {
|
|
initializeWidget("ANYRTCAPP", true);
|
|
expect(createRoomWidgetClientSpy).toHaveBeenLastCalledWith(
|
|
expect.anything(),
|
|
// capabilities
|
|
expect.objectContaining({
|
|
sendEvent: expect.arrayContaining(["m.room.message"]),
|
|
}),
|
|
expect.anything(),
|
|
expect.anything(),
|
|
expect.anything(),
|
|
);
|
|
});
|
|
|
|
it("should not request send message permission when not requested", () => {
|
|
initializeWidget("", false);
|
|
expect(createRoomWidgetClientSpy).toHaveBeenLastCalledWith(
|
|
expect.anything(),
|
|
// capabilities
|
|
expect.objectContaining({
|
|
sendEvent: expect.not.arrayContaining(["m.room.message"]),
|
|
}),
|
|
expect.anything(),
|
|
expect.anything(),
|
|
expect.anything(),
|
|
);
|
|
});
|
|
});
|