Skip to content

Commit 12bda78

Browse files
committed
Add a test demonstrating a regression in Call.start
1 parent cb5f9ec commit 12bda78

1 file changed

Lines changed: 49 additions & 2 deletions

File tree

test/unit-tests/models/Call-test.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import { Anonymity, PosthogAnalytics } from "../../../src/PosthogAnalytics";
4848
import { type SettingKey } from "../../../src/settings/Settings.tsx";
4949
import SdkConfig from "../../../src/SdkConfig.ts";
5050
import DMRoomMap from "../../../src/utils/DMRoomMap.ts";
51-
import { type WidgetMessaging } from "../../../src/stores/widgets/WidgetMessaging.ts";
51+
import { WidgetMessagingEvent, type WidgetMessaging } from "../../../src/stores/widgets/WidgetMessaging.ts";
5252

5353
const { enabledSettings } = enableCalls();
5454

@@ -724,20 +724,67 @@ describe("ElementCall", () => {
724724
});
725725

726726
afterEach(() => cleanUpCallAndWidget(call, widget));
727+
727728
// TODO refactor initial device configuration to use the EW settings.
728729
// Add tests for passing EW device configuration to the widget.
729-
it("waits for messaging when starting", async () => {
730+
731+
it("waits for messaging when starting (widget API available immediately)", async () => {
730732
// Temporarily remove the messaging to simulate connecting while the
731733
// widget is still initializing
734+
WidgetMessagingStore.instance.stopMessaging(widget, room.roomId);
735+
expect(call.connectionState).toBe(ConnectionState.Disconnected);
736+
737+
const startup = call.start({});
738+
WidgetMessagingStore.instance.storeMessaging(widget, room.roomId, messaging);
739+
await startup;
740+
await connect(call, widgetApi, false);
741+
expect(call.connectionState).toBe(ConnectionState.Connected);
742+
});
732743

744+
it("waits for messaging when starting (widget API started asynchronously)", async () => {
745+
// Temporarily remove the messaging to simulate connecting while the
746+
// widget is still initializing
733747
WidgetMessagingStore.instance.stopMessaging(widget, room.roomId);
748+
// Also remove the widget API from said messaging until later
749+
let storedWidgetApi: Mocked<ClientWidgetApi> | null = null;
750+
Object.defineProperty(messaging, "widgetApi", {
751+
get() {
752+
return storedWidgetApi;
753+
},
754+
});
755+
expect(call.connectionState).toBe(ConnectionState.Disconnected);
756+
757+
const startup = call.start({});
758+
WidgetMessagingStore.instance.storeMessaging(widget, room.roomId, messaging);
759+
// Yield the event loop to the Call.start promise, then simulate the
760+
// widget API being started asynchronously
761+
await Promise.resolve();
762+
storedWidgetApi = widgetApi;
763+
messaging.emit(WidgetMessagingEvent.Start, storedWidgetApi);
764+
await startup;
765+
await connect(call, widgetApi, false);
766+
expect(call.connectionState).toBe(ConnectionState.Connected);
767+
});
768+
769+
it("waits for messaging when starting (even if messaging is replaced during startup)", async () => {
770+
const firstMessaging = messaging;
771+
// Entirely remove the widget API from this first messaging
772+
Object.defineProperty(firstMessaging, "widgetApi", {
773+
get() {
774+
return null;
775+
},
776+
});
734777
expect(call.connectionState).toBe(ConnectionState.Disconnected);
735778

736779
const startup = call.start({});
780+
// Now imagine that the messaging gets abandoned and replaced by an
781+
// entirely new messaging object
782+
({ widget, messaging, widgetApi } = setUpWidget(call));
737783
WidgetMessagingStore.instance.storeMessaging(widget, room.roomId, messaging);
738784
await startup;
739785
await connect(call, widgetApi, false);
740786
expect(call.connectionState).toBe(ConnectionState.Connected);
787+
expect(firstMessaging.listenerCount(WidgetMessagingEvent.Start)).toBe(0); // No leaks
741788
});
742789

743790
it("fails to disconnect if the widget returns an error", async () => {

0 commit comments

Comments
 (0)