You've already forked matrix-react-sdk
mirror of
https://github.com/matrix-org/matrix-react-sdk.git
synced 2025-07-31 13:44:28 +03:00
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:
92
test/test-utils/call.ts
Normal file
92
test/test-utils/call.ts
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { MatrixWidgetType } from "matrix-widget-api";
|
||||
|
||||
import type { Room } from "matrix-js-sdk/src/models/room";
|
||||
import type { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
import { mkEvent } from "./test-utils";
|
||||
import { Call } from "../../src/models/Call";
|
||||
|
||||
export class MockedCall extends Call {
|
||||
private static EVENT_TYPE = "org.example.mocked_call";
|
||||
|
||||
private constructor(private readonly room: Room, private readonly id: string) {
|
||||
super({
|
||||
id,
|
||||
eventId: "$1:example.org",
|
||||
roomId: room.roomId,
|
||||
type: MatrixWidgetType.Custom,
|
||||
url: "https://example.org",
|
||||
name: "Group call",
|
||||
creatorUserId: "@alice:example.org",
|
||||
});
|
||||
}
|
||||
|
||||
public static get(room: Room): MockedCall | null {
|
||||
const [event] = room.currentState.getStateEvents(this.EVENT_TYPE);
|
||||
return event?.getContent().terminated ?? true ? null : new MockedCall(room, event.getStateKey()!);
|
||||
}
|
||||
|
||||
public static create(room: Room, id: string) {
|
||||
// Update room state to let CallStore know that a call might now exist
|
||||
room.addLiveEvents([mkEvent({
|
||||
event: true,
|
||||
type: this.EVENT_TYPE,
|
||||
room: room.roomId,
|
||||
user: "@alice:example.org",
|
||||
content: { terminated: false },
|
||||
skey: id,
|
||||
})]);
|
||||
}
|
||||
|
||||
public get participants(): Set<RoomMember> {
|
||||
return super.participants;
|
||||
}
|
||||
public set participants(value: Set<RoomMember>) {
|
||||
super.participants = value;
|
||||
}
|
||||
|
||||
// No action needed for any of the following methods since this is just a mock
|
||||
public async clean(): Promise<void> {}
|
||||
// Public to allow spying
|
||||
public async performConnection(
|
||||
audioInput: MediaDeviceInfo | null,
|
||||
videoInput: MediaDeviceInfo | null,
|
||||
): Promise<void> {}
|
||||
public async performDisconnection(): Promise<void> {}
|
||||
|
||||
public destroy() {
|
||||
// Terminate the call for good measure
|
||||
this.room.addLiveEvents([mkEvent({
|
||||
event: true,
|
||||
type: MockedCall.EVENT_TYPE,
|
||||
room: this.room.roomId,
|
||||
user: "@alice:example.org",
|
||||
content: { terminated: true },
|
||||
skey: this.id,
|
||||
})]);
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the call store to use mocked calls.
|
||||
*/
|
||||
export const useMockedCalls = () => {
|
||||
Call.get = room => MockedCall.get(room);
|
||||
};
|
@ -21,6 +21,6 @@ export * from './platform';
|
||||
export * from './poll';
|
||||
export * from './room';
|
||||
export * from './test-utils';
|
||||
export * from './video';
|
||||
export * from './call';
|
||||
export * from './wrappers';
|
||||
export * from './utilities';
|
||||
|
@ -32,6 +32,7 @@ import {
|
||||
IUnsigned,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { normalize } from "matrix-js-sdk/src/utils";
|
||||
import { ReEmitter } from "matrix-js-sdk/src/ReEmitter";
|
||||
|
||||
import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg';
|
||||
import dis from '../../src/dispatcher/dispatcher';
|
||||
@ -175,6 +176,8 @@ export function createTestClient(): MatrixClient {
|
||||
encryptAndSendToDevices: jest.fn().mockResolvedValue(undefined),
|
||||
} as unknown as MatrixClient;
|
||||
|
||||
client.reEmitter = new ReEmitter(client);
|
||||
|
||||
Object.defineProperty(client, "pollingTurnServers", {
|
||||
configurable: true,
|
||||
get: () => true,
|
||||
@ -325,6 +328,18 @@ export function mkMembership(opts: MakeEventPassThruProps & {
|
||||
return e;
|
||||
}
|
||||
|
||||
export function mkRoomMember(roomId: string, userId: string, membership = "join"): RoomMember {
|
||||
return {
|
||||
userId,
|
||||
membership,
|
||||
name: userId,
|
||||
rawDisplayName: userId,
|
||||
roomId,
|
||||
getAvatarUrl: () => {},
|
||||
getMxcAvatarUrl: () => {},
|
||||
} as unknown as RoomMember;
|
||||
}
|
||||
|
||||
export type MessageEventProps = MakeEventPassThruProps & {
|
||||
room: Room["roomId"];
|
||||
relatesTo?: IEventRelation;
|
||||
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from "events";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
|
||||
import { mkEvent } from "./test-utils";
|
||||
import { VIDEO_CHANNEL_MEMBER, STUCK_DEVICE_TIMEOUT_MS } from "../../src/utils/VideoChannelUtils";
|
||||
import VideoChannelStore, { VideoChannelEvent, IJitsiParticipant } from "../../src/stores/VideoChannelStore";
|
||||
|
||||
export class StubVideoChannelStore extends EventEmitter {
|
||||
private _roomId: string | null;
|
||||
public get roomId(): string | null { return this._roomId; }
|
||||
public set roomId(value: string | null) { this._roomId = value; }
|
||||
private _connected: boolean;
|
||||
public get connected(): boolean { return this._connected; }
|
||||
public get participants(): IJitsiParticipant[] { return []; }
|
||||
|
||||
public startConnect = (roomId: string) => {
|
||||
this.roomId = roomId;
|
||||
this.emit(VideoChannelEvent.StartConnect, roomId);
|
||||
};
|
||||
public connect = jest.fn((roomId: string) => {
|
||||
this.roomId = roomId;
|
||||
this._connected = true;
|
||||
this.emit(VideoChannelEvent.Connect, roomId);
|
||||
});
|
||||
public disconnect = jest.fn(() => {
|
||||
const roomId = this._roomId;
|
||||
this.roomId = null;
|
||||
this._connected = false;
|
||||
this.emit(VideoChannelEvent.Disconnect, roomId);
|
||||
});
|
||||
}
|
||||
|
||||
export const stubVideoChannelStore = (): StubVideoChannelStore => {
|
||||
const store = new StubVideoChannelStore();
|
||||
jest.spyOn(VideoChannelStore, "instance", "get").mockReturnValue(store as unknown as VideoChannelStore);
|
||||
return store;
|
||||
};
|
||||
|
||||
export const mkVideoChannelMember = (userId: string, devices: string[], expiresAt?: number): MatrixEvent => mkEvent({
|
||||
event: true,
|
||||
type: VIDEO_CHANNEL_MEMBER,
|
||||
room: "!1:example.org",
|
||||
user: userId,
|
||||
skey: userId,
|
||||
content: {
|
||||
devices,
|
||||
expires_ts: expiresAt == null ? Date.now() + STUCK_DEVICE_TIMEOUT_MS : expiresAt,
|
||||
},
|
||||
});
|
Reference in New Issue
Block a user