You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-09 10:22:46 +03:00
Add a few group call event handler tests (#2679)
This commit is contained in:
@@ -21,10 +21,12 @@ import {
|
|||||||
GroupCall,
|
GroupCall,
|
||||||
GroupCallIntent,
|
GroupCallIntent,
|
||||||
GroupCallType,
|
GroupCallType,
|
||||||
|
IContent,
|
||||||
ISendEventResponse,
|
ISendEventResponse,
|
||||||
MatrixClient,
|
MatrixClient,
|
||||||
MatrixEvent,
|
MatrixEvent,
|
||||||
Room,
|
Room,
|
||||||
|
RoomState,
|
||||||
RoomStateEvent,
|
RoomStateEvent,
|
||||||
RoomStateEventHandlerMap,
|
RoomStateEventHandlerMap,
|
||||||
} from "../../src";
|
} from "../../src";
|
||||||
@@ -381,8 +383,18 @@ export class MockCallMatrixClient extends TypedEventEmitter<EmittedEvents, Emitt
|
|||||||
getSyncState = jest.fn<SyncState, []>().mockReturnValue(SyncState.Syncing);
|
getSyncState = jest.fn<SyncState, []>().mockReturnValue(SyncState.Syncing);
|
||||||
|
|
||||||
getRooms = jest.fn<Room[], []>().mockReturnValue([]);
|
getRooms = jest.fn<Room[], []>().mockReturnValue([]);
|
||||||
|
getRoom = jest.fn();
|
||||||
|
|
||||||
typed(): MatrixClient { return this as unknown as MatrixClient; }
|
typed(): MatrixClient { return this as unknown as MatrixClient; }
|
||||||
|
|
||||||
|
emitRoomState(event: MatrixEvent, state: RoomState): void {
|
||||||
|
this.emit(
|
||||||
|
RoomStateEvent.Events,
|
||||||
|
event,
|
||||||
|
state,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MockCallFeed {
|
export class MockCallFeed {
|
||||||
@@ -436,15 +448,15 @@ export function installWebRTCMocks() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeMockGroupCallStateEvent(roomId: string, groupCallId: string): MatrixEvent {
|
export function makeMockGroupCallStateEvent(roomId: string, groupCallId: string, content: IContent = {
|
||||||
|
"m.type": GroupCallType.Video,
|
||||||
|
"m.intent": GroupCallIntent.Prompt,
|
||||||
|
}): MatrixEvent {
|
||||||
return {
|
return {
|
||||||
getType: jest.fn().mockReturnValue(EventType.GroupCallPrefix),
|
getType: jest.fn().mockReturnValue(EventType.GroupCallPrefix),
|
||||||
getRoomId: jest.fn().mockReturnValue(roomId),
|
getRoomId: jest.fn().mockReturnValue(roomId),
|
||||||
getTs: jest.fn().mockReturnValue(0),
|
getTs: jest.fn().mockReturnValue(0),
|
||||||
getContent: jest.fn().mockReturnValue({
|
getContent: jest.fn().mockReturnValue(content),
|
||||||
"m.type": GroupCallType.Video,
|
|
||||||
"m.intent": GroupCallIntent.Prompt,
|
|
||||||
}),
|
|
||||||
getStateKey: jest.fn().mockReturnValue(groupCallId),
|
getStateKey: jest.fn().mockReturnValue(groupCallId),
|
||||||
} as unknown as MatrixEvent;
|
} as unknown as MatrixEvent;
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,21 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ClientEvent, GroupCall, Room, RoomState, RoomStateEvent } from "../../../src";
|
import { mocked } from "jest-mock";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ClientEvent,
|
||||||
|
GroupCall,
|
||||||
|
GroupCallIntent,
|
||||||
|
GroupCallState,
|
||||||
|
GroupCallType,
|
||||||
|
IContent,
|
||||||
|
MatrixEvent,
|
||||||
|
Room,
|
||||||
|
RoomState,
|
||||||
|
} from "../../../src";
|
||||||
import { SyncState } from "../../../src/sync";
|
import { SyncState } from "../../../src/sync";
|
||||||
|
import { GroupCallTerminationReason } from "../../../src/webrtc/groupCall";
|
||||||
import { GroupCallEventHandler, GroupCallEventHandlerEvent } from "../../../src/webrtc/groupCallEventHandler";
|
import { GroupCallEventHandler, GroupCallEventHandlerEvent } from "../../../src/webrtc/groupCallEventHandler";
|
||||||
import { flushPromises } from "../../test-utils/flushPromises";
|
import { flushPromises } from "../../test-utils/flushPromises";
|
||||||
import {
|
import {
|
||||||
@@ -53,6 +66,35 @@ describe('Group Call Event Handler', function() {
|
|||||||
(mockClient as any).getRoom = jest.fn().mockReturnValue(mockRoom);
|
(mockClient as any).getRoom = jest.fn().mockReturnValue(mockRoom);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("reacts to state changes", () => {
|
||||||
|
it("terminates call", async () => {
|
||||||
|
await groupCallEventHandler.start();
|
||||||
|
mockClient.emitRoomState(
|
||||||
|
makeMockGroupCallStateEvent(FAKE_ROOM_ID, FAKE_GROUP_CALL_ID),
|
||||||
|
{ roomId: FAKE_ROOM_ID } as unknown as RoomState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const groupCall = groupCallEventHandler.groupCalls.get(FAKE_ROOM_ID);
|
||||||
|
|
||||||
|
expect(groupCall.state).toBe(GroupCallState.LocalCallFeedUninitialized);
|
||||||
|
|
||||||
|
mockClient.emitRoomState(
|
||||||
|
makeMockGroupCallStateEvent(
|
||||||
|
FAKE_ROOM_ID, FAKE_GROUP_CALL_ID, {
|
||||||
|
"m.type": GroupCallType.Video,
|
||||||
|
"m.intent": GroupCallIntent.Prompt,
|
||||||
|
"m.terminated": GroupCallTerminationReason.CallEnded,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
{
|
||||||
|
roomId: FAKE_ROOM_ID,
|
||||||
|
} as unknown as RoomState,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(groupCall.state).toBe(GroupCallState.Ended);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("waits until client starts syncing", async () => {
|
it("waits until client starts syncing", async () => {
|
||||||
mockClient.getSyncState.mockReturnValue(null);
|
mockClient.getSyncState.mockReturnValue(null);
|
||||||
let isStarted = false;
|
let isStarted = false;
|
||||||
@@ -119,15 +161,13 @@ describe('Group Call Event Handler', function() {
|
|||||||
mockClient.on(GroupCallEventHandlerEvent.Incoming, onIncomingGroupCall);
|
mockClient.on(GroupCallEventHandlerEvent.Incoming, onIncomingGroupCall);
|
||||||
await groupCallEventHandler.start();
|
await groupCallEventHandler.start();
|
||||||
|
|
||||||
mockClient.emit(
|
mockClient.emitRoomState(
|
||||||
RoomStateEvent.Events,
|
|
||||||
makeMockGroupCallStateEvent(
|
makeMockGroupCallStateEvent(
|
||||||
FAKE_ROOM_ID, FAKE_GROUP_CALL_ID,
|
FAKE_ROOM_ID, FAKE_GROUP_CALL_ID,
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
roomId: FAKE_ROOM_ID,
|
roomId: FAKE_ROOM_ID,
|
||||||
} as unknown as RoomState,
|
} as unknown as RoomState,
|
||||||
null,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(onIncomingGroupCall).toHaveBeenCalledWith(expect.objectContaining({
|
expect(onIncomingGroupCall).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
@@ -137,6 +177,40 @@ describe('Group Call Event Handler', function() {
|
|||||||
mockClient.off(GroupCallEventHandlerEvent.Incoming, onIncomingGroupCall);
|
mockClient.off(GroupCallEventHandlerEvent.Incoming, onIncomingGroupCall);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("handles data channel", async () => {
|
||||||
|
await groupCallEventHandler.start();
|
||||||
|
|
||||||
|
const dataChannelOptions = {
|
||||||
|
"maxPacketLifeTime": "life_time",
|
||||||
|
"maxRetransmits": "retransmits",
|
||||||
|
"ordered": "ordered",
|
||||||
|
"protocol": "protocol",
|
||||||
|
};
|
||||||
|
|
||||||
|
mockClient.emitRoomState(
|
||||||
|
makeMockGroupCallStateEvent(
|
||||||
|
FAKE_ROOM_ID,
|
||||||
|
FAKE_GROUP_CALL_ID,
|
||||||
|
{
|
||||||
|
"m.type": GroupCallType.Video,
|
||||||
|
"m.intent": GroupCallIntent.Prompt,
|
||||||
|
"dataChannelsEnabled": true,
|
||||||
|
dataChannelOptions,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
{
|
||||||
|
roomId: FAKE_ROOM_ID,
|
||||||
|
} as unknown as RoomState,
|
||||||
|
);
|
||||||
|
|
||||||
|
// @ts-ignore Mock dataChannelsEnabled is private
|
||||||
|
expect(groupCallEventHandler.groupCalls.get(FAKE_ROOM_ID)?.dataChannelsEnabled).toBe(true);
|
||||||
|
// @ts-ignore Mock dataChannelOptions is private
|
||||||
|
expect(groupCallEventHandler.groupCalls.get(FAKE_ROOM_ID)?.dataChannelOptions).toStrictEqual(
|
||||||
|
dataChannelOptions,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("sends member events to group calls", async () => {
|
it("sends member events to group calls", async () => {
|
||||||
await groupCallEventHandler.start();
|
await groupCallEventHandler.start();
|
||||||
|
|
||||||
@@ -148,15 +222,95 @@ describe('Group Call Event Handler', function() {
|
|||||||
|
|
||||||
const mockStateEvent = makeMockGroupCallMemberStateEvent(FAKE_ROOM_ID, FAKE_GROUP_CALL_ID);
|
const mockStateEvent = makeMockGroupCallMemberStateEvent(FAKE_ROOM_ID, FAKE_GROUP_CALL_ID);
|
||||||
|
|
||||||
mockClient.emit(
|
mockClient.emitRoomState(
|
||||||
RoomStateEvent.Events,
|
|
||||||
mockStateEvent,
|
mockStateEvent,
|
||||||
{
|
{
|
||||||
roomId: FAKE_ROOM_ID,
|
roomId: FAKE_ROOM_ID,
|
||||||
} as unknown as RoomState,
|
} as unknown as RoomState,
|
||||||
null,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mockGroupCall.onMemberStateChanged).toHaveBeenCalledWith(mockStateEvent);
|
expect(mockGroupCall.onMemberStateChanged).toHaveBeenCalledWith(mockStateEvent);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("ignoring invalid group call state events", () => {
|
||||||
|
let mockClientEmit: jest.Func;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockClientEmit = mockClient.emit = jest.fn();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
groupCallEventHandler.stop();
|
||||||
|
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
const setupCallAndStart = async (content?: IContent) => {
|
||||||
|
mocked(mockRoom.currentState.getStateEvents).mockReturnValue([
|
||||||
|
makeMockGroupCallStateEvent(
|
||||||
|
FAKE_ROOM_ID,
|
||||||
|
FAKE_GROUP_CALL_ID,
|
||||||
|
content,
|
||||||
|
),
|
||||||
|
] as unknown as MatrixEvent);
|
||||||
|
mockClient.getRooms.mockReturnValue([mockRoom]);
|
||||||
|
await groupCallEventHandler.start();
|
||||||
|
};
|
||||||
|
|
||||||
|
it("ignores terminated calls", async () => {
|
||||||
|
await setupCallAndStart({
|
||||||
|
"m.type": GroupCallType.Video,
|
||||||
|
"m.intent": GroupCallIntent.Prompt,
|
||||||
|
"m.terminated": GroupCallTerminationReason.CallEnded,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockClientEmit).not.toHaveBeenCalledWith(
|
||||||
|
GroupCallEventHandlerEvent.Incoming,
|
||||||
|
expect.objectContaining({
|
||||||
|
groupCallId: FAKE_GROUP_CALL_ID,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores calls with invalid type", async () => {
|
||||||
|
await setupCallAndStart({
|
||||||
|
"m.type": "fake_type",
|
||||||
|
"m.intent": GroupCallIntent.Prompt,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockClientEmit).not.toHaveBeenCalledWith(
|
||||||
|
GroupCallEventHandlerEvent.Incoming,
|
||||||
|
expect.objectContaining({
|
||||||
|
groupCallId: FAKE_GROUP_CALL_ID,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores calls with invalid intent", async () => {
|
||||||
|
await setupCallAndStart({
|
||||||
|
"m.type": GroupCallType.Video,
|
||||||
|
"m.intent": "fake_intent",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockClientEmit).not.toHaveBeenCalledWith(
|
||||||
|
GroupCallEventHandlerEvent.Incoming,
|
||||||
|
expect.objectContaining({
|
||||||
|
groupCallId: FAKE_GROUP_CALL_ID,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores calls without a room", async () => {
|
||||||
|
mockClient.getRoom.mockReturnValue(undefined);
|
||||||
|
|
||||||
|
await setupCallAndStart();
|
||||||
|
|
||||||
|
expect(mockClientEmit).not.toHaveBeenCalledWith(
|
||||||
|
GroupCallEventHandlerEvent.Incoming,
|
||||||
|
expect.objectContaining({
|
||||||
|
groupCallId: FAKE_GROUP_CALL_ID,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user