@@ -37,7 +37,7 @@ import {
3737 MockRTCRtpSender ,
3838} from "../../test-utils/webrtc" ;
3939import { CallFeed } from "../../../src/webrtc/callFeed" ;
40- import { Callback , EventType , IContent , MatrixEvent , Room } from "../../../src" ;
40+ import { Callback , EventType , IContent , ISendEventResponse , MatrixEvent , Room } from "../../../src" ;
4141
4242const FAKE_ROOM_ID = "!foo:bar" ;
4343const CALL_LIFETIME = 60000 ;
@@ -99,7 +99,7 @@ describe('Call', function() {
9999 let prevDocument : Document ;
100100 let prevWindow : Window & typeof globalThis ;
101101 // We retain a reference to this in the correct Mock type
102- let mockSendEvent : jest . Mock < void , [ string , string , IContent , string , Callback < any > ] > ;
102+ let mockSendEvent : jest . Mock < Promise < ISendEventResponse > , [ string , string , IContent , string , Callback < any > ] > ;
103103
104104 beforeEach ( function ( ) {
105105 prevNavigator = global . navigator ;
@@ -888,6 +888,8 @@ describe('Call', function() {
888888 } ) ;
889889
890890 describe ( "answering calls" , ( ) => {
891+ const realSetTimeout = setTimeout ;
892+
891893 beforeEach ( async ( ) => {
892894 await fakeIncomingCall ( client , call , "1" ) ;
893895 } ) ;
@@ -898,11 +900,14 @@ describe('Call', function() {
898900 for ( let tries = 0 ; tries < maxTries ; ++ tries ) {
899901 if ( tries ) {
900902 await new Promise ( resolve => {
901- setTimeout ( resolve , 100 ) ;
903+ realSetTimeout ( resolve , 100 ) ;
902904 } ) ;
903905 }
906+ // We might not always be in fake timer mode, but it's
907+ // fine to run this if not, so we just call it anyway.
908+ jest . runOnlyPendingTimers ( ) ;
904909 try {
905- expect ( client . client . sendEvent ) . toHaveBeenCalledWith ( ...args ) ;
910+ expect ( mockSendEvent ) . toHaveBeenCalledWith ( ...args ) ;
906911 return ;
907912 } catch ( e ) {
908913 if ( tries == maxTries - 1 ) {
@@ -926,35 +931,107 @@ describe('Call', function() {
926931 ) ;
927932 } ) ;
928933
929- it ( "sends ICE candidates as separate events if they arrive after the answer" , async ( ) => {
934+ describe ( "ICE candidate sending" , ( ) => {
935+ let mockPeerConn ;
930936 const fakeCandidateString = "here is a fake candidate!" ;
931-
932- await call . answer ( ) ;
933- await untilEventSent (
934- FAKE_ROOM_ID ,
935- EventType . CallAnswer ,
936- expect . objectContaining ( { } ) ,
937- ) ;
938-
939- const mockPeerConn = call . peerConn as unknown as MockRTCPeerConnection ;
940- mockPeerConn . iceCandidateListener ! ( {
937+ const fakeCandidateEvent = {
941938 candidate : {
942939 candidate : fakeCandidateString ,
943940 sdpMLineIndex : 0 ,
944941 sdpMid : '0' ,
945942 toJSON : jest . fn ( ) . mockReturnValue ( fakeCandidateString ) ,
946943 } ,
947- } as unknown as RTCPeerConnectionIceEvent ) ;
944+ } as unknown as RTCPeerConnectionIceEvent ;
945+
946+ beforeEach ( async ( ) => {
947+ await call . answer ( ) ;
948+ await untilEventSent (
949+ FAKE_ROOM_ID ,
950+ EventType . CallAnswer ,
951+ expect . objectContaining ( { } ) ,
952+ ) ;
953+ mockPeerConn = call . peerConn as unknown as MockRTCPeerConnection ;
954+ } ) ;
948955
949- await untilEventSent (
950- FAKE_ROOM_ID ,
951- EventType . CallCandidates ,
952- expect . objectContaining ( {
953- candidates : [
954- fakeCandidateString ,
955- ] ,
956- } ) ,
957- ) ;
956+ afterEach ( ( ) => {
957+ jest . useRealTimers ( ) ;
958+ } ) ;
959+
960+ it ( "sends ICE candidates as separate events if they arrive after the answer" , async ( ) => {
961+ mockPeerConn ! . iceCandidateListener ! ( fakeCandidateEvent ) ;
962+
963+ await untilEventSent (
964+ FAKE_ROOM_ID ,
965+ EventType . CallCandidates ,
966+ expect . objectContaining ( {
967+ candidates : [
968+ fakeCandidateString ,
969+ ] ,
970+ } ) ,
971+ ) ;
972+ } ) ;
973+
974+ it ( "retries sending ICE candidates" , async ( ) => {
975+ jest . useFakeTimers ( ) ;
976+
977+ mockSendEvent . mockRejectedValueOnce ( new Error ( "Fake error" ) ) ;
978+
979+ mockPeerConn ! . iceCandidateListener ! ( fakeCandidateEvent ) ;
980+
981+ await untilEventSent (
982+ FAKE_ROOM_ID ,
983+ EventType . CallCandidates ,
984+ expect . objectContaining ( {
985+ candidates : [
986+ fakeCandidateString ,
987+ ] ,
988+ } ) ,
989+ ) ;
990+
991+ mockSendEvent . mockClear ( ) ;
992+
993+ await untilEventSent (
994+ FAKE_ROOM_ID ,
995+ EventType . CallCandidates ,
996+ expect . objectContaining ( {
997+ candidates : [
998+ fakeCandidateString ,
999+ ] ,
1000+ } ) ,
1001+ ) ;
1002+ } ) ;
1003+
1004+ it ( "gives up on call after 5 attempts at sending ICE candidates" , async ( ) => {
1005+ jest . useFakeTimers ( ) ;
1006+
1007+ mockSendEvent . mockImplementation ( ( roomId : string , eventType : string ) => {
1008+ if ( eventType === EventType . CallCandidates ) {
1009+ return Promise . reject ( new Error ( ) ) ;
1010+ } else {
1011+ return Promise . resolve ( { event_id : "foo" } ) ;
1012+ }
1013+ } ) ;
1014+
1015+ mockPeerConn ! . iceCandidateListener ! ( fakeCandidateEvent ) ;
1016+
1017+ while ( ! call . callHasEnded ( ) ) {
1018+ jest . runOnlyPendingTimers ( ) ;
1019+ await untilEventSent (
1020+ FAKE_ROOM_ID ,
1021+ EventType . CallCandidates ,
1022+ expect . objectContaining ( {
1023+ candidates : [
1024+ fakeCandidateString ,
1025+ ] ,
1026+ } ) ,
1027+ ) ;
1028+ if ( ! call . callHasEnded ) {
1029+ mockSendEvent . mockReset ( ) ;
1030+ }
1031+ }
1032+
1033+ expect ( call . callHasEnded ( ) ) . toEqual ( true ) ;
1034+ } ) ;
9581035 } ) ;
9591036 } ) ;
9601037
@@ -1006,6 +1083,7 @@ describe('Call', function() {
10061083 const sendNegotiatePromise = new Promise < void > ( resolve => {
10071084 mockSendEvent . mockImplementationOnce ( ( ) => {
10081085 resolve ( ) ;
1086+ return Promise . resolve ( { event_id : "foo" } ) ;
10091087 } ) ;
10101088 } ) ;
10111089
0 commit comments