Fix room list often showing the wrong icons for calls (#32881)

* Give rooms with calls a proper accessible description

Besides improving accessibility, this makes it possible to check for the presence of a call indicator in the room list in Playwright tests.

* Make room list react to calls in a room, even when not connected to them

To use the results of CallStore.getRoom reactively, you need to listen for Call events, not ConnectedCalls events.

* Don't assume that every call starts off as a video call

If a Call object is created by way of someone starting a voice call, then of course the call's initial type needs to be 'voice'.

* Make room list items react to changes in call type

The type of a call may change over time; therefore room list items explicitly need to react to the changes.

* Update a call's type before notifying listeners of the change

If we notify listeners of a change in a call's type before actually making that change, the listeners will be working with glitched state. This would cause the room list to show the wrong call type in certain situations.

* Ignore the Vitest attachments directory
This commit is contained in:
Robin
2026-03-26 10:28:48 +00:00
committed by GitHub
parent 441b292353
commit 5a074e637a
15 changed files with 468 additions and 44 deletions
@@ -5,6 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/
import EventEmitter from "events";
import {
type MatrixClient,
type MatrixEvent,
@@ -26,7 +27,7 @@ import { DefaultTagID } from "../../../src/stores/room-list-v3/skip-list/tag";
import dispatcher from "../../../src/dispatcher/dispatcher";
import { Action } from "../../../src/dispatcher/actions";
import { CallStore } from "../../../src/stores/CallStore";
import type { Call } from "../../../src/models/Call";
import { CallEvent, type Call } from "../../../src/models/Call";
import { RoomListItemViewModel } from "../../../src/viewmodels/room-list/RoomListItemViewModel";
jest.mock("../../../src/viewmodels/room-list/utils", () => ({
@@ -436,6 +437,28 @@ describe("RoomListItemViewModel", () => {
// The new call must have a listener registered
expect(secondCall.on).toHaveBeenCalledWith("participants", expect.any(Function));
});
it("should listen to call type changes", async () => {
// Start with a voice call
let callType = CallType.Voice;
const mockCall = new (class extends EventEmitter {
get callType() {
return callType;
}
participants = new Map([[matrixClient.getUserId()!, {}]]);
})() as unknown as Call;
jest.spyOn(CallStore.instance, "getCall").mockReturnValue(mockCall);
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
await flushPromises();
expect(viewModel.getSnapshot().notification.callType).toBe("voice");
// Now turn it into a video call
callType = CallType.Video;
mockCall.emit(CallEvent.CallTypeChanged, callType);
expect(viewModel.getSnapshot().notification.callType).toBe("video");
});
});
describe("Room name updates", () => {