1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-09 10:22:46 +03:00

Add more MatrixCall tests (#2697)

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
Šimon Brandner
2022-09-26 12:02:41 +02:00
committed by GitHub
parent af6f9d49f4
commit ab39ee37d6
2 changed files with 125 additions and 2 deletions

View File

@@ -103,6 +103,7 @@ export class MockRTCPeerConnection {
private negotiationNeededListener: () => void; private negotiationNeededListener: () => void;
public iceCandidateListener?: (e: RTCPeerConnectionIceEvent) => void; public iceCandidateListener?: (e: RTCPeerConnectionIceEvent) => void;
public onTrackListener?: (e: RTCTrackEvent) => void;
private needsNegotiation = false; private needsNegotiation = false;
public readyToNegotiate: Promise<void>; public readyToNegotiate: Promise<void>;
private onReadyToNegotiate: () => void; private onReadyToNegotiate: () => void;
@@ -143,6 +144,8 @@ export class MockRTCPeerConnection {
this.negotiationNeededListener = listener; this.negotiationNeededListener = listener;
} else if (type == 'icecandidate') { } else if (type == 'icecandidate') {
this.iceCandidateListener = listener; this.iceCandidateListener = listener;
} else if (type == 'track') {
this.onTrackListener = listener;
} }
} }
createDataChannel(label: string, opts: RTCDataChannelInit) { return { label, ...opts }; } createDataChannel(label: string, opts: RTCDataChannelInit) { return { label, ...opts }; }

View File

@@ -26,7 +26,13 @@ import {
CallState, CallState,
CallParty, CallParty,
} from '../../../src/webrtc/call'; } from '../../../src/webrtc/call';
import { SDPStreamMetadata, SDPStreamMetadataKey, SDPStreamMetadataPurpose } from '../../../src/webrtc/callEventTypes'; import {
MCallAnswer,
MCallHangupReject,
SDPStreamMetadata,
SDPStreamMetadataKey,
SDPStreamMetadataPurpose,
} from '../../../src/webrtc/callEventTypes';
import { import {
DUMMY_SDP, DUMMY_SDP,
MockMediaHandler, MockMediaHandler,
@@ -102,6 +108,8 @@ describe('Call', function() {
// We retain a reference to this in the correct Mock type // We retain a reference to this in the correct Mock type
let mockSendEvent: jest.Mock<Promise<ISendEventResponse>, [string, string, IContent, string, Callback<any>]>; let mockSendEvent: jest.Mock<Promise<ISendEventResponse>, [string, string, IContent, string, Callback<any>]>;
const errorListener = () => {};
beforeEach(function() { beforeEach(function() {
prevNavigator = global.navigator; prevNavigator = global.navigator;
prevDocument = global.document; prevDocument = global.document;
@@ -135,7 +143,7 @@ describe('Call', function() {
roomId: FAKE_ROOM_ID, roomId: FAKE_ROOM_ID,
}); });
// call checks one of these is wired up // call checks one of these is wired up
call.on(CallEvent.Error, () => {}); call.on(CallEvent.Error, errorListener);
}); });
afterEach(function() { afterEach(function() {
@@ -1276,4 +1284,116 @@ describe('Call', function() {
expect(call.terminate).toHaveBeenCalledWith(CallParty.Local, CallErrorCode.Transfered, true); expect(call.terminate).toHaveBeenCalledWith(CallParty.Local, CallErrorCode.Transfered, true);
}); });
}); });
describe("onTrack", () => {
it("ignores streamless track", async () => {
// @ts-ignore Mock pushRemoteFeed() is private
jest.spyOn(call, "pushRemoteFeed");
await call.placeVoiceCall();
(call.peerConn as unknown as MockRTCPeerConnection).onTrackListener(
{ streams: [], track: new MockMediaStreamTrack("track_ev", "audio") } as unknown as RTCTrackEvent,
);
// @ts-ignore Mock pushRemoteFeed() is private
expect(call.pushRemoteFeed).not.toHaveBeenCalled();
});
it("correctly pushes", async () => {
// @ts-ignore Mock pushRemoteFeed() is private
jest.spyOn(call, "pushRemoteFeed");
await call.placeVoiceCall();
await call.onAnswerReceived(makeMockEvent("@test:foo", {
version: 1,
call_id: call.callId,
party_id: 'the_correct_party_id',
answer: {
sdp: DUMMY_SDP,
},
}));
const stream = new MockMediaStream("stream_ev", [new MockMediaStreamTrack("track_ev", "audio")]);
(call.peerConn as unknown as MockRTCPeerConnection).onTrackListener(
{ streams: [stream], track: stream.getAudioTracks()[0] } as unknown as RTCTrackEvent,
);
// @ts-ignore Mock pushRemoteFeed() is private
expect(call.pushRemoteFeed).toHaveBeenCalledWith(stream);
// @ts-ignore Mock pushRemoteFeed() is private
expect(call.removeTrackListeners.has(stream)).toBe(true);
});
});
describe("onHangupReceived()", () => {
it("ends call on onHangupReceived() if state is ringing", async () => {
expect(call.callHasEnded()).toBe(false);
call.state = CallState.Ringing;
call.onHangupReceived({} as MCallHangupReject);
expect(call.callHasEnded()).toBe(true);
});
it("ends call on onHangupReceived() if party id matches", async () => {
expect(call.callHasEnded()).toBe(false);
await call.initWithInvite({
getContent: jest.fn().mockReturnValue({
version: "1",
call_id: "call_id",
party_id: "remote_party_id",
lifetime: CALL_LIFETIME,
offer: {
sdp: DUMMY_SDP,
},
}),
getSender: () => "@test:foo",
} as unknown as MatrixEvent);
call.onHangupReceived({ version: "1", party_id: "remote_party_id" } as MCallHangupReject);
expect(call.callHasEnded()).toBe(true);
});
});
it.each(
Object.values(CallState),
)("ends call on onRejectReceived() if in correct state (state=%s)", async (state: CallState) => {
expect(call.callHasEnded()).toBe(false);
call.state = state;
call.onRejectReceived({} as MCallHangupReject);
expect(call.callHasEnded()).toBe(
[CallState.InviteSent, CallState.Ringing, CallState.Ended].includes(state),
);
});
it("terminates call when answered elsewhere", async () => {
await call.placeVoiceCall();
expect(call.callHasEnded()).toBe(false);
call.onAnsweredElsewhere({} as MCallAnswer);
expect(call.callHasEnded()).toBe(true);
});
it("throws when there is no error listener", async () => {
call.off(CallEvent.Error, errorListener);
expect(call.placeVoiceCall()).rejects.toThrow();
});
describe("hasPeerConnection()", () => {
it("hasPeerConnection() returns false if there is no peer connection", () => {
expect(call.hasPeerConnection).toBe(false);
});
it("hasPeerConnection() returns true if there is a peer connection", async () => {
await call.placeVoiceCall();
expect(call.hasPeerConnection).toBe(true);
});
});
}); });