Proactively fix stuck devices in video rooms (#8587)
* Proactively fix stuck devices in video rooms * Fix tests * Explain why we're disabling the lint rule * Apply code review suggestions * Back VideoChannelStore's flags by SettingsStore instead of localStorage
This commit is contained in:
parent
6f851108be
commit
ceda77d7dc
9 changed files with 149 additions and 49 deletions
|
@ -17,7 +17,8 @@ limitations under the License.
|
|||
import React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { mocked } from "jest-mock";
|
||||
import { MatrixClient, IMyDevice } from "matrix-js-sdk/src/client";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { MatrixWidgetType } from "matrix-widget-api";
|
||||
|
||||
|
@ -27,9 +28,11 @@ import {
|
|||
StubVideoChannelStore,
|
||||
mkRoom,
|
||||
wrapInMatrixClientContext,
|
||||
mockStateEventImplementation,
|
||||
mkVideoChannelMember,
|
||||
} from "../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import { VIDEO_CHANNEL } from "../../../src/utils/VideoChannelUtils";
|
||||
import { VIDEO_CHANNEL, VIDEO_CHANNEL_MEMBER } from "../../../src/utils/VideoChannelUtils";
|
||||
import WidgetStore from "../../../src/stores/WidgetStore";
|
||||
import _VideoRoomView from "../../../src/components/structures/VideoRoomView";
|
||||
import VideoLobby from "../../../src/components/views/voip/VideoLobby";
|
||||
|
@ -64,6 +67,37 @@ describe("VideoRoomView", () => {
|
|||
room = mkRoom(cli, "!1:example.org");
|
||||
});
|
||||
|
||||
it("removes stuck devices on mount", async () => {
|
||||
// Simulate an unclean disconnect
|
||||
store.roomId = "!1:example.org";
|
||||
|
||||
const devices: IMyDevice[] = [
|
||||
{
|
||||
device_id: cli.getDeviceId(),
|
||||
last_seen_ts: new Date().valueOf(),
|
||||
},
|
||||
{
|
||||
device_id: "went offline 2 hours ago",
|
||||
last_seen_ts: new Date().valueOf() - 1000 * 60 * 60 * 2,
|
||||
},
|
||||
];
|
||||
mocked(cli).getDevices.mockResolvedValue({ devices });
|
||||
|
||||
// Make both devices be stuck
|
||||
mocked(room.currentState).getStateEvents.mockImplementation(mockStateEventImplementation([
|
||||
mkVideoChannelMember(cli.getUserId(), devices.map(d => d.device_id)),
|
||||
]));
|
||||
|
||||
mount(<VideoRoomView room={room} resizing={false} />);
|
||||
// Wait for state to settle
|
||||
await act(() => Promise.resolve());
|
||||
|
||||
// All devices should have been removed
|
||||
expect(cli.sendStateEvent).toHaveBeenLastCalledWith(
|
||||
"!1:example.org", VIDEO_CHANNEL_MEMBER, { devices: [] }, cli.getUserId(),
|
||||
);
|
||||
});
|
||||
|
||||
it("shows lobby and keeps widget loaded when disconnected", async () => {
|
||||
const view = mount(<VideoRoomView room={room} resizing={false} />);
|
||||
// Wait for state to settle
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
import { mocked } from "jest-mock";
|
||||
import { Widget, ClientWidgetApi, MatrixWidgetType, IWidgetApiRequest } from "matrix-widget-api";
|
||||
|
||||
import { stubClient, setupAsyncStoreWithClient } from "../test-utils";
|
||||
import { stubClient, setupAsyncStoreWithClient, mkRoom } from "../test-utils";
|
||||
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||
import WidgetStore, { IApp } from "../../src/stores/WidgetStore";
|
||||
import { WidgetMessagingStore } from "../../src/stores/widgets/WidgetMessagingStore";
|
||||
|
@ -51,6 +51,7 @@ describe("VideoChannelStore", () => {
|
|||
const cli = MatrixClientPeg.get();
|
||||
setupAsyncStoreWithClient(WidgetMessagingStore.instance, cli);
|
||||
setupAsyncStoreWithClient(store, cli);
|
||||
mocked(cli).getRoom.mockReturnValue(mkRoom(cli, "!1:example.org"));
|
||||
|
||||
let resolveMessageSent: () => void;
|
||||
messageSent = new Promise(resolve => resolveMessageSent = resolve);
|
||||
|
|
|
@ -79,6 +79,7 @@ export function createTestClient(): MatrixClient {
|
|||
getUserId: jest.fn().mockReturnValue("@userId:matrix.rog"),
|
||||
getUser: jest.fn().mockReturnValue({ on: jest.fn() }),
|
||||
getDeviceId: jest.fn().mockReturnValue("ABCDEFGHI"),
|
||||
getDevices: jest.fn().mockResolvedValue({ devices: [{ device_id: "ABCDEFGHI" }] }),
|
||||
credentials: { userId: "@userId:matrix.rog" },
|
||||
|
||||
getPushActionsForEvent: jest.fn(),
|
||||
|
|
|
@ -22,24 +22,25 @@ import { VIDEO_CHANNEL_MEMBER } from "../../src/utils/VideoChannelUtils";
|
|||
import VideoChannelStore, { VideoChannelEvent, IJitsiParticipant } from "../../src/stores/VideoChannelStore";
|
||||
|
||||
export class StubVideoChannelStore extends EventEmitter {
|
||||
private _roomId: string;
|
||||
public get roomId(): string { return this._roomId; }
|
||||
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.roomId = roomId;
|
||||
this.emit(VideoChannelEvent.StartConnect, roomId);
|
||||
};
|
||||
public connect = jest.fn((roomId: string) => {
|
||||
this._roomId = roomId;
|
||||
this.roomId = roomId;
|
||||
this._connected = true;
|
||||
this.emit(VideoChannelEvent.Connect, roomId);
|
||||
});
|
||||
public disconnect = jest.fn(() => {
|
||||
const roomId = this._roomId;
|
||||
this._roomId = null;
|
||||
this.roomId = null;
|
||||
this._connected = false;
|
||||
this.emit(VideoChannelEvent.Disconnect, roomId);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue