@webex/plugin-meetings 2.60.0-next.1 → 2.60.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +2 -1
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/in-meeting-actions.js +2 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +155 -103
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +3 -0
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +14 -29
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +17 -0
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +13 -0
- package/dist/meetings/index.js.map +1 -1
- package/dist/metrics/constants.js +1 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reconnection-manager/index.js +26 -26
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/rtcMetrics/index.js +25 -0
- package/dist/rtcMetrics/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +21 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +16 -16
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +21 -22
- package/src/constants.ts +10 -4
- package/src/controls-options-manager/enums.ts +2 -0
- package/src/meeting/in-meeting-actions.ts +4 -0
- package/src/meeting/index.ts +140 -92
- package/src/meeting-info/meeting-info-v2.ts +4 -0
- package/src/meeting-info/utilv2.ts +6 -19
- package/src/meetings/collection.ts +13 -0
- package/src/meetings/index.ts +11 -0
- package/src/metrics/constants.ts +1 -0
- package/src/reconnection-manager/index.ts +62 -66
- package/src/rtcMetrics/index.ts +24 -0
- package/src/statsAnalyzer/index.ts +30 -1
- package/src/statsAnalyzer/mqaUtil.ts +17 -14
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
- package/test/unit/spec/meeting/index.js +1058 -158
- package/test/unit/spec/meeting/muteState.js +2 -1
- package/test/unit/spec/meeting-info/meetinginfov2.js +28 -0
- package/test/unit/spec/meetings/collection.js +12 -0
- package/test/unit/spec/meetings/index.js +306 -118
- package/test/unit/spec/member/util.js +0 -31
- package/test/unit/spec/reconnection-manager/index.js +25 -10
- package/test/unit/spec/rtcMetrics/index.ts +20 -0
- package/test/unit/spec/stats-analyzer/index.js +12 -2
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
NETWORK_STATUS,
|
|
34
34
|
ONLINE,
|
|
35
35
|
OFFLINE,
|
|
36
|
+
RECONNECTION,
|
|
36
37
|
} from '@webex/plugin-meetings/src/constants';
|
|
37
38
|
import * as InternalMediaCoreModule from '@webex/internal-media-core';
|
|
38
39
|
import {
|
|
@@ -827,11 +828,11 @@ describe('plugin-meetings', () => {
|
|
|
827
828
|
});
|
|
828
829
|
|
|
829
830
|
it('should join the meeting and return promise', async () => {
|
|
830
|
-
const join = meeting.join();
|
|
831
|
+
const join = meeting.join({pstnAudioType: 'dial-in'});
|
|
831
832
|
|
|
832
|
-
assert.
|
|
833
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
833
834
|
name: 'client.call.initiated',
|
|
834
|
-
payload: {trigger: 'user-interaction', isRoapCallEnabled: true},
|
|
835
|
+
payload: {trigger: 'user-interaction', isRoapCallEnabled: true, pstnAudioType: 'dial-in'},
|
|
835
836
|
options: {meetingId: meeting.id},
|
|
836
837
|
});
|
|
837
838
|
|
|
@@ -1791,17 +1792,26 @@ describe('plugin-meetings', () => {
|
|
|
1791
1792
|
}]);
|
|
1792
1793
|
|
|
1793
1794
|
const sendBehavioralMetricCalls = Metrics.sendBehavioralMetric.getCalls();
|
|
1794
|
-
assert.equal(sendBehavioralMetricCalls.length,
|
|
1795
|
-
assert.deepEqual(sendBehavioralMetricCalls[0].args, [
|
|
1795
|
+
assert.equal(sendBehavioralMetricCalls.length, 3);
|
|
1796
|
+
assert.deepEqual(sendBehavioralMetricCalls[0].args, [
|
|
1797
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_RETRY,
|
|
1798
|
+
{
|
|
1799
|
+
correlation_id: meeting.correlationId,
|
|
1800
|
+
state: meeting.state,
|
|
1801
|
+
meetingState: meeting.meetingState,
|
|
1802
|
+
reason: 'forcingTurnTls',
|
|
1803
|
+
},
|
|
1804
|
+
]);
|
|
1805
|
+
assert.deepEqual(sendBehavioralMetricCalls[1].args, [
|
|
1796
1806
|
BEHAVIORAL_METRICS.TURN_DISCOVERY_LATENCY,
|
|
1797
1807
|
{
|
|
1798
1808
|
correlation_id: meeting.correlationId,
|
|
1799
1809
|
turnServerUsed: true,
|
|
1800
1810
|
retriedWithTurnServer: true,
|
|
1801
1811
|
latency: undefined,
|
|
1802
|
-
}
|
|
1812
|
+
},
|
|
1803
1813
|
]);
|
|
1804
|
-
assert.deepEqual(sendBehavioralMetricCalls[
|
|
1814
|
+
assert.deepEqual(sendBehavioralMetricCalls[2].args, [
|
|
1805
1815
|
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
|
|
1806
1816
|
{
|
|
1807
1817
|
correlation_id: meeting.correlationId,
|
|
@@ -1816,7 +1826,7 @@ describe('plugin-meetings', () => {
|
|
|
1816
1826
|
signalingState: 'unknown',
|
|
1817
1827
|
connectionState: 'unknown',
|
|
1818
1828
|
iceConnectionState: 'unknown',
|
|
1819
|
-
}
|
|
1829
|
+
},
|
|
1820
1830
|
]);
|
|
1821
1831
|
|
|
1822
1832
|
// Check that doTurnDiscovery is called with th4 correct value of isForced
|
|
@@ -1957,17 +1967,26 @@ describe('plugin-meetings', () => {
|
|
|
1957
1967
|
}]);
|
|
1958
1968
|
|
|
1959
1969
|
const sendBehavioralMetricCalls = Metrics.sendBehavioralMetric.getCalls();
|
|
1960
|
-
assert.equal(sendBehavioralMetricCalls.length,
|
|
1961
|
-
assert.deepEqual(sendBehavioralMetricCalls[0].args, [
|
|
1970
|
+
assert.equal(sendBehavioralMetricCalls.length, 3);
|
|
1971
|
+
assert.deepEqual(sendBehavioralMetricCalls[0].args, [
|
|
1972
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_RETRY,
|
|
1973
|
+
{
|
|
1974
|
+
correlation_id: meeting.correlationId,
|
|
1975
|
+
state: meeting.state,
|
|
1976
|
+
meetingState: meeting.meetingState,
|
|
1977
|
+
reason: 'forcingTurnTls',
|
|
1978
|
+
},
|
|
1979
|
+
]);
|
|
1980
|
+
assert.deepEqual(sendBehavioralMetricCalls[1].args, [
|
|
1962
1981
|
BEHAVIORAL_METRICS.TURN_DISCOVERY_LATENCY,
|
|
1963
1982
|
{
|
|
1964
1983
|
correlation_id: meeting.correlationId,
|
|
1965
1984
|
turnServerUsed: true,
|
|
1966
1985
|
retriedWithTurnServer: true,
|
|
1967
1986
|
latency: undefined,
|
|
1968
|
-
}
|
|
1987
|
+
},
|
|
1969
1988
|
]);
|
|
1970
|
-
assert.deepEqual(sendBehavioralMetricCalls[
|
|
1989
|
+
assert.deepEqual(sendBehavioralMetricCalls[2].args, [
|
|
1971
1990
|
BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS,
|
|
1972
1991
|
{
|
|
1973
1992
|
correlation_id: meeting.correlationId,
|
|
@@ -1975,7 +1994,7 @@ describe('plugin-meetings', () => {
|
|
|
1975
1994
|
connectionType: 'udp',
|
|
1976
1995
|
isMultistream: false,
|
|
1977
1996
|
retriedWithTurnServer: true,
|
|
1978
|
-
}
|
|
1997
|
+
},
|
|
1979
1998
|
]);
|
|
1980
1999
|
meeting.roap.doTurnDiscovery
|
|
1981
2000
|
|
|
@@ -1999,6 +2018,90 @@ describe('plugin-meetings', () => {
|
|
|
1999
2018
|
assert.isNotOk(errorThrown);
|
|
2000
2019
|
});
|
|
2001
2020
|
|
|
2021
|
+
it('should call join if state is LEFT after first media connection attempt', async () => {
|
|
2022
|
+
const FAKE_TURN_URL = 'turns:webex.com:3478';
|
|
2023
|
+
const FAKE_TURN_USER = 'some-turn-username';
|
|
2024
|
+
const FAKE_TURN_PASSWORD = 'some-password';
|
|
2025
|
+
let errorThrown = undefined;
|
|
2026
|
+
|
|
2027
|
+
meeting.meetingState = 'ACTIVE';
|
|
2028
|
+
meeting.state = 'LEFT';
|
|
2029
|
+
meeting.roap.doTurnDiscovery = sinon.stub().onFirstCall().returns({
|
|
2030
|
+
turnServerInfo: undefined,
|
|
2031
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
2032
|
+
}).onSecondCall().returns({
|
|
2033
|
+
turnServerInfo: {
|
|
2034
|
+
url: FAKE_TURN_URL,
|
|
2035
|
+
username: FAKE_TURN_USER,
|
|
2036
|
+
password: FAKE_TURN_PASSWORD,
|
|
2037
|
+
},
|
|
2038
|
+
turnDiscoverySkippedReason: undefined,
|
|
2039
|
+
});
|
|
2040
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().onFirstCall().rejects().onSecondCall().resolves();
|
|
2041
|
+
meeting.join = sinon.stub().resolves();
|
|
2042
|
+
|
|
2043
|
+
const closeMediaConnectionStub = sinon.stub();
|
|
2044
|
+
Media.createMediaConnection = sinon.stub().returns({
|
|
2045
|
+
close: closeMediaConnectionStub,
|
|
2046
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
|
2047
|
+
initiateOffer: sinon.stub().resolves({}),
|
|
2048
|
+
on: sinon.stub(),
|
|
2049
|
+
});
|
|
2050
|
+
|
|
2051
|
+
await meeting
|
|
2052
|
+
.addMedia({
|
|
2053
|
+
mediaSettings: {},
|
|
2054
|
+
})
|
|
2055
|
+
.catch((err) => {
|
|
2056
|
+
errorThrown = err;
|
|
2057
|
+
});
|
|
2058
|
+
|
|
2059
|
+
assert.isNotOk(errorThrown);
|
|
2060
|
+
assert.calledOnceWithExactly(meeting.join, {rejoin: true});
|
|
2061
|
+
});
|
|
2062
|
+
|
|
2063
|
+
it('should reject if join attempt fails if state is LEFT after first media connection attempt', async () => {
|
|
2064
|
+
const FAKE_TURN_URL = 'turns:webex.com:3478';
|
|
2065
|
+
const FAKE_TURN_USER = 'some-turn-username';
|
|
2066
|
+
const FAKE_TURN_PASSWORD = 'some-password';
|
|
2067
|
+
let errorThrown = undefined;
|
|
2068
|
+
|
|
2069
|
+
meeting.meetingState = 'ACTIVE';
|
|
2070
|
+
meeting.state = 'LEFT';
|
|
2071
|
+
meeting.roap.doTurnDiscovery = sinon.stub().onFirstCall().returns({
|
|
2072
|
+
turnServerInfo: undefined,
|
|
2073
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
2074
|
+
}).onSecondCall().returns({
|
|
2075
|
+
turnServerInfo: {
|
|
2076
|
+
url: FAKE_TURN_URL,
|
|
2077
|
+
username: FAKE_TURN_USER,
|
|
2078
|
+
password: FAKE_TURN_PASSWORD,
|
|
2079
|
+
},
|
|
2080
|
+
turnDiscoverySkippedReason: undefined,
|
|
2081
|
+
});
|
|
2082
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().onFirstCall().rejects().onSecondCall().resolves();
|
|
2083
|
+
meeting.join = sinon.stub().rejects();
|
|
2084
|
+
|
|
2085
|
+
const closeMediaConnectionStub = sinon.stub();
|
|
2086
|
+
Media.createMediaConnection = sinon.stub().returns({
|
|
2087
|
+
close: closeMediaConnectionStub,
|
|
2088
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
|
2089
|
+
initiateOffer: sinon.stub().resolves({}),
|
|
2090
|
+
on: sinon.stub(),
|
|
2091
|
+
});
|
|
2092
|
+
|
|
2093
|
+
await meeting
|
|
2094
|
+
.addMedia({
|
|
2095
|
+
mediaSettings: {},
|
|
2096
|
+
})
|
|
2097
|
+
.catch((err) => {
|
|
2098
|
+
errorThrown = err;
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2101
|
+
assert.isOk(errorThrown);
|
|
2102
|
+
assert.calledOnceWithExactly(meeting.join, {rejoin: true});
|
|
2103
|
+
});
|
|
2104
|
+
|
|
2002
2105
|
it('should send ADD_MEDIA_SUCCESS metrics', async () => {
|
|
2003
2106
|
meeting.meetingState = 'ACTIVE';
|
|
2004
2107
|
meeting.webex.meetings.reachability = {
|
|
@@ -2383,6 +2486,7 @@ describe('plugin-meetings', () => {
|
|
|
2383
2486
|
category: 'media',
|
|
2384
2487
|
errorCode: clientErrorCode,
|
|
2385
2488
|
serviceErrorCode: undefined,
|
|
2489
|
+
rawErrorMessage: undefined,
|
|
2386
2490
|
...expectedErrorPayload,
|
|
2387
2491
|
},
|
|
2388
2492
|
],
|
|
@@ -5436,31 +5540,62 @@ describe('plugin-meetings', () => {
|
|
|
5436
5540
|
it('should have #reconnect', () => {
|
|
5437
5541
|
assert.exists(meeting.reconnect);
|
|
5438
5542
|
});
|
|
5543
|
+
|
|
5439
5544
|
describe('successful reconnect', () => {
|
|
5545
|
+
let eventListeners;
|
|
5546
|
+
|
|
5440
5547
|
beforeEach(() => {
|
|
5548
|
+
eventListeners = {};
|
|
5549
|
+
meeting.mediaProperties.webrtcMediaConnection = {
|
|
5550
|
+
// mock the on() method and store all the listeners
|
|
5551
|
+
on: sinon.stub().callsFake((event, listener) => {
|
|
5552
|
+
eventListeners[event] = listener;
|
|
5553
|
+
}),
|
|
5554
|
+
};
|
|
5555
|
+
meeting.setupMediaConnectionListeners();
|
|
5556
|
+
meeting.deferSDPAnswer = {
|
|
5557
|
+
resolve: sinon.stub(),
|
|
5558
|
+
reject: sinon.stub(),
|
|
5559
|
+
};
|
|
5560
|
+
meeting.sdpResponseTimer = '1234';
|
|
5561
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
|
|
5562
|
+
|
|
5563
|
+
eventListeners[Event.REMOTE_SDP_ANSWER_PROCESSED]();
|
|
5441
5564
|
meeting.config.reconnection.enabled = true;
|
|
5442
5565
|
meeting.currentMediaStatus = {audio: true};
|
|
5443
5566
|
meeting.reconnectionManager = new ReconnectionManager(meeting);
|
|
5444
5567
|
meeting.reconnectionManager.reconnect = sinon.stub().returns(Promise.resolve());
|
|
5445
5568
|
meeting.reconnectionManager.reset = sinon.stub().returns(true);
|
|
5446
5569
|
meeting.reconnectionManager.cleanup = sinon.stub().returns(true);
|
|
5570
|
+
meeting.reconnectionManager.setStatus = sinon.stub();
|
|
5447
5571
|
});
|
|
5448
5572
|
|
|
5449
|
-
it('should throw error if media not established before trying
|
|
5573
|
+
it('should throw error if media not established before trying reconnect', async () => {
|
|
5450
5574
|
meeting.currentMediaStatus = null;
|
|
5451
5575
|
await meeting.reconnect().catch((err) => {
|
|
5452
5576
|
assert.instanceOf(err, ParameterError);
|
|
5453
5577
|
});
|
|
5454
5578
|
});
|
|
5455
5579
|
|
|
5456
|
-
it('should trigger reconnection success', async () => {
|
|
5580
|
+
it('should trigger reconnection success and send CA metric', async () => {
|
|
5457
5581
|
await meeting.reconnect();
|
|
5582
|
+
|
|
5458
5583
|
assert.calledWith(
|
|
5459
5584
|
TriggerProxy.trigger,
|
|
5460
5585
|
sinon.match.instanceOf(Meeting),
|
|
5461
5586
|
{file: 'meeting/index', function: 'reconnect'},
|
|
5462
5587
|
'meeting:reconnectionSuccess'
|
|
5463
5588
|
);
|
|
5589
|
+
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
5590
|
+
name: 'client.media.recovered',
|
|
5591
|
+
payload: {
|
|
5592
|
+
recoveredBy: 'new',
|
|
5593
|
+
},
|
|
5594
|
+
options: {
|
|
5595
|
+
meetingId: meeting.id,
|
|
5596
|
+
},
|
|
5597
|
+
});
|
|
5598
|
+
assert.calledOnceWithExactly(meeting.reconnectionManager.setStatus, RECONNECTION.STATE.COMPLETE);
|
|
5464
5599
|
});
|
|
5465
5600
|
|
|
5466
5601
|
it('should reset after reconnection success', async () => {
|
|
@@ -5613,37 +5748,42 @@ describe('plugin-meetings', () => {
|
|
|
5613
5748
|
});
|
|
5614
5749
|
});
|
|
5615
5750
|
|
|
5616
|
-
describe('
|
|
5617
|
-
it('sends client.ice.
|
|
5618
|
-
|
|
5619
|
-
const getErrorPayloadForClientErrorCodeStub = webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon
|
|
5620
|
-
.stub()
|
|
5621
|
-
.returns(FAKE_ERROR);
|
|
5751
|
+
describe('CONNECTION_STATE_CHANGED event when state = "Connecting"', () => {
|
|
5752
|
+
it('sends client.ice.start correctly when hasMediaConnectionConnectedAtLeastOnce = true', () => {
|
|
5753
|
+
meeting.hasMediaConnectionConnectedAtLeastOnce = true;
|
|
5622
5754
|
meeting.setupMediaConnectionListeners();
|
|
5623
5755
|
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5624
|
-
state: '
|
|
5756
|
+
state: 'Connecting',
|
|
5757
|
+
});
|
|
5758
|
+
|
|
5759
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
5760
|
+
})
|
|
5761
|
+
|
|
5762
|
+
it('sends client.ice.start correctly when hasMediaConnectionConnectedAtLeastOnce = false', () => {
|
|
5763
|
+
meeting.hasMediaConnectionConnectedAtLeastOnce = false;
|
|
5764
|
+
meeting.setupMediaConnectionListeners();
|
|
5765
|
+
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5766
|
+
state: 'Connecting',
|
|
5625
5767
|
});
|
|
5626
|
-
|
|
5768
|
+
|
|
5627
5769
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
5628
5770
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
5629
|
-
name: 'client.ice.
|
|
5630
|
-
payload: {
|
|
5631
|
-
canProceed: false,
|
|
5632
|
-
icePhase: 'IN_MEETING',
|
|
5633
|
-
errors: [FAKE_ERROR],
|
|
5634
|
-
},
|
|
5771
|
+
name: 'client.ice.start',
|
|
5635
5772
|
options: {
|
|
5636
5773
|
meetingId: meeting.id,
|
|
5637
5774
|
},
|
|
5638
5775
|
});
|
|
5639
|
-
})
|
|
5776
|
+
})
|
|
5640
5777
|
});
|
|
5641
5778
|
|
|
5642
5779
|
describe('submitClientEvent on connectionSuccess', () => {
|
|
5643
|
-
|
|
5780
|
+
let setNetworkStatusSpy;
|
|
5781
|
+
|
|
5782
|
+
const setupSpies = () => {
|
|
5783
|
+
setNetworkStatusSpy = sinon.spy(meeting, 'setNetworkStatus');
|
|
5784
|
+
|
|
5644
5785
|
meeting.reconnectionManager = new ReconnectionManager(meeting);
|
|
5645
5786
|
meeting.reconnectionManager.iceReconnected = sinon.stub().returns(undefined);
|
|
5646
|
-
meeting.setNetworkStatus = sinon.stub().returns(undefined);
|
|
5647
5787
|
meeting.statsAnalyzer = {startAnalyzer: sinon.stub()};
|
|
5648
5788
|
meeting.mediaProperties.webrtcMediaConnection = {
|
|
5649
5789
|
// mock the on() method and store all the listeners
|
|
@@ -5651,113 +5791,302 @@ describe('plugin-meetings', () => {
|
|
|
5651
5791
|
eventListeners[event] = listener;
|
|
5652
5792
|
}),
|
|
5653
5793
|
};
|
|
5794
|
+
};
|
|
5654
5795
|
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5796
|
+
const checkExpectedSpies = (expected) => {
|
|
5797
|
+
if (expected.icePhase) {
|
|
5798
|
+
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
5799
|
+
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
5800
|
+
name: 'client.ice.end',
|
|
5801
|
+
options: {
|
|
5802
|
+
meetingId: meeting.id,
|
|
5803
|
+
},
|
|
5804
|
+
payload: {
|
|
5805
|
+
canProceed: true,
|
|
5806
|
+
icePhase: expected.icePhase,
|
|
5807
|
+
},
|
|
5808
|
+
});
|
|
5809
|
+
} else {
|
|
5810
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
5811
|
+
}
|
|
5666
5812
|
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
5667
5813
|
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.CONNECTION_SUCCESS, {
|
|
5668
5814
|
correlation_id: meeting.correlationId,
|
|
5669
5815
|
locus_id: meeting.locusId,
|
|
5670
5816
|
latency: undefined,
|
|
5671
5817
|
});
|
|
5672
|
-
assert.
|
|
5673
|
-
|
|
5818
|
+
assert.deepEqual(
|
|
5819
|
+
setNetworkStatusSpy.getCalls().map((call) => call.args[0]),
|
|
5820
|
+
expected.setNetworkStatusCallParams
|
|
5821
|
+
);
|
|
5674
5822
|
assert.calledOnce(meeting.reconnectionManager.iceReconnected);
|
|
5675
5823
|
assert.calledOnce(meeting.statsAnalyzer.startAnalyzer);
|
|
5676
5824
|
assert.calledWith(
|
|
5677
5825
|
meeting.statsAnalyzer.startAnalyzer,
|
|
5678
5826
|
meeting.mediaProperties.webrtcMediaConnection
|
|
5679
5827
|
);
|
|
5828
|
+
};
|
|
5829
|
+
|
|
5830
|
+
const resetSpies = () => {
|
|
5831
|
+
setNetworkStatusSpy.resetHistory();
|
|
5832
|
+
webex.internal.newMetrics.submitClientEvent.resetHistory();
|
|
5833
|
+
Metrics.sendBehavioralMetric.resetHistory();
|
|
5834
|
+
meeting.reconnectionManager.iceReconnected.resetHistory();
|
|
5835
|
+
meeting.statsAnalyzer.startAnalyzer.resetHistory();
|
|
5836
|
+
};
|
|
5837
|
+
|
|
5838
|
+
it('sends client.ice.end with the correct icePhase when we get ConnectionState.Connected on CONNECTION_STATE_CHANGED event', () => {
|
|
5839
|
+
setupSpies();
|
|
5840
|
+
|
|
5841
|
+
meeting.setupMediaConnectionListeners();
|
|
5842
|
+
|
|
5843
|
+
assert.equal(meeting.hasMediaConnectionConnectedAtLeastOnce, false);
|
|
5844
|
+
|
|
5845
|
+
// simulate first connection success
|
|
5846
|
+
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5847
|
+
state: 'Connected',
|
|
5848
|
+
});
|
|
5849
|
+
checkExpectedSpies({
|
|
5850
|
+
icePhase: 'JOIN_MEETING_FINAL',
|
|
5851
|
+
setNetworkStatusCallParams: [NETWORK_STATUS.CONNECTED],
|
|
5852
|
+
});
|
|
5853
|
+
assert.equal(meeting.hasMediaConnectionConnectedAtLeastOnce, true);
|
|
5854
|
+
|
|
5855
|
+
// now simulate short connection loss, client.ice.end is not sent a second time as hasMediaConnectionConnectedAtLeastOnce = true
|
|
5856
|
+
resetSpies();
|
|
5857
|
+
|
|
5858
|
+
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5859
|
+
state: 'Disconnected',
|
|
5860
|
+
});
|
|
5861
|
+
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5862
|
+
state: 'Connected',
|
|
5863
|
+
});
|
|
5864
|
+
|
|
5865
|
+
checkExpectedSpies({
|
|
5866
|
+
setNetworkStatusCallParams: [NETWORK_STATUS.DISCONNECTED, NETWORK_STATUS.CONNECTED],
|
|
5867
|
+
});
|
|
5868
|
+
|
|
5869
|
+
resetSpies();
|
|
5870
|
+
|
|
5871
|
+
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5872
|
+
state: 'Disconnected',
|
|
5873
|
+
});
|
|
5874
|
+
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5875
|
+
state: 'Connected',
|
|
5876
|
+
});
|
|
5680
5877
|
});
|
|
5681
5878
|
});
|
|
5682
5879
|
|
|
5683
|
-
describe('
|
|
5684
|
-
const fakeErrorMessage = 'test error';
|
|
5685
|
-
const fakeRootCauseName = 'root cause name';
|
|
5686
|
-
const fakeErrorName = 'test error name';
|
|
5687
|
-
|
|
5880
|
+
describe('CONNECTION_STATE_CHANGED event when state = "Disconnected"', () => {
|
|
5688
5881
|
beforeEach(() => {
|
|
5689
|
-
meeting.
|
|
5882
|
+
meeting.reconnectionManager = new ReconnectionManager(meeting);
|
|
5883
|
+
meeting.reconnectionManager.iceReconnected = sinon.stub().returns(undefined);
|
|
5884
|
+
meeting.setNetworkStatus = sinon.stub().returns(undefined);
|
|
5885
|
+
meeting.statsAnalyzer = {startAnalyzer: sinon.stub()};
|
|
5886
|
+
meeting.mediaProperties.webrtcMediaConnection = {
|
|
5887
|
+
// mock the on() method and store all the listeners
|
|
5888
|
+
on: sinon.stub().callsFake((event, listener) => {
|
|
5889
|
+
eventListeners[event] = listener;
|
|
5890
|
+
}),
|
|
5891
|
+
};
|
|
5892
|
+
meeting.reconnect = sinon.stub().resolves();
|
|
5690
5893
|
});
|
|
5691
5894
|
|
|
5692
|
-
const
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
payload: {
|
|
5697
|
-
canProceed: false,
|
|
5698
|
-
},
|
|
5699
|
-
options: {rawError: error, meetingId: meeting.id},
|
|
5895
|
+
const mockDisconnectedEvent = () => {
|
|
5896
|
+
meeting.setupMediaConnectionListeners();
|
|
5897
|
+
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5898
|
+
state: 'Disconnected',
|
|
5700
5899
|
});
|
|
5701
5900
|
};
|
|
5702
5901
|
|
|
5703
|
-
const checkBehavioralMetricSent = (
|
|
5704
|
-
metricName,
|
|
5705
|
-
expectedCode,
|
|
5706
|
-
expectedReason,
|
|
5707
|
-
expectedMetadataType
|
|
5708
|
-
) => {
|
|
5902
|
+
const checkBehavioralMetricSent = (hasMediaConnectionConnectedAtLeastOnce = false) => {
|
|
5709
5903
|
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
5710
5904
|
assert.calledWith(
|
|
5711
5905
|
Metrics.sendBehavioralMetric,
|
|
5712
|
-
|
|
5906
|
+
BEHAVIORAL_METRICS.CONNECTION_FAILURE,
|
|
5713
5907
|
{
|
|
5714
|
-
code: expectedCode,
|
|
5715
5908
|
correlation_id: meeting.correlationId,
|
|
5716
|
-
|
|
5717
|
-
|
|
5909
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
5910
|
+
networkStatus: meeting.networkStatus,
|
|
5911
|
+
hasMediaConnectionConnectedAtLeastOnce,
|
|
5718
5912
|
},
|
|
5719
|
-
{
|
|
5720
|
-
type: expectedMetadataType,
|
|
5721
|
-
}
|
|
5722
5913
|
);
|
|
5723
5914
|
};
|
|
5724
5915
|
|
|
5725
|
-
it('
|
|
5726
|
-
|
|
5727
|
-
name: fakeErrorName,
|
|
5728
|
-
cause: {name: fakeRootCauseName},
|
|
5729
|
-
});
|
|
5730
|
-
|
|
5731
|
-
eventListeners[Event.ROAP_FAILURE](fakeError);
|
|
5916
|
+
it('handles "Disconnected" state correctly when waitForIceReconnect resolves', async () => {
|
|
5917
|
+
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().resolves();
|
|
5732
5918
|
|
|
5733
|
-
checkMetricSent('client.media-engine.local-sdp-generated', fakeError);
|
|
5734
|
-
checkBehavioralMetricSent(
|
|
5735
|
-
BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE,
|
|
5736
|
-
Errors.ErrorCode.SdpOfferCreationError,
|
|
5737
|
-
fakeErrorMessage,
|
|
5738
|
-
fakeRootCauseName
|
|
5739
|
-
);
|
|
5740
|
-
});
|
|
5741
5919
|
|
|
5742
|
-
|
|
5743
|
-
const fakeError = new Errors.SdpOfferHandlingError(fakeErrorMessage, {
|
|
5744
|
-
name: fakeErrorName,
|
|
5745
|
-
cause: {name: fakeRootCauseName},
|
|
5746
|
-
});
|
|
5920
|
+
mockDisconnectedEvent();
|
|
5747
5921
|
|
|
5748
|
-
|
|
5922
|
+
await testUtils.flushPromises();
|
|
5749
5923
|
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
fakeRootCauseName
|
|
5756
|
-
);
|
|
5924
|
+
assert.calledOnce(meeting.setNetworkStatus);
|
|
5925
|
+
assert.calledWith(meeting.setNetworkStatus, NETWORK_STATUS.DISCONNECTED);
|
|
5926
|
+
assert.calledOnce(meeting.reconnectionManager.waitForIceReconnect);
|
|
5927
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
5928
|
+
assert.notCalled(Metrics.sendBehavioralMetric);
|
|
5757
5929
|
});
|
|
5758
5930
|
|
|
5759
|
-
it('
|
|
5760
|
-
const
|
|
5931
|
+
it('handles "Disconnected" state correctly when waitForIceReconnect rejects and hasMediaConnectionConnectedAtLeastOnce = true', async () => {
|
|
5932
|
+
const FAKE_ERROR = {fatal: true};
|
|
5933
|
+
const getErrorPayloadForClientErrorCodeStub = webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon
|
|
5934
|
+
.stub()
|
|
5935
|
+
.returns(FAKE_ERROR);
|
|
5936
|
+
meeting.waitForMediaConnectionConnected = sinon.stub().resolves();
|
|
5937
|
+
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().rejects();
|
|
5938
|
+
meeting.hasMediaConnectionConnectedAtLeastOnce = true;
|
|
5939
|
+
|
|
5940
|
+
|
|
5941
|
+
mockDisconnectedEvent();
|
|
5942
|
+
|
|
5943
|
+
await testUtils.flushPromises();
|
|
5944
|
+
|
|
5945
|
+
assert.calledOnce(meeting.setNetworkStatus);
|
|
5946
|
+
assert.calledWith(meeting.setNetworkStatus, NETWORK_STATUS.DISCONNECTED);
|
|
5947
|
+
assert.calledOnce(meeting.reconnectionManager.waitForIceReconnect);
|
|
5948
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
5949
|
+
checkBehavioralMetricSent(true);
|
|
5950
|
+
});
|
|
5951
|
+
|
|
5952
|
+
it('handles "Disconnected" state correctly when waitForIceReconnect rejects and hasMediaConnectionConnectedAtLeastOnce = false', async () => {
|
|
5953
|
+
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().rejects();
|
|
5954
|
+
|
|
5955
|
+
|
|
5956
|
+
mockDisconnectedEvent();
|
|
5957
|
+
|
|
5958
|
+
await testUtils.flushPromises();
|
|
5959
|
+
|
|
5960
|
+
assert.calledOnce(meeting.setNetworkStatus);
|
|
5961
|
+
assert.calledWith(meeting.setNetworkStatus, NETWORK_STATUS.DISCONNECTED);
|
|
5962
|
+
assert.calledOnce(meeting.reconnectionManager.waitForIceReconnect);
|
|
5963
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
5964
|
+
checkBehavioralMetricSent();
|
|
5965
|
+
});
|
|
5966
|
+
});
|
|
5967
|
+
|
|
5968
|
+
describe('CONNECTION_STATE_CHANGED event when state = "Failed"', () => {
|
|
5969
|
+
|
|
5970
|
+
const mockFailedEvent = () => {
|
|
5971
|
+
meeting.setupMediaConnectionListeners();
|
|
5972
|
+
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
5973
|
+
state: 'Failed',
|
|
5974
|
+
});
|
|
5975
|
+
};
|
|
5976
|
+
|
|
5977
|
+
const checkBehavioralMetricSent = (hasMediaConnectionConnectedAtLeastOnce = false) => {
|
|
5978
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
5979
|
+
assert.calledWith(
|
|
5980
|
+
Metrics.sendBehavioralMetric,
|
|
5981
|
+
BEHAVIORAL_METRICS.CONNECTION_FAILURE,
|
|
5982
|
+
{
|
|
5983
|
+
correlation_id: meeting.correlationId,
|
|
5984
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
5985
|
+
networkStatus: meeting.networkStatus,
|
|
5986
|
+
hasMediaConnectionConnectedAtLeastOnce,
|
|
5987
|
+
},
|
|
5988
|
+
);
|
|
5989
|
+
};
|
|
5990
|
+
|
|
5991
|
+
it('handles "Failed" state correctly when hasMediaConnectionConnectedAtLeastOnce = false', async () => {
|
|
5992
|
+
meeting.waitForMediaConnectionConnected = sinon.stub().resolves();
|
|
5993
|
+
|
|
5994
|
+
mockFailedEvent();
|
|
5995
|
+
|
|
5996
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
5997
|
+
checkBehavioralMetricSent();
|
|
5998
|
+
});
|
|
5999
|
+
|
|
6000
|
+
it('handles "Failed" state correctly when hasMediaConnectionConnectedAtLeastOnce = true', async () => {
|
|
6001
|
+
meeting.hasMediaConnectionConnectedAtLeastOnce = true;
|
|
6002
|
+
|
|
6003
|
+
mockFailedEvent();
|
|
6004
|
+
|
|
6005
|
+
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
6006
|
+
checkBehavioralMetricSent(true);
|
|
6007
|
+
});
|
|
6008
|
+
});
|
|
6009
|
+
|
|
6010
|
+
describe('should send correct metrics for ROAP_FAILURE event', () => {
|
|
6011
|
+
const fakeErrorMessage = 'test error';
|
|
6012
|
+
const fakeRootCauseName = 'root cause name';
|
|
6013
|
+
const fakeErrorName = 'test error name';
|
|
6014
|
+
|
|
6015
|
+
beforeEach(() => {
|
|
6016
|
+
meeting.setupMediaConnectionListeners();
|
|
6017
|
+
webex.internal.newMetrics.submitClientEvent.resetHistory();
|
|
6018
|
+
Metrics.sendBehavioralMetric.resetHistory();
|
|
6019
|
+
});
|
|
6020
|
+
|
|
6021
|
+
const checkMetricSent = (event, error) => {
|
|
6022
|
+
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
6023
|
+
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
6024
|
+
name: event,
|
|
6025
|
+
payload: {
|
|
6026
|
+
canProceed: false,
|
|
6027
|
+
},
|
|
6028
|
+
options: {rawError: error, meetingId: meeting.id},
|
|
6029
|
+
});
|
|
6030
|
+
};
|
|
6031
|
+
|
|
6032
|
+
const checkBehavioralMetricSent = (
|
|
6033
|
+
metricName,
|
|
6034
|
+
expectedCode,
|
|
6035
|
+
expectedReason,
|
|
6036
|
+
expectedMetadataType
|
|
6037
|
+
) => {
|
|
6038
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
6039
|
+
assert.calledWith(
|
|
6040
|
+
Metrics.sendBehavioralMetric,
|
|
6041
|
+
metricName,
|
|
6042
|
+
{
|
|
6043
|
+
code: expectedCode,
|
|
6044
|
+
correlation_id: meeting.correlationId,
|
|
6045
|
+
reason: expectedReason,
|
|
6046
|
+
stack: sinon.match.any,
|
|
6047
|
+
},
|
|
6048
|
+
{
|
|
6049
|
+
type: expectedMetadataType,
|
|
6050
|
+
}
|
|
6051
|
+
);
|
|
6052
|
+
};
|
|
6053
|
+
|
|
6054
|
+
it('should send metrics for SdpOfferCreationError error', () => {
|
|
6055
|
+
const fakeError = new Errors.SdpOfferCreationError(fakeErrorMessage, {
|
|
6056
|
+
name: fakeErrorName,
|
|
6057
|
+
cause: {name: fakeRootCauseName},
|
|
6058
|
+
});
|
|
6059
|
+
|
|
6060
|
+
eventListeners[Event.ROAP_FAILURE](fakeError);
|
|
6061
|
+
|
|
6062
|
+
checkMetricSent('client.media-engine.local-sdp-generated', fakeError);
|
|
6063
|
+
checkBehavioralMetricSent(
|
|
6064
|
+
BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE,
|
|
6065
|
+
Errors.ErrorCode.SdpOfferCreationError,
|
|
6066
|
+
fakeErrorMessage,
|
|
6067
|
+
fakeRootCauseName
|
|
6068
|
+
);
|
|
6069
|
+
});
|
|
6070
|
+
|
|
6071
|
+
it('should send metrics for SdpOfferHandlingError error', () => {
|
|
6072
|
+
const fakeError = new Errors.SdpOfferHandlingError(fakeErrorMessage, {
|
|
6073
|
+
name: fakeErrorName,
|
|
6074
|
+
cause: {name: fakeRootCauseName},
|
|
6075
|
+
});
|
|
6076
|
+
|
|
6077
|
+
eventListeners[Event.ROAP_FAILURE](fakeError);
|
|
6078
|
+
|
|
6079
|
+
checkMetricSent('client.media-engine.remote-sdp-received', fakeError);
|
|
6080
|
+
checkBehavioralMetricSent(
|
|
6081
|
+
BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE,
|
|
6082
|
+
Errors.ErrorCode.SdpOfferHandlingError,
|
|
6083
|
+
fakeErrorMessage,
|
|
6084
|
+
fakeRootCauseName
|
|
6085
|
+
);
|
|
6086
|
+
});
|
|
6087
|
+
|
|
6088
|
+
it('should send metrics for SdpAnswerHandlingError error', () => {
|
|
6089
|
+
const fakeError = new Errors.SdpAnswerHandlingError(fakeErrorMessage, {
|
|
5761
6090
|
name: fakeErrorName,
|
|
5762
6091
|
cause: {name: fakeRootCauseName},
|
|
5763
6092
|
});
|
|
@@ -6732,6 +7061,7 @@ describe('plugin-meetings', () => {
|
|
|
6732
7061
|
done();
|
|
6733
7062
|
});
|
|
6734
7063
|
});
|
|
7064
|
+
|
|
6735
7065
|
describe('#setUpLocusInfoMediaInactiveListener', () => {
|
|
6736
7066
|
it('listens to disconnect due to un activity ', (done) => {
|
|
6737
7067
|
TriggerProxy.trigger.reset();
|
|
@@ -6977,12 +7307,14 @@ describe('plugin-meetings', () => {
|
|
|
6977
7307
|
});
|
|
6978
7308
|
describe('#closePeerConnections', () => {
|
|
6979
7309
|
it('should close the webrtc media connection, and return a promise', async () => {
|
|
7310
|
+
const setNetworkStatusSpy = sinon.spy(meeting, 'setNetworkStatus');
|
|
6980
7311
|
meeting.mediaProperties.webrtcMediaConnection = {close: sinon.stub()};
|
|
6981
7312
|
const pcs = meeting.closePeerConnections();
|
|
6982
7313
|
|
|
6983
7314
|
assert.exists(pcs.then);
|
|
6984
7315
|
await pcs;
|
|
6985
7316
|
assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.close);
|
|
7317
|
+
assert.calledOnceWithExactly(setNetworkStatusSpy, undefined);
|
|
6986
7318
|
});
|
|
6987
7319
|
});
|
|
6988
7320
|
describe('#unsetPeerConnections', () => {
|
|
@@ -7246,47 +7578,12 @@ describe('plugin-meetings', () => {
|
|
|
7246
7578
|
});
|
|
7247
7579
|
|
|
7248
7580
|
describe('#setUpLocusInfoMeetingInfoListener', () => {
|
|
7249
|
-
let inMeetingActionsSetSpy;
|
|
7250
|
-
let canUserLockSpy;
|
|
7251
|
-
let canUserUnlockSpy;
|
|
7252
|
-
let canUserStartSpy;
|
|
7253
|
-
let canUserStopSpy;
|
|
7254
|
-
let canUserPauseSpy;
|
|
7255
|
-
let canUserResumeSpy;
|
|
7256
|
-
let canSetMuteOnEntrySpy;
|
|
7257
|
-
let canUnsetMuteOnEntrySpy;
|
|
7258
|
-
let canSetDisallowUnmuteSpy;
|
|
7259
|
-
let canUnsetDisallowUnmuteSpy;
|
|
7260
|
-
let canUserRaiseHandSpy;
|
|
7261
|
-
let bothLeaveAndEndMeetingAvailableSpy;
|
|
7262
|
-
let canUserLowerAllHandsSpy;
|
|
7263
|
-
let canUserLowerSomeoneElsesHandSpy;
|
|
7264
|
-
let waitingForOthersToJoinSpy;
|
|
7265
7581
|
let locusInfoOnSpy;
|
|
7266
7582
|
let handleDataChannelUrlChangeSpy;
|
|
7267
7583
|
let updateMeetingActionsSpy;
|
|
7268
7584
|
|
|
7269
7585
|
beforeEach(() => {
|
|
7270
7586
|
locusInfoOnSpy = sinon.spy(meeting.locusInfo, 'on');
|
|
7271
|
-
canUserLockSpy = sinon.spy(MeetingUtil, 'canUserLock');
|
|
7272
|
-
canUserUnlockSpy = sinon.spy(MeetingUtil, 'canUserUnlock');
|
|
7273
|
-
canUserStartSpy = sinon.spy(RecordingUtil, 'canUserStart');
|
|
7274
|
-
canUserStopSpy = sinon.spy(RecordingUtil, 'canUserStop');
|
|
7275
|
-
canUserPauseSpy = sinon.spy(RecordingUtil, 'canUserPause');
|
|
7276
|
-
canUserResumeSpy = sinon.spy(RecordingUtil, 'canUserResume');
|
|
7277
|
-
canSetMuteOnEntrySpy = sinon.spy(ControlsOptionsUtil, 'canSetMuteOnEntry');
|
|
7278
|
-
canUnsetMuteOnEntrySpy = sinon.spy(ControlsOptionsUtil, 'canUnsetMuteOnEntry');
|
|
7279
|
-
canSetDisallowUnmuteSpy = sinon.spy(ControlsOptionsUtil, 'canSetDisallowUnmute');
|
|
7280
|
-
canUnsetDisallowUnmuteSpy = sinon.spy(ControlsOptionsUtil, 'canUnsetDisallowUnmute');
|
|
7281
|
-
inMeetingActionsSetSpy = sinon.spy(meeting.inMeetingActions, 'set');
|
|
7282
|
-
canUserRaiseHandSpy = sinon.spy(MeetingUtil, 'canUserRaiseHand');
|
|
7283
|
-
canUserLowerAllHandsSpy = sinon.spy(MeetingUtil, 'canUserLowerAllHands');
|
|
7284
|
-
bothLeaveAndEndMeetingAvailableSpy = sinon.spy(
|
|
7285
|
-
MeetingUtil,
|
|
7286
|
-
'bothLeaveAndEndMeetingAvailable'
|
|
7287
|
-
);
|
|
7288
|
-
canUserLowerSomeoneElsesHandSpy = sinon.spy(MeetingUtil, 'canUserLowerSomeoneElsesHand');
|
|
7289
|
-
waitingForOthersToJoinSpy = sinon.spy(MeetingUtil, 'waitingForOthersToJoin');
|
|
7290
7587
|
handleDataChannelUrlChangeSpy = sinon.spy(meeting, 'handleDataChannelUrlChange');
|
|
7291
7588
|
updateMeetingActionsSpy = sinon.spy(meeting, 'updateMeetingActions');
|
|
7292
7589
|
});
|
|
@@ -7324,29 +7621,632 @@ describe('plugin-meetings', () => {
|
|
|
7324
7621
|
assert.equal(locusInfoOnSpy.thirdCall.args[0], 'MEETING_INFO_UPDATED');
|
|
7325
7622
|
const callback = locusInfoOnSpy.thirdCall.args[1];
|
|
7326
7623
|
|
|
7327
|
-
const payload = {
|
|
7328
|
-
info: {
|
|
7329
|
-
userDisplayHints: ['LOCK_CONTROL_UNLOCK'],
|
|
7330
|
-
},
|
|
7331
|
-
};
|
|
7332
|
-
|
|
7333
7624
|
callback();
|
|
7334
7625
|
|
|
7335
|
-
assert.calledWith(
|
|
7336
|
-
assert.calledWith(
|
|
7337
|
-
assert.calledWith(
|
|
7338
|
-
assert.calledWith(
|
|
7339
|
-
assert.calledWith(
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7626
|
+
assert.calledWith(updateMeetingActionsSpy);
|
|
7627
|
+
assert.calledWith(setRecordingDisplayHintsSpy, userDisplayHints);
|
|
7628
|
+
assert.calledWith(setUserPolicySpy, userDisplayPolicy);
|
|
7629
|
+
assert.calledWith(setControlsDisplayHintsSpy, userDisplayHints);
|
|
7630
|
+
assert.calledWith(handleDataChannelUrlChangeSpy, datachannelUrl);
|
|
7631
|
+
});
|
|
7632
|
+
});
|
|
7633
|
+
|
|
7634
|
+
describe('#updateMeetingActions', () => {
|
|
7635
|
+
let inMeetingActionsSetSpy;
|
|
7636
|
+
let canUserLockSpy;
|
|
7637
|
+
let canUserUnlockSpy;
|
|
7638
|
+
let canUserStartSpy;
|
|
7639
|
+
let canUserStopSpy;
|
|
7640
|
+
let canUserPauseSpy;
|
|
7641
|
+
let canUserResumeSpy;
|
|
7642
|
+
let canSetMuteOnEntrySpy;
|
|
7643
|
+
let canUnsetMuteOnEntrySpy;
|
|
7644
|
+
let canSetDisallowUnmuteSpy;
|
|
7645
|
+
let canUnsetDisallowUnmuteSpy;
|
|
7646
|
+
let canUserRaiseHandSpy;
|
|
7647
|
+
let bothLeaveAndEndMeetingAvailableSpy;
|
|
7648
|
+
let canUserLowerAllHandsSpy;
|
|
7649
|
+
let canUserLowerSomeoneElsesHandSpy;
|
|
7650
|
+
let waitingForOthersToJoinSpy;
|
|
7651
|
+
let canSendReactionsSpy;
|
|
7652
|
+
let canUserRenameSelfAndObservedSpy;
|
|
7653
|
+
let canUserRenameOthersSpy;
|
|
7654
|
+
let canShareWhiteBoardSpy;
|
|
7655
|
+
// Due to import tree issues, hasHints must be stubed within the scope of the `it`.
|
|
7656
|
+
|
|
7657
|
+
beforeEach(() => {
|
|
7658
|
+
canUserLockSpy = sinon.spy(MeetingUtil, 'canUserLock');
|
|
7659
|
+
canUserUnlockSpy = sinon.spy(MeetingUtil, 'canUserUnlock');
|
|
7660
|
+
canUserStartSpy = sinon.spy(RecordingUtil, 'canUserStart');
|
|
7661
|
+
canUserStopSpy = sinon.spy(RecordingUtil, 'canUserStop');
|
|
7662
|
+
canUserPauseSpy = sinon.spy(RecordingUtil, 'canUserPause');
|
|
7663
|
+
canUserResumeSpy = sinon.spy(RecordingUtil, 'canUserResume');
|
|
7664
|
+
canSetMuteOnEntrySpy = sinon.spy(ControlsOptionsUtil, 'canSetMuteOnEntry');
|
|
7665
|
+
canUnsetMuteOnEntrySpy = sinon.spy(ControlsOptionsUtil, 'canUnsetMuteOnEntry');
|
|
7666
|
+
canSetDisallowUnmuteSpy = sinon.spy(ControlsOptionsUtil, 'canSetDisallowUnmute');
|
|
7667
|
+
canUnsetDisallowUnmuteSpy = sinon.spy(ControlsOptionsUtil, 'canUnsetDisallowUnmute');
|
|
7668
|
+
inMeetingActionsSetSpy = sinon.spy(meeting.inMeetingActions, 'set');
|
|
7669
|
+
canUserRaiseHandSpy = sinon.spy(MeetingUtil, 'canUserRaiseHand');
|
|
7670
|
+
canUserLowerAllHandsSpy = sinon.spy(MeetingUtil, 'canUserLowerAllHands');
|
|
7671
|
+
bothLeaveAndEndMeetingAvailableSpy = sinon.spy(
|
|
7672
|
+
MeetingUtil,
|
|
7673
|
+
'bothLeaveAndEndMeetingAvailable'
|
|
7674
|
+
);
|
|
7675
|
+
canUserLowerSomeoneElsesHandSpy = sinon.spy(MeetingUtil, 'canUserLowerSomeoneElsesHand');
|
|
7676
|
+
waitingForOthersToJoinSpy = sinon.spy(MeetingUtil, 'waitingForOthersToJoin');
|
|
7677
|
+
canSendReactionsSpy = sinon.spy(MeetingUtil, 'canSendReactions');
|
|
7678
|
+
canUserRenameSelfAndObservedSpy = sinon.spy(MeetingUtil, 'canUserRenameSelfAndObserved');
|
|
7679
|
+
canUserRenameOthersSpy = sinon.spy(MeetingUtil, 'canUserRenameOthers');
|
|
7680
|
+
canShareWhiteBoardSpy = sinon.spy(MeetingUtil, 'canShareWhiteBoard');
|
|
7681
|
+
});
|
|
7682
|
+
|
|
7683
|
+
afterEach(() => {
|
|
7684
|
+
inMeetingActionsSetSpy.restore();
|
|
7685
|
+
waitingForOthersToJoinSpy.restore();
|
|
7686
|
+
});
|
|
7687
|
+
|
|
7688
|
+
forEach(
|
|
7689
|
+
[
|
|
7690
|
+
{
|
|
7691
|
+
actionName: 'canShareApplication',
|
|
7692
|
+
expectedEnabled: true,
|
|
7693
|
+
arePolicyRestrictionsSupported: false,
|
|
7694
|
+
},
|
|
7695
|
+
{
|
|
7696
|
+
actionName: 'canShareApplication',
|
|
7697
|
+
expectedEnabled: false,
|
|
7698
|
+
arePolicyRestrictionsSupported: true,
|
|
7699
|
+
},
|
|
7700
|
+
{
|
|
7701
|
+
actionName: 'canShareDesktop',
|
|
7702
|
+
arePolicyRestrictionsSupported: false,
|
|
7703
|
+
expectedEnabled: true,
|
|
7704
|
+
},
|
|
7705
|
+
{
|
|
7706
|
+
actionName: 'canShareDesktop',
|
|
7707
|
+
arePolicyRestrictionsSupported: true,
|
|
7708
|
+
expectedEnabled: false,
|
|
7709
|
+
},
|
|
7710
|
+
{
|
|
7711
|
+
actionName: 'canShareContent',
|
|
7712
|
+
arePolicyRestrictionsSupported: false,
|
|
7713
|
+
expectedEnabled: true,
|
|
7714
|
+
},
|
|
7715
|
+
{
|
|
7716
|
+
actionName: 'canShareContent',
|
|
7717
|
+
arePolicyRestrictionsSupported: true,
|
|
7718
|
+
expectedEnabled: false,
|
|
7719
|
+
},
|
|
7720
|
+
{
|
|
7721
|
+
actionName: 'canUseVoip',
|
|
7722
|
+
expectedEnabled: true,
|
|
7723
|
+
arePolicyRestrictionsSupported: false,
|
|
7724
|
+
},
|
|
7725
|
+
{
|
|
7726
|
+
actionName: 'canUseVoip',
|
|
7727
|
+
expectedEnabled: false,
|
|
7728
|
+
arePolicyRestrictionsSupported: true,
|
|
7729
|
+
},
|
|
7730
|
+
],
|
|
7731
|
+
({actionName, arePolicyRestrictionsSupported, expectedEnabled}) => {
|
|
7732
|
+
it(`${actionName} is ${expectedEnabled} when the call type is ${arePolicyRestrictionsSupported}`, () => {
|
|
7733
|
+
meeting.userDisplayHints = [];
|
|
7734
|
+
meeting.meetingInfo = {some: 'info'};
|
|
7735
|
+
sinon
|
|
7736
|
+
.stub(meeting, 'arePolicyRestrictionsSupported')
|
|
7737
|
+
.returns(arePolicyRestrictionsSupported);
|
|
7738
|
+
|
|
7739
|
+
meeting.updateMeetingActions();
|
|
7740
|
+
|
|
7741
|
+
assert.equal(meeting.inMeetingActions.get()[actionName], expectedEnabled);
|
|
7742
|
+
});
|
|
7743
|
+
}
|
|
7744
|
+
);
|
|
7745
|
+
|
|
7746
|
+
forEach(
|
|
7747
|
+
[
|
|
7748
|
+
{
|
|
7749
|
+
actionName: 'canShareFile',
|
|
7750
|
+
requiredDisplayHints: [DISPLAY_HINTS.SHARE_FILE],
|
|
7751
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_FILE_SHARE],
|
|
7752
|
+
},
|
|
7753
|
+
{
|
|
7754
|
+
actionName: 'canShareApplication',
|
|
7755
|
+
requiredDisplayHints: [DISPLAY_HINTS.SHARE_APPLICATION],
|
|
7756
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_APP_SHARE],
|
|
7757
|
+
},
|
|
7758
|
+
{
|
|
7759
|
+
actionName: 'canShareCamera',
|
|
7760
|
+
requiredDisplayHints: [DISPLAY_HINTS.SHARE_CAMERA],
|
|
7761
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_CAMERA_SHARE],
|
|
7762
|
+
},
|
|
7763
|
+
{
|
|
7764
|
+
actionName: 'canBroadcastMessageToBreakout',
|
|
7765
|
+
requiredDisplayHints: [DISPLAY_HINTS.BROADCAST_MESSAGE_TO_BREAKOUT],
|
|
7766
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_BROADCAST_MESSAGE],
|
|
7767
|
+
},
|
|
7768
|
+
{
|
|
7769
|
+
actionName: 'canShareDesktop',
|
|
7770
|
+
requiredDisplayHints: [DISPLAY_HINTS.SHARE_DESKTOP],
|
|
7771
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_DESKTOP_SHARE],
|
|
7772
|
+
},
|
|
7773
|
+
{
|
|
7774
|
+
actionName: 'canTransferFile',
|
|
7775
|
+
requiredDisplayHints: [],
|
|
7776
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_FILE_TRANSFER],
|
|
7777
|
+
},
|
|
7778
|
+
{
|
|
7779
|
+
actionName: 'canChat',
|
|
7780
|
+
requiredDisplayHints: [],
|
|
7781
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_CHAT],
|
|
7782
|
+
},
|
|
7783
|
+
{
|
|
7784
|
+
actionName: 'canShareDesktop',
|
|
7785
|
+
requiredDisplayHints: [DISPLAY_HINTS.SHARE_DESKTOP],
|
|
7786
|
+
requiredPolicies: [],
|
|
7787
|
+
enableUnifiedMeetings: false,
|
|
7788
|
+
arePolicyRestrictionsSupported: false,
|
|
7789
|
+
},
|
|
7790
|
+
{
|
|
7791
|
+
actionName: 'canShareApplication',
|
|
7792
|
+
requiredDisplayHints: [DISPLAY_HINTS.SHARE_APPLICATION],
|
|
7793
|
+
requiredPolicies: [],
|
|
7794
|
+
enableUnifiedMeetings: false,
|
|
7795
|
+
arePolicyRestrictionsSupported: false,
|
|
7796
|
+
},
|
|
7797
|
+
{
|
|
7798
|
+
actionName: 'canAnnotate',
|
|
7799
|
+
requiredDisplayHints: [],
|
|
7800
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_ANNOTATION],
|
|
7801
|
+
},
|
|
7802
|
+
],
|
|
7803
|
+
({
|
|
7804
|
+
actionName,
|
|
7805
|
+
requiredDisplayHints,
|
|
7806
|
+
requiredPolicies,
|
|
7807
|
+
enableUnifiedMeetings,
|
|
7808
|
+
meetingInfo,
|
|
7809
|
+
arePolicyRestrictionsSupported,
|
|
7810
|
+
}) => {
|
|
7811
|
+
it(`${actionName} is enabled when the conditions are met`, () => {
|
|
7812
|
+
meeting.userDisplayHints = requiredDisplayHints;
|
|
7813
|
+
meeting.selfUserPolicies = undefined;
|
|
7814
|
+
sinon
|
|
7815
|
+
.stub(meeting, 'arePolicyRestrictionsSupported')
|
|
7816
|
+
.returns(arePolicyRestrictionsSupported);
|
|
7817
|
+
|
|
7818
|
+
meeting.config.experimental.enableUnifiedMeetings = isUndefined(enableUnifiedMeetings)
|
|
7819
|
+
? true
|
|
7820
|
+
: enableUnifiedMeetings;
|
|
7821
|
+
|
|
7822
|
+
meeting.meetingInfo = isUndefined(meetingInfo) ? {some: 'info'} : meetingInfo;
|
|
7823
|
+
|
|
7824
|
+
if (requiredPolicies) {
|
|
7825
|
+
meeting.selfUserPolicies = {};
|
|
7826
|
+
}
|
|
7827
|
+
forEach(requiredPolicies, (policy) => {
|
|
7828
|
+
meeting.selfUserPolicies[policy] = true;
|
|
7829
|
+
});
|
|
7830
|
+
|
|
7831
|
+
meeting.updateMeetingActions();
|
|
7832
|
+
|
|
7833
|
+
assert.isTrue(meeting.inMeetingActions.get()[actionName]);
|
|
7834
|
+
});
|
|
7835
|
+
|
|
7836
|
+
if (requiredDisplayHints.length !== 0) {
|
|
7837
|
+
it(`${actionName} is disabled when the required display hints are missing`, () => {
|
|
7838
|
+
meeting.userDisplayHints = [];
|
|
7839
|
+
meeting.selfUserPolicies = undefined;
|
|
7840
|
+
|
|
7841
|
+
meeting.meetingInfo = isUndefined(meetingInfo) ? {some: 'info'} : meetingInfo;
|
|
7842
|
+
|
|
7843
|
+
if (requiredPolicies) {
|
|
7844
|
+
meeting.selfUserPolicies = {};
|
|
7845
|
+
}
|
|
7846
|
+
forEach(requiredPolicies, (policy) => {
|
|
7847
|
+
meeting.selfUserPolicies[policy] = true;
|
|
7848
|
+
});
|
|
7849
|
+
|
|
7850
|
+
meeting.updateMeetingActions();
|
|
7851
|
+
|
|
7852
|
+
assert.isFalse(meeting.inMeetingActions.get()[actionName]);
|
|
7853
|
+
});
|
|
7854
|
+
}
|
|
7855
|
+
|
|
7856
|
+
it(`${actionName} is disabled when the required policies are missing`, () => {
|
|
7857
|
+
meeting.userDisplayHints = requiredDisplayHints;
|
|
7858
|
+
meeting.selfUserPolicies = undefined;
|
|
7859
|
+
|
|
7860
|
+
if (requiredPolicies) {
|
|
7861
|
+
meeting.selfUserPolicies = {};
|
|
7862
|
+
}
|
|
7863
|
+
meeting.meetingInfo = isUndefined(meetingInfo) ? {some: 'info'} : meetingInfo;
|
|
7864
|
+
|
|
7865
|
+
meeting.updateMeetingActions();
|
|
7866
|
+
|
|
7867
|
+
assert.isFalse(meeting.inMeetingActions.get()[actionName]);
|
|
7868
|
+
});
|
|
7869
|
+
}
|
|
7870
|
+
);
|
|
7871
|
+
|
|
7872
|
+
forEach(
|
|
7873
|
+
[
|
|
7874
|
+
{
|
|
7875
|
+
meetingInfo: {
|
|
7876
|
+
video: {
|
|
7877
|
+
supportHDV: true,
|
|
7878
|
+
supportHQV: true,
|
|
7879
|
+
},
|
|
7880
|
+
},
|
|
7881
|
+
selfUserPolicies: {
|
|
7882
|
+
[SELF_POLICY.SUPPORT_HDV]: true,
|
|
7883
|
+
[SELF_POLICY.SUPPORT_HQV]: true,
|
|
7884
|
+
},
|
|
7885
|
+
expectedActions: {
|
|
7886
|
+
supportHQV: true,
|
|
7887
|
+
supportHDV: true,
|
|
7888
|
+
},
|
|
7889
|
+
},
|
|
7890
|
+
{
|
|
7891
|
+
meetingInfo: {
|
|
7892
|
+
video: {
|
|
7893
|
+
supportHDV: false,
|
|
7894
|
+
supportHQV: false,
|
|
7895
|
+
},
|
|
7896
|
+
},
|
|
7897
|
+
selfUserPolicies: {
|
|
7898
|
+
[SELF_POLICY.SUPPORT_HDV]: true,
|
|
7899
|
+
[SELF_POLICY.SUPPORT_HQV]: true,
|
|
7900
|
+
},
|
|
7901
|
+
expectedActions: {
|
|
7902
|
+
supportHQV: false,
|
|
7903
|
+
supportHDV: false,
|
|
7904
|
+
},
|
|
7905
|
+
},
|
|
7906
|
+
{
|
|
7907
|
+
meetingInfo: {
|
|
7908
|
+
video: {
|
|
7909
|
+
supportHDV: true,
|
|
7910
|
+
supportHQV: true,
|
|
7911
|
+
},
|
|
7912
|
+
},
|
|
7913
|
+
selfUserPolicies: {
|
|
7914
|
+
[SELF_POLICY.SUPPORT_HDV]: false,
|
|
7915
|
+
[SELF_POLICY.SUPPORT_HQV]: false,
|
|
7916
|
+
},
|
|
7917
|
+
expectedActions: {
|
|
7918
|
+
supportHQV: false,
|
|
7919
|
+
supportHDV: false,
|
|
7920
|
+
},
|
|
7921
|
+
},
|
|
7922
|
+
{
|
|
7923
|
+
meetingInfo: undefined,
|
|
7924
|
+
selfUserPolicies: {},
|
|
7925
|
+
expectedActions: {
|
|
7926
|
+
supportHQV: true,
|
|
7927
|
+
supportHDV: true,
|
|
7928
|
+
},
|
|
7929
|
+
},
|
|
7930
|
+
{
|
|
7931
|
+
meetingInfo: {some: 'data'},
|
|
7932
|
+
selfUserPolicies: undefined,
|
|
7933
|
+
expectedActions: {
|
|
7934
|
+
supportHQV: true,
|
|
7935
|
+
supportHDV: true,
|
|
7936
|
+
},
|
|
7937
|
+
},
|
|
7938
|
+
],
|
|
7939
|
+
({meetingInfo, selfUserPolicies, expectedActions}) => {
|
|
7940
|
+
it(`expectedActions are ${JSON.stringify(
|
|
7941
|
+
expectedActions
|
|
7942
|
+
)} when policies are ${JSON.stringify(
|
|
7943
|
+
selfUserPolicies
|
|
7944
|
+
)} and meetingInfo is ${JSON.stringify(meetingInfo)}`, () => {
|
|
7945
|
+
meeting.meetingInfo = meetingInfo;
|
|
7946
|
+
meeting.selfUserPolicies = selfUserPolicies;
|
|
7947
|
+
|
|
7948
|
+
meeting.updateMeetingActions();
|
|
7949
|
+
|
|
7950
|
+
assert.deepEqual(
|
|
7951
|
+
{
|
|
7952
|
+
supportHDV: meeting.inMeetingActions.supportHDV,
|
|
7953
|
+
supportHQV: meeting.inMeetingActions.supportHQV,
|
|
7954
|
+
},
|
|
7955
|
+
expectedActions
|
|
7956
|
+
);
|
|
7957
|
+
});
|
|
7958
|
+
}
|
|
7959
|
+
);
|
|
7960
|
+
|
|
7961
|
+
it('canUseVoip is disabled when the required policies are missing', () => {
|
|
7962
|
+
meeting.userDisplayHints = [DISPLAY_HINTS.VOIP_IS_ENABLED];
|
|
7963
|
+
meeting.selfUserPolicies = {};
|
|
7964
|
+
meeting.meetingInfo.supportVoIP = true;
|
|
7965
|
+
|
|
7966
|
+
meeting.updateMeetingActions();
|
|
7967
|
+
|
|
7968
|
+
assert.isFalse(meeting.inMeetingActions.get()['canUseVoip']);
|
|
7969
|
+
});
|
|
7970
|
+
|
|
7971
|
+
it('canUseVoip is enabled based on api info when the conditions are met', () => {
|
|
7972
|
+
meeting.userDisplayHints = undefined;
|
|
7973
|
+
meeting.selfUserPolicies = {[SELF_POLICY.SUPPORT_VOIP]: true};
|
|
7974
|
+
meeting.meetingInfo.supportVoIP = true;
|
|
7975
|
+
|
|
7976
|
+
meeting.updateMeetingActions();
|
|
7977
|
+
|
|
7978
|
+
assert.isTrue(meeting.inMeetingActions.get()['canUseVoip']);
|
|
7979
|
+
});
|
|
7980
|
+
|
|
7981
|
+
it('canUseVoip is enabled based on api info when the conditions are met - no display hints', () => {
|
|
7982
|
+
meeting.userDisplayHints = [];
|
|
7983
|
+
meeting.selfUserPolicies = {[SELF_POLICY.SUPPORT_VOIP]: true};
|
|
7984
|
+
meeting.meetingInfo.supportVoIP = true;
|
|
7985
|
+
|
|
7986
|
+
meeting.updateMeetingActions();
|
|
7987
|
+
|
|
7988
|
+
assert.isTrue(meeting.inMeetingActions.get()['canUseVoip']);
|
|
7989
|
+
});
|
|
7990
|
+
|
|
7991
|
+
it('canUseVoip is enabled when there is no meeting info', () => {
|
|
7992
|
+
meeting.updateMeetingActions();
|
|
7993
|
+
|
|
7994
|
+
assert.isTrue(meeting.inMeetingActions.get()['canUseVoip']);
|
|
7995
|
+
});
|
|
7996
|
+
|
|
7997
|
+
it('canUseVoip is enabled when it is a locus call', () => {
|
|
7998
|
+
meeting.meetingInfo = {some: 'info'};
|
|
7999
|
+
meeting.type = 'CALL';
|
|
8000
|
+
|
|
8001
|
+
meeting.updateMeetingActions();
|
|
8002
|
+
|
|
8003
|
+
assert.isTrue(meeting.inMeetingActions.get()['canUseVoip']);
|
|
8004
|
+
});
|
|
8005
|
+
|
|
8006
|
+
it('canUseVoip is disabled based on api info when supportVoip is false', () => {
|
|
8007
|
+
meeting.userDisplayHints = undefined;
|
|
8008
|
+
meeting.selfUserPolicies = {[SELF_POLICY.SUPPORT_VOIP]: true};
|
|
8009
|
+
meeting.meetingInfo.supportVoIP = false;
|
|
8010
|
+
|
|
8011
|
+
meeting.updateMeetingActions();
|
|
8012
|
+
|
|
8013
|
+
assert.isFalse(meeting.inMeetingActions.get()['canUseVoip']);
|
|
8014
|
+
});
|
|
8015
|
+
|
|
8016
|
+
it('canUseVoip is disabled based on api info when the required policies are missing', () => {
|
|
8017
|
+
meeting.userDisplayHints = undefined;
|
|
8018
|
+
meeting.selfUserPolicies = {};
|
|
8019
|
+
meeting.meetingInfo.supportVoIP = true;
|
|
8020
|
+
|
|
8021
|
+
meeting.updateMeetingActions();
|
|
8022
|
+
|
|
8023
|
+
assert.isFalse(meeting.inMeetingActions.get()['canUseVoip']);
|
|
8024
|
+
});
|
|
8025
|
+
|
|
8026
|
+
it('canUseVoip is enabled when there are no policies', () => {
|
|
8027
|
+
meeting.userDisplayHints = [DISPLAY_HINTS.VOIP_IS_ENABLED];
|
|
8028
|
+
meeting.selfUserPolicies = undefined;
|
|
8029
|
+
meeting.meetingInfo.supportVoIP = false;
|
|
8030
|
+
|
|
8031
|
+
meeting.updateMeetingActions();
|
|
8032
|
+
|
|
8033
|
+
assert.isTrue(meeting.inMeetingActions.get()['canUseVoip']);
|
|
8034
|
+
});
|
|
8035
|
+
|
|
8036
|
+
forEach(
|
|
8037
|
+
[
|
|
8038
|
+
{
|
|
8039
|
+
meetingInfo: {},
|
|
8040
|
+
selfUserPolicies: {
|
|
8041
|
+
[SELF_POLICY.SUPPORT_VIDEO]: true,
|
|
8042
|
+
},
|
|
8043
|
+
expectedActions: {
|
|
8044
|
+
canDoVideo: true,
|
|
8045
|
+
},
|
|
8046
|
+
},
|
|
8047
|
+
{
|
|
8048
|
+
meetingInfo: {},
|
|
8049
|
+
selfUserPolicies: {
|
|
8050
|
+
[SELF_POLICY.SUPPORT_VIDEO]: false,
|
|
8051
|
+
},
|
|
8052
|
+
expectedActions: {
|
|
8053
|
+
canDoVideo: true,
|
|
8054
|
+
},
|
|
8055
|
+
},
|
|
8056
|
+
{
|
|
8057
|
+
meetingInfo: {some: 'data'},
|
|
8058
|
+
selfUserPolicies: {
|
|
8059
|
+
[SELF_POLICY.SUPPORT_VIDEO]: true,
|
|
8060
|
+
},
|
|
8061
|
+
expectedActions: {
|
|
8062
|
+
canDoVideo: false,
|
|
8063
|
+
},
|
|
8064
|
+
},
|
|
8065
|
+
{
|
|
8066
|
+
meetingInfo: {some: 'data'},
|
|
8067
|
+
selfUserPolicies: undefined,
|
|
8068
|
+
expectedActions: {
|
|
8069
|
+
canDoVideo: true,
|
|
8070
|
+
},
|
|
8071
|
+
},
|
|
8072
|
+
{
|
|
8073
|
+
meetingInfo: {
|
|
8074
|
+
video: {},
|
|
8075
|
+
},
|
|
8076
|
+
selfUserPolicies: {
|
|
8077
|
+
[SELF_POLICY.SUPPORT_VIDEO]: true,
|
|
8078
|
+
},
|
|
8079
|
+
expectedActions: {
|
|
8080
|
+
canDoVideo: true,
|
|
8081
|
+
},
|
|
8082
|
+
},
|
|
8083
|
+
{
|
|
8084
|
+
meetingInfo: undefined,
|
|
8085
|
+
selfUserPolicies: {},
|
|
8086
|
+
expectedActions: {
|
|
8087
|
+
canDoVideo: true,
|
|
8088
|
+
},
|
|
8089
|
+
},
|
|
8090
|
+
{
|
|
8091
|
+
meetingInfo: {
|
|
8092
|
+
video: {},
|
|
8093
|
+
},
|
|
8094
|
+
selfUserPolicies: {
|
|
8095
|
+
[SELF_POLICY.SUPPORT_VIDEO]: false,
|
|
8096
|
+
},
|
|
8097
|
+
expectedActions: {
|
|
8098
|
+
canDoVideo: false,
|
|
8099
|
+
},
|
|
8100
|
+
},
|
|
8101
|
+
],
|
|
8102
|
+
({meetingInfo, selfUserPolicies, expectedActions}) => {
|
|
8103
|
+
it(`has expectedActions ${JSON.stringify(
|
|
8104
|
+
expectedActions
|
|
8105
|
+
)} when policies are ${JSON.stringify(
|
|
8106
|
+
selfUserPolicies
|
|
8107
|
+
)} and meetingInfo is ${JSON.stringify(meetingInfo)}`, () => {
|
|
8108
|
+
meeting.meetingInfo = meetingInfo;
|
|
8109
|
+
meeting.selfUserPolicies = selfUserPolicies;
|
|
8110
|
+
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
8111
|
+
|
|
8112
|
+
meeting.updateMeetingActions();
|
|
8113
|
+
|
|
8114
|
+
assert.deepEqual(
|
|
8115
|
+
{
|
|
8116
|
+
canDoVideo: meeting.inMeetingActions.canDoVideo,
|
|
8117
|
+
},
|
|
8118
|
+
expectedActions
|
|
8119
|
+
);
|
|
8120
|
+
});
|
|
8121
|
+
}
|
|
8122
|
+
);
|
|
8123
|
+
|
|
8124
|
+
it('correctly updates the meeting actions', () => {
|
|
8125
|
+
// Due to import tree issues, hasHints must be stubed within the scope of the `it`.
|
|
8126
|
+
const restorableHasHints = ControlsOptionsUtil.hasHints;
|
|
8127
|
+
ControlsOptionsUtil.hasHints = sinon.stub().returns(true);
|
|
8128
|
+
ControlsOptionsUtil.hasPolicies = sinon.stub().returns(true);
|
|
8129
|
+
|
|
8130
|
+
const selfUserPolicies = {a: true};
|
|
8131
|
+
meeting.selfUserPolicies = {a: true};
|
|
8132
|
+
const userDisplayHints = ['LOCK_CONTROL_UNLOCK'];
|
|
8133
|
+
meeting.userDisplayHints = ['LOCK_CONTROL_UNLOCK'];
|
|
8134
|
+
meeting.meetingInfo.supportVoIP = true;
|
|
8135
|
+
|
|
8136
|
+
meeting.updateMeetingActions();
|
|
8137
|
+
|
|
8138
|
+
assert.calledWith(canUserLockSpy, userDisplayHints);
|
|
8139
|
+
assert.calledWith(canUserUnlockSpy, userDisplayHints);
|
|
8140
|
+
assert.calledWith(canUserStartSpy, userDisplayHints);
|
|
8141
|
+
assert.calledWith(canUserStopSpy, userDisplayHints);
|
|
8142
|
+
assert.calledWith(canUserPauseSpy, userDisplayHints);
|
|
8143
|
+
assert.calledWith(canUserResumeSpy, userDisplayHints);
|
|
8144
|
+
assert.calledWith(canSetMuteOnEntrySpy, userDisplayHints);
|
|
8145
|
+
assert.calledWith(canUnsetMuteOnEntrySpy, userDisplayHints);
|
|
8146
|
+
assert.calledWith(canSetDisallowUnmuteSpy, userDisplayHints);
|
|
8147
|
+
assert.calledWith(canUnsetDisallowUnmuteSpy, userDisplayHints);
|
|
8148
|
+
assert.calledWith(canUserRaiseHandSpy, userDisplayHints);
|
|
8149
|
+
assert.calledWith(bothLeaveAndEndMeetingAvailableSpy, userDisplayHints);
|
|
8150
|
+
assert.calledWith(canUserLowerAllHandsSpy, userDisplayHints);
|
|
8151
|
+
assert.calledWith(canUserLowerSomeoneElsesHandSpy, userDisplayHints);
|
|
8152
|
+
assert.calledWith(waitingForOthersToJoinSpy, userDisplayHints);
|
|
8153
|
+
assert.calledWith(canSendReactionsSpy, null, userDisplayHints);
|
|
8154
|
+
assert.calledWith(canUserRenameSelfAndObservedSpy, userDisplayHints);
|
|
8155
|
+
assert.calledWith(canUserRenameOthersSpy, userDisplayHints);
|
|
8156
|
+
assert.calledWith(canShareWhiteBoardSpy, userDisplayHints);
|
|
8157
|
+
|
|
8158
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8159
|
+
requiredHints: [DISPLAY_HINTS.MUTE_ALL],
|
|
8160
|
+
displayHints: userDisplayHints,
|
|
8161
|
+
});
|
|
8162
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8163
|
+
requiredHints: [DISPLAY_HINTS.UNMUTE_ALL],
|
|
8164
|
+
displayHints: userDisplayHints,
|
|
8165
|
+
});
|
|
8166
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8167
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_HARD_MUTE],
|
|
8168
|
+
displayHints: userDisplayHints,
|
|
8169
|
+
});
|
|
8170
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8171
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_HARD_MUTE],
|
|
8172
|
+
displayHints: userDisplayHints,
|
|
8173
|
+
});
|
|
8174
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8175
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_MUTE_ON_ENTRY],
|
|
8176
|
+
displayHints: userDisplayHints,
|
|
8177
|
+
});
|
|
8178
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8179
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_MUTE_ON_ENTRY],
|
|
8180
|
+
displayHints: userDisplayHints,
|
|
8181
|
+
});
|
|
8182
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8183
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_REACTIONS],
|
|
8184
|
+
displayHints: userDisplayHints,
|
|
8185
|
+
});
|
|
8186
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8187
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_REACTIONS],
|
|
8188
|
+
displayHints: userDisplayHints,
|
|
8189
|
+
});
|
|
8190
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8191
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_SHOW_DISPLAY_NAME],
|
|
8192
|
+
displayHints: userDisplayHints,
|
|
8193
|
+
});
|
|
8194
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8195
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_SHOW_DISPLAY_NAME],
|
|
8196
|
+
displayHints: userDisplayHints,
|
|
8197
|
+
});
|
|
8198
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8199
|
+
requiredHints: [DISPLAY_HINTS.SHARE_CONTROL],
|
|
8200
|
+
displayHints: userDisplayHints,
|
|
8201
|
+
});
|
|
8202
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8203
|
+
requiredHints: [DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST],
|
|
8204
|
+
displayHints: userDisplayHints,
|
|
8205
|
+
});
|
|
8206
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8207
|
+
requiredHints: [DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST],
|
|
8208
|
+
displayHints: userDisplayHints,
|
|
8209
|
+
});
|
|
8210
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8211
|
+
requiredHints: [DISPLAY_HINTS.SHARE_FILE],
|
|
8212
|
+
displayHints: userDisplayHints,
|
|
8213
|
+
});
|
|
8214
|
+
assert.calledWith(ControlsOptionsUtil.hasPolicies, {
|
|
8215
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_FILE_SHARE],
|
|
8216
|
+
policies: selfUserPolicies,
|
|
8217
|
+
});
|
|
8218
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8219
|
+
requiredHints: [DISPLAY_HINTS.SHARE_APPLICATION],
|
|
8220
|
+
displayHints: userDisplayHints,
|
|
8221
|
+
});
|
|
8222
|
+
assert.calledWith(ControlsOptionsUtil.hasPolicies, {
|
|
8223
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_APP_SHARE],
|
|
8224
|
+
policies: selfUserPolicies,
|
|
8225
|
+
});
|
|
8226
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8227
|
+
requiredHints: [DISPLAY_HINTS.SHARE_CAMERA],
|
|
8228
|
+
displayHints: userDisplayHints,
|
|
8229
|
+
});
|
|
8230
|
+
assert.calledWith(ControlsOptionsUtil.hasPolicies, {
|
|
8231
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_CAMERA_SHARE],
|
|
8232
|
+
policies: selfUserPolicies,
|
|
8233
|
+
});
|
|
8234
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8235
|
+
requiredHints: [DISPLAY_HINTS.SHARE_DESKTOP],
|
|
8236
|
+
displayHints: userDisplayHints,
|
|
8237
|
+
});
|
|
8238
|
+
assert.calledWith(ControlsOptionsUtil.hasPolicies, {
|
|
8239
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_DESKTOP_SHARE],
|
|
8240
|
+
policies: selfUserPolicies,
|
|
8241
|
+
});
|
|
8242
|
+
assert.calledWith(ControlsOptionsUtil.hasHints, {
|
|
8243
|
+
requiredHints: [DISPLAY_HINTS.SHARE_CONTENT],
|
|
8244
|
+
displayHints: userDisplayHints,
|
|
8245
|
+
});
|
|
8246
|
+
assert.calledWith(ControlsOptionsUtil.hasPolicies, {
|
|
8247
|
+
requiredPolicies: [SELF_POLICY.SUPPORT_VOIP],
|
|
8248
|
+
policies: selfUserPolicies,
|
|
8249
|
+
});
|
|
7350
8250
|
|
|
7351
8251
|
assert.calledWith(updateMeetingActionsSpy);
|
|
7352
8252
|
assert.calledWith(setRecordingDisplayHintsSpy, userDisplayHints);
|