Prepare for Element Call integration (#9224)
* Improve accessibility and testability of Tooltip Adding a role to Tooltip was motivated by React Testing Library's reliance on accessibility-related attributes to locate elements. * Make the ReadyWatchingStore constructor safer The ReadyWatchingStore constructor previously had a chance to immediately call onReady, which was dangerous because it was potentially calling the derived class's onReady at a point when the derived class hadn't even finished construction yet. In normal usage, I guess this never was a problem, but it was causing some of the tests I was writing to crash. This is solved by separating out the onReady call into a start method. * Rename 1:1 call components to 'LegacyCall' to reflect the fact that they're slated for removal, and to not clash with the new Call code. * Refactor VideoChannelStore into Call and CallStore Call is an abstract class that currently only has a Jitsi implementation, but this will make it easy to later add an Element Call implementation. * Remove WidgetReady, ClientReady, and ForceHangupCall hacks These are no longer used by the new Jitsi call implementation, and can be removed. * yarn i18n * Delete call map entries instead of inserting nulls * Allow multiple active calls and consolidate call listeners * Fix a race condition when creating a video room * Un-hardcode the media device fallback labels * Apply misc code review fixes * yarn i18n * Disconnect from calls more politely on logout * Fix some strict mode errors * Fix another updateRoom race condition
This commit is contained in:
parent
50f6986f6c
commit
0d6a550c33
107 changed files with 2573 additions and 2157 deletions
|
@ -14,51 +14,91 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { stubClient, stubVideoChannelStore, mkRoom } from "../../../test-utils";
|
||||
import { mocked, MockedObject } from "jest-mock";
|
||||
import { PendingEventOrdering } from "matrix-js-sdk/src/client";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
||||
import { Widget } from "matrix-widget-api";
|
||||
|
||||
import type { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import type { ClientWidgetApi } from "matrix-widget-api";
|
||||
import { stubClient, setupAsyncStoreWithClient, useMockedCalls, MockedCall } from "../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
||||
import { DefaultTagID } from "../../../../src/stores/room-list/models";
|
||||
import { SortAlgorithm, ListAlgorithm } from "../../../../src/stores/room-list/algorithms/models";
|
||||
import "../../../../src/stores/room-list/RoomListStore"; // must be imported before Algorithm to avoid cycles
|
||||
import { Algorithm } from "../../../../src/stores/room-list/algorithms/Algorithm";
|
||||
import { CallStore } from "../../../../src/stores/CallStore";
|
||||
import { WidgetMessagingStore } from "../../../../src/stores/widgets/WidgetMessagingStore";
|
||||
|
||||
describe("Algorithm", () => {
|
||||
let videoChannelStore;
|
||||
let algorithm;
|
||||
let textRoom;
|
||||
let videoRoom;
|
||||
useMockedCalls();
|
||||
|
||||
let client: MockedObject<MatrixClient>;
|
||||
let algorithm: Algorithm;
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
const cli = MatrixClientPeg.get();
|
||||
client = mocked(MatrixClientPeg.get());
|
||||
DMRoomMap.makeShared();
|
||||
videoChannelStore = stubVideoChannelStore();
|
||||
|
||||
algorithm = new Algorithm();
|
||||
algorithm.start();
|
||||
|
||||
textRoom = mkRoom(cli, "!text:example.org");
|
||||
videoRoom = mkRoom(cli, "!video:example.org");
|
||||
videoRoom.isElementVideoRoom.mockReturnValue(true);
|
||||
algorithm.populateTags(
|
||||
{ [DefaultTagID.Untagged]: SortAlgorithm.Alphabetic },
|
||||
{ [DefaultTagID.Untagged]: ListAlgorithm.Natural },
|
||||
);
|
||||
algorithm.setKnownRooms([textRoom, videoRoom]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
algorithm.stop();
|
||||
});
|
||||
|
||||
it("sticks video rooms to the top when they connect", () => {
|
||||
expect(algorithm.getOrderedRooms()[DefaultTagID.Untagged]).toEqual([textRoom, videoRoom]);
|
||||
videoChannelStore.connect("!video:example.org");
|
||||
expect(algorithm.getOrderedRooms()[DefaultTagID.Untagged]).toEqual([videoRoom, textRoom]);
|
||||
});
|
||||
it("sticks rooms with calls to the top when they're connected", async () => {
|
||||
const room = new Room("!1:example.org", client, "@alice:example.org", {
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
const roomWithCall = new Room("!2:example.org", client, "@alice:example.org", {
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
|
||||
it("unsticks video rooms from the top when they disconnect", () => {
|
||||
videoChannelStore.connect("!video:example.org");
|
||||
expect(algorithm.getOrderedRooms()[DefaultTagID.Untagged]).toEqual([videoRoom, textRoom]);
|
||||
videoChannelStore.disconnect();
|
||||
expect(algorithm.getOrderedRooms()[DefaultTagID.Untagged]).toEqual([textRoom, videoRoom]);
|
||||
client.getRoom.mockImplementation(roomId => {
|
||||
switch (roomId) {
|
||||
case room.roomId: return room;
|
||||
case roomWithCall.roomId: return roomWithCall;
|
||||
default: return null;
|
||||
}
|
||||
});
|
||||
client.getRooms.mockReturnValue([room, roomWithCall]);
|
||||
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
|
||||
client.reEmitter.reEmit(roomWithCall, [RoomStateEvent.Events]);
|
||||
|
||||
for (const room of client.getRooms()) jest.spyOn(room, "getMyMembership").mockReturnValue("join");
|
||||
algorithm.setKnownRooms(client.getRooms());
|
||||
|
||||
setupAsyncStoreWithClient(CallStore.instance, client);
|
||||
setupAsyncStoreWithClient(WidgetMessagingStore.instance, client);
|
||||
|
||||
MockedCall.create(roomWithCall, "1");
|
||||
const call = CallStore.instance.get(roomWithCall.roomId);
|
||||
if (call === null) throw new Error("Failed to create call");
|
||||
|
||||
const widget = new Widget(call.widget);
|
||||
WidgetMessagingStore.instance.storeMessaging(widget, roomWithCall.roomId, {
|
||||
stop: () => {},
|
||||
} as unknown as ClientWidgetApi);
|
||||
|
||||
Object.defineProperty(navigator, "mediaDevices", {
|
||||
value: { enumerateDevices: async () => [] },
|
||||
});
|
||||
|
||||
// End of setup
|
||||
|
||||
expect(algorithm.getOrderedRooms()[DefaultTagID.Untagged]).toEqual([room, roomWithCall]);
|
||||
await call.connect();
|
||||
expect(algorithm.getOrderedRooms()[DefaultTagID.Untagged]).toEqual([roomWithCall, room]);
|
||||
await call.disconnect();
|
||||
expect(algorithm.getOrderedRooms()[DefaultTagID.Untagged]).toEqual([room, roomWithCall]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ import { mocked } from "jest-mock";
|
|||
import { Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { VisibilityProvider } from "../../../../src/stores/room-list/filters/VisibilityProvider";
|
||||
import CallHandler from "../../../../src/CallHandler";
|
||||
import LegacyCallHandler from "../../../../src/LegacyCallHandler";
|
||||
import VoipUserMapper from "../../../../src/VoipUserMapper";
|
||||
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../../../src/models/LocalRoom";
|
||||
import { RoomListCustomisations } from "../../../../src/customisations/RoomList";
|
||||
|
@ -28,7 +28,7 @@ jest.mock("../../../../src/VoipUserMapper", () => ({
|
|||
sharedInstance: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../../../../src/CallHandler", () => ({
|
||||
jest.mock("../../../../src/LegacyCallHandler", () => ({
|
||||
instance: {
|
||||
getSupportsVirtualRooms: jest.fn(),
|
||||
},
|
||||
|
@ -82,7 +82,7 @@ describe("VisibilityProvider", () => {
|
|||
describe("isRoomVisible", () => {
|
||||
describe("for a virtual room", () => {
|
||||
beforeEach(() => {
|
||||
mocked(CallHandler.instance.getSupportsVirtualRooms).mockReturnValue(true);
|
||||
mocked(LegacyCallHandler.instance.getSupportsVirtualRooms).mockReturnValue(true);
|
||||
mocked(mockVoipUserMapper.isVirtualRoom).mockReturnValue(true);
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue