tests: end scope tests

This commit is contained in:
Valere
2025-10-01 16:39:21 +02:00
parent 6a1f7dd057
commit e8bf817f88
3 changed files with 62 additions and 23 deletions

View File

@@ -1890,7 +1890,7 @@ export class CallViewModel extends ViewModel {
this.startConnection$ this.startConnection$
.pipe(this.scope.bind()) .pipe(this.scope.bind())
.subscribe((c) => void c.start()); .subscribe((c) => void c.start());
this.stopConnection$.pipe(this.scope.bind()).subscribe((c) => c.stop()); this.stopConnection$.pipe(this.scope.bind()).subscribe((c) => void c.stop());
combineLatest([this.localFocus, this.join$]) combineLatest([this.localFocus, this.join$])
.pipe(this.scope.bind()) .pipe(this.scope.bind())

View File

@@ -28,9 +28,9 @@ describe("Start connection states", () => {
let fakeRoomEventEmiter: EventEmitter<RoomEventCallbacks>; let fakeRoomEventEmiter: EventEmitter<RoomEventCallbacks>;
let fakeMembershipsFocusMap$: BehaviorSubject<{ membership: CallMembership; focus: LivekitFocus }[]>; let fakeMembershipsFocusMap$: BehaviorSubject<{ membership: CallMembership; focus: LivekitFocus }[]>;
const livekitFocus : LivekitFocus = { const livekitFocus: LivekitFocus = {
livekit_alias:"!roomID:example.org", livekit_alias: "!roomID:example.org",
livekit_service_url : "https://matrix-rtc.example.org/livekit/jwt" livekit_service_url: "https://matrix-rtc.example.org/livekit/jwt"
} }
afterEach(() => { afterEach(() => {
@@ -98,8 +98,8 @@ describe("Start connection states", () => {
.mockResolvedValue(undefined); .mockResolvedValue(undefined);
const connection = new RemoteConnection( const connection = new RemoteConnection(
opts, opts,
undefined, undefined,
); );
return connection; return connection;
} }
@@ -115,8 +115,8 @@ describe("Start connection states", () => {
livekitRoomFactory: () => fakeLivekitRoom, livekitRoomFactory: () => fakeLivekitRoom,
} }
const connection = new RemoteConnection( const connection = new RemoteConnection(
opts, opts,
undefined, undefined,
); );
expect(connection.focusedConnectionState$.getValue().state) expect(connection.focusedConnectionState$.getValue().state)
@@ -254,7 +254,7 @@ describe("Start connection states", () => {
const deferredSFU = Promise.withResolvers<void>(); const deferredSFU = Promise.withResolvers<void>();
// mock the /sfu/get call // mock the /sfu/get call
fetchMock.post(`${livekitFocus.livekit_service_url}/sfu/get`, fetchMock.post(`${livekitFocus.livekit_service_url}/sfu/get`,
() => { () => {
return { return {
status: 200, status: 200,
body: body:
@@ -318,15 +318,13 @@ describe("Start connection states", () => {
}); });
it("should relay livekit events once connected", async () => { it("should relay livekit events once connected", async () => {
vi.useFakeTimers();
setupTest() setupTest()
const connection = setupRemoteConnection(); const connection = setupRemoteConnection();
await connection.start(); await connection.start();
await vi.runAllTimersAsync();
const capturedState: FocusConnectionState[] = []; let capturedState: FocusConnectionState[] = [];
connection.focusedConnectionState$.subscribe((value) => { connection.focusedConnectionState$.subscribe((value) => {
capturedState.push(value); capturedState.push(value);
}); });
@@ -342,11 +340,8 @@ describe("Start connection states", () => {
] ]
for (const state of states) { for (const state of states) {
fakeRoomEventEmiter.emit(RoomEvent.ConnectionStateChanged, state); fakeRoomEventEmiter.emit(RoomEvent.ConnectionStateChanged, state);
await vi.runAllTimersAsync();
} }
await vi.runAllTimersAsync();
for (const state of states) { for (const state of states) {
const s = capturedState.shift(); const s = capturedState.shift();
expect(s?.state).toEqual("ConnectedToLkRoom"); expect(s?.state).toEqual("ConnectedToLkRoom");
@@ -357,7 +352,47 @@ describe("Start connection states", () => {
expect(s?.focus.livekit_service_url).toEqual(livekitFocus.livekit_service_url); expect(s?.focus.livekit_service_url).toEqual(livekitFocus.livekit_service_url);
} }
// If the state is not ConnectedToLkRoom, no events should be relayed anymore
await connection.stop();
capturedState = [];
for (const state of states) {
fakeRoomEventEmiter.emit(RoomEvent.ConnectionStateChanged, state);
}
expect(capturedState.length).toEqual(0);
}); });
}) it("shutting down the scope should stop the connection", async () => {
setupTest()
vi.useFakeTimers();
const connection = setupRemoteConnection();
let capturedState: FocusConnectionState[] = [];
connection.focusedConnectionState$.subscribe((value) => {
capturedState.push(value);
});
await connection.start();
const stopSpy = vi.spyOn(connection, "stop");
testScope.end();
expect(stopSpy).toHaveBeenCalled();
expect(fakeLivekitRoom.disconnect).toHaveBeenCalled();
/// Ensures that focusedConnectionState$ is bound to the scope.
capturedState = [];
// the subscription should be closed, and no new state should be received
// @ts-expect-error: Accessing private field for testing purposes
connection._focusedConnectionState$.next({ state: "Initialized" });
// @ts-expect-error: Accessing private field for testing purposes
connection._focusedConnectionState$.next({ state: "ConnectingToLkRoom" });
expect(capturedState.length).toEqual(0);
});
});

View File

@@ -46,14 +46,14 @@ export type FocusConnectionState =
export class Connection { export class Connection {
// Private Behavior // Private Behavior
private readonly _focusedConnectionState$ = new BehaviorSubject<FocusConnectionState>({ state: 'Initialized' }); private readonly _focusedConnectionState$
= new BehaviorSubject<FocusConnectionState>({ state: 'Initialized' });
/** /**
* The current state of the connection to the focus server. * The current state of the connection to the focus server.
*/ */
public get focusedConnectionState$(): Behavior<FocusConnectionState> { public readonly focusedConnectionState$: Behavior<FocusConnectionState>;
return this._focusedConnectionState$;
}
/** /**
* Whether the connection has been stopped. * Whether the connection has been stopped.
* @see Connection.stop * @see Connection.stop
@@ -103,9 +103,9 @@ export class Connection {
* This will disconnect from the LiveKit room. * This will disconnect from the LiveKit room.
* If the connection is already stopped, this is a no-op. * If the connection is already stopped, this is a no-op.
*/ */
public stop(): void { public async stop(): Promise<void> {
if (this.stopped) return; if (this.stopped) return;
void this.livekitRoom.disconnect(); await this.livekitRoom.disconnect();
this._focusedConnectionState$.next({ state: 'Stopped', focus: this.targetFocus }); this._focusedConnectionState$.next({ state: 'Stopped', focus: this.targetFocus });
this.stopped = true; this.stopped = true;
} }
@@ -142,6 +142,10 @@ export class Connection {
this.targetFocus = focus; this.targetFocus = focus;
this.client = client; this.client = client;
this.focusedConnectionState$ = scope.behavior(
this._focusedConnectionState$, { state: 'Initialized' }
);
const participantsIncludingSubscribers$ = scope.behavior( const participantsIncludingSubscribers$ = scope.behavior(
connectedParticipantsObserver(this.livekitRoom), connectedParticipantsObserver(this.livekitRoom),
[] []
@@ -180,7 +184,7 @@ export class Connection {
} }
}); });
scope.onEnd(() => this.stop()); scope.onEnd(() => void this.stop());
} }
} }