@webex/plugin-meetings 1.160.0 → 2.1.0
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/README.md +1 -0
- package/dist/constants.js +10 -2
- package/dist/constants.js.map +1 -1
- package/dist/locus-info/controlsUtils.js +10 -3
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +11 -0
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.js +190 -67
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +17 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/state.js +5 -2
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/util.js +23 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +66 -16
- package/dist/meetings/index.js.map +1 -1
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/package.json +6 -6
- package/src/constants.js +6 -0
- package/src/locus-info/controlsUtils.js +11 -1
- package/src/locus-info/index.js +23 -1
- package/src/meeting/index.js +153 -26
- package/src/meeting/request.js +18 -0
- package/src/meeting/state.js +12 -1
- package/src/meeting/util.js +31 -1
- package/src/meetings/index.js +35 -8
- package/src/metrics/constants.js +2 -0
- package/test/unit/spec/locus-info/index.js +51 -1
- package/test/unit/spec/meeting/index.js +224 -7
- package/test/unit/spec/meeting/request.js +15 -0
- package/test/unit/spec/meetings/index.js +187 -19
|
@@ -10,6 +10,7 @@ import {assert} from '@webex/test-helper-chai';
|
|
|
10
10
|
import {Credentials} from '@webex/webex-core';
|
|
11
11
|
import Support from '@webex/internal-plugin-support';
|
|
12
12
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
13
|
+
|
|
13
14
|
import Meetings, {CONSTANTS} from '@webex/plugin-meetings';
|
|
14
15
|
import Meeting from '@webex/plugin-meetings/src/meeting';
|
|
15
16
|
import Members from '@webex/plugin-meetings/src/members';
|
|
@@ -228,6 +229,7 @@ describe('plugin-meetings', () => {
|
|
|
228
229
|
assert.isNull(meeting.policy);
|
|
229
230
|
assert.instanceOf(meeting.meetingRequest, MeetingRequest);
|
|
230
231
|
assert.instanceOf(meeting.locusInfo, LocusInfo);
|
|
232
|
+
assert.equal(meeting.fetchMeetingInfoTimeoutId, undefined);
|
|
231
233
|
assert.instanceOf(meeting.mediaProperties, MediaProperties);
|
|
232
234
|
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.UNKNOWN);
|
|
233
235
|
assert.equal(meeting.requiredCaptcha, null);
|
|
@@ -2118,6 +2120,7 @@ describe('plugin-meetings', () => {
|
|
|
2118
2120
|
describe('#fetchMeetingInfo', () => {
|
|
2119
2121
|
const FAKE_DESTINATION = 'something@somecompany.com';
|
|
2120
2122
|
const FAKE_TYPE = _SIP_URI_;
|
|
2123
|
+
const FAKE_TIMEOUT_FETCHMEETINGINFO_ID = '123456';
|
|
2121
2124
|
const FAKE_PASSWORD = '123abc';
|
|
2122
2125
|
const FAKE_CAPTCHA_CODE = 'a1b2c3XYZ';
|
|
2123
2126
|
const FAKE_CAPTCHA_ID = '987654321';
|
|
@@ -2150,6 +2153,7 @@ describe('plugin-meetings', () => {
|
|
|
2150
2153
|
meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
|
|
2151
2154
|
meeting.destination = FAKE_DESTINATION;
|
|
2152
2155
|
meeting.destinationType = FAKE_TYPE;
|
|
2156
|
+
meeting.parseMeetingInfo = sinon.stub().returns(undefined);
|
|
2153
2157
|
|
|
2154
2158
|
await meeting.fetchMeetingInfo({
|
|
2155
2159
|
password: FAKE_PASSWORD, captchaCode: FAKE_CAPTCHA_CODE
|
|
@@ -2157,10 +2161,45 @@ describe('plugin-meetings', () => {
|
|
|
2157
2161
|
|
|
2158
2162
|
assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, FAKE_PASSWORD, {code: FAKE_CAPTCHA_CODE, id: FAKE_CAPTCHA_ID});
|
|
2159
2163
|
|
|
2164
|
+
assert.calledWith(meeting.parseMeetingInfo, {body: FAKE_MEETING_INFO}, FAKE_DESTINATION);
|
|
2160
2165
|
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
2161
2166
|
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.NOT_REQUIRED);
|
|
2162
2167
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
2163
2168
|
assert.equal(meeting.requiredCaptcha, null);
|
|
2169
|
+
assert.calledTwice(TriggerProxy.trigger);
|
|
2170
|
+
assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
|
|
2171
|
+
});
|
|
2172
|
+
|
|
2173
|
+
it('calls meetingInfoProvider with all the right parameters and parses the result when random delay is applied', async () => {
|
|
2174
|
+
meeting.attrs.meetingInfoProvider = {fetchMeetingInfo: sinon.stub().resolves({body: FAKE_MEETING_INFO})};
|
|
2175
|
+
meeting.destination = FAKE_DESTINATION;
|
|
2176
|
+
meeting.destinationType = FAKE_TYPE;
|
|
2177
|
+
meeting.parseMeetingInfo = sinon.stub().returns(undefined);
|
|
2178
|
+
meeting.fetchMeetingInfoTimeoutId = FAKE_TIMEOUT_FETCHMEETINGINFO_ID;
|
|
2179
|
+
|
|
2180
|
+
const clock = sinon.useFakeTimers();
|
|
2181
|
+
const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
|
|
2182
|
+
|
|
2183
|
+
await meeting.fetchMeetingInfo({});
|
|
2184
|
+
|
|
2185
|
+
// clear timer
|
|
2186
|
+
assert.calledWith(clearTimeoutSpy, FAKE_TIMEOUT_FETCHMEETINGINFO_ID);
|
|
2187
|
+
clock.restore();
|
|
2188
|
+
assert.isUndefined(meeting.fetchMeetingInfoTimeoutId);
|
|
2189
|
+
|
|
2190
|
+
// meeting info provider
|
|
2191
|
+
assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, null, null);
|
|
2192
|
+
|
|
2193
|
+
// parseMeeting info
|
|
2194
|
+
assert.calledWith(meeting.parseMeetingInfo, {body: FAKE_MEETING_INFO}, FAKE_DESTINATION);
|
|
2195
|
+
|
|
2196
|
+
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
2197
|
+
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
2198
|
+
assert.equal(meeting.requiredCaptcha, null);
|
|
2199
|
+
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.NOT_REQUIRED);
|
|
2200
|
+
|
|
2201
|
+
assert.calledTwice(TriggerProxy.trigger);
|
|
2202
|
+
assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
|
|
2164
2203
|
});
|
|
2165
2204
|
|
|
2166
2205
|
it('fails if captchaCode is provided when captcha not needed', async () => {
|
|
@@ -2428,6 +2467,64 @@ describe('plugin-meetings', () => {
|
|
|
2428
2467
|
);
|
|
2429
2468
|
});
|
|
2430
2469
|
});
|
|
2470
|
+
|
|
2471
|
+
describe('#endMeeting for all', () => {
|
|
2472
|
+
let sandbox;
|
|
2473
|
+
|
|
2474
|
+
it('should have #endMeetingForAll', () => {
|
|
2475
|
+
assert.exists(meeting.endMeetingForAll);
|
|
2476
|
+
});
|
|
2477
|
+
|
|
2478
|
+
it('should reject if meeting is already ended', async () => {
|
|
2479
|
+
await meeting.endMeetingForAll().catch((err) => {
|
|
2480
|
+
assert.instanceOf(err, MeetingNotActiveError);
|
|
2481
|
+
});
|
|
2482
|
+
});
|
|
2483
|
+
beforeEach(() => {
|
|
2484
|
+
sandbox = sinon.createSandbox();
|
|
2485
|
+
meeting.meetingFiniteStateMachine.ring();
|
|
2486
|
+
meeting.meetingFiniteStateMachine.join();
|
|
2487
|
+
meeting.meetingRequest.endMeetingForAll = sinon.stub().returns(Promise.resolve({body: 'test'}));
|
|
2488
|
+
meeting.locusInfo.onFullLocus = sinon.stub().returns(true);
|
|
2489
|
+
meeting.closeLocalStream = sinon.stub().returns(Promise.resolve());
|
|
2490
|
+
meeting.closeLocalShare = sinon.stub().returns(Promise.resolve());
|
|
2491
|
+
meeting.closeRemoteStream = sinon.stub().returns(Promise.resolve());
|
|
2492
|
+
sandbox.stub(meeting, 'closeRemoteTracks').returns(Promise.resolve());
|
|
2493
|
+
meeting.closePeerConnections = sinon.stub().returns(Promise.resolve());
|
|
2494
|
+
meeting.unsetLocalVideoTrack = sinon.stub().returns(true);
|
|
2495
|
+
meeting.unsetLocalShareTrack = sinon.stub().returns(true);
|
|
2496
|
+
meeting.unsetRemoteTracks = sinon.stub();
|
|
2497
|
+
meeting.statsAnalyzer = {stopAnalyzer: sinon.stub()};
|
|
2498
|
+
meeting.unsetRemoteStream = sinon.stub().returns(true);
|
|
2499
|
+
meeting.unsetPeerConnections = sinon.stub().returns(true);
|
|
2500
|
+
meeting.roap.stop = sinon.stub().returns(Promise.resolve());
|
|
2501
|
+
meeting.logger.error = sinon.stub().returns(true);
|
|
2502
|
+
|
|
2503
|
+
// A meeting needs to be joined to end
|
|
2504
|
+
meeting.meetingState = 'ACTIVE';
|
|
2505
|
+
meeting.state = 'JOINED';
|
|
2506
|
+
});
|
|
2507
|
+
afterEach(() => {
|
|
2508
|
+
sandbox.restore();
|
|
2509
|
+
sandbox = null;
|
|
2510
|
+
});
|
|
2511
|
+
it('should end the meeting for all and return promise', async () => {
|
|
2512
|
+
const endMeetingForAll = meeting.endMeetingForAll();
|
|
2513
|
+
|
|
2514
|
+
assert.exists(endMeetingForAll.then);
|
|
2515
|
+
await endMeetingForAll;
|
|
2516
|
+
assert.calledOnce(meeting?.meetingRequest?.endMeetingForAll);
|
|
2517
|
+
assert.calledOnce(meeting?.closeLocalStream);
|
|
2518
|
+
assert.calledOnce(meeting?.closeLocalShare);
|
|
2519
|
+
assert.calledOnce(meeting?.closeRemoteTracks);
|
|
2520
|
+
assert.calledOnce(meeting?.closePeerConnections);
|
|
2521
|
+
assert.calledOnce(meeting?.unsetLocalVideoTrack);
|
|
2522
|
+
assert.calledOnce(meeting?.unsetLocalShareTrack);
|
|
2523
|
+
assert.calledOnce(meeting?.unsetRemoteTracks);
|
|
2524
|
+
assert.calledOnce(meeting?.unsetPeerConnections);
|
|
2525
|
+
assert.calledOnce(meeting?.roap?.stop);
|
|
2526
|
+
});
|
|
2527
|
+
});
|
|
2431
2528
|
});
|
|
2432
2529
|
|
|
2433
2530
|
describe('Public Event Triggers', () => {
|
|
@@ -2879,21 +2976,141 @@ describe('plugin-meetings', () => {
|
|
|
2879
2976
|
});
|
|
2880
2977
|
});
|
|
2881
2978
|
describe('#parseMeetingInfo', () => {
|
|
2882
|
-
|
|
2979
|
+
const checkParseMeetingInfo = (expectedInfoToParse) => {
|
|
2980
|
+
assert.equal(meeting.conversationUrl, expectedInfoToParse.conversationUrl);
|
|
2981
|
+
assert.equal(meeting.locusUrl, expectedInfoToParse.locusUrl);
|
|
2982
|
+
assert.equal(meeting.sipUri, expectedInfoToParse.sipUri);
|
|
2983
|
+
assert.equal(meeting.meetingNumber, expectedInfoToParse.meetingNumber);
|
|
2984
|
+
assert.equal(meeting.meetingJoinUrl, expectedInfoToParse.meetingJoinUrl);
|
|
2985
|
+
assert.equal(meeting.owner, expectedInfoToParse.owner);
|
|
2986
|
+
assert.equal(meeting.permissionToken, expectedInfoToParse.permissionToken);
|
|
2987
|
+
};
|
|
2988
|
+
|
|
2989
|
+
it('should parse meeting info from api return when locus meeting object is not available, set values, and return null', () => {
|
|
2883
2990
|
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
2991
|
+
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
2992
|
+
const FAKE_MEETING_INFO = {
|
|
2993
|
+
body: {
|
|
2994
|
+
conversationUrl: uuid1,
|
|
2995
|
+
locusUrl: url1,
|
|
2996
|
+
meetingJoinUrl: url2,
|
|
2997
|
+
meetingNumber: '12345',
|
|
2998
|
+
permissionToken: 'abc',
|
|
2999
|
+
sipMeetingUri: test1,
|
|
3000
|
+
sipUrl: test1,
|
|
3001
|
+
owner: test2
|
|
3002
|
+
}
|
|
3003
|
+
};
|
|
2884
3004
|
|
|
2885
|
-
meeting.parseMeetingInfo(
|
|
3005
|
+
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
3006
|
+
const expectedInfoToParse = {
|
|
3007
|
+
conversationUrl: uuid1,
|
|
3008
|
+
locusUrl: url1,
|
|
3009
|
+
sipUri: test1,
|
|
3010
|
+
meetingNumber: '12345',
|
|
3011
|
+
meetingJoinUrl: url2,
|
|
3012
|
+
owner: test2,
|
|
3013
|
+
permissionToken: 'abc'
|
|
3014
|
+
};
|
|
3015
|
+
|
|
3016
|
+
checkParseMeetingInfo(expectedInfoToParse);
|
|
3017
|
+
});
|
|
3018
|
+
it('should parse meeting info from locus meeting object if possible, else from api return, set values, and return null', () => {
|
|
3019
|
+
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
3020
|
+
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
3021
|
+
const FAKE_LOCUS_MEETING = {
|
|
3022
|
+
conversationUrl: 'locusConvURL',
|
|
3023
|
+
url: 'locusUrl',
|
|
3024
|
+
info: {
|
|
3025
|
+
webExMeetingId: 'locusMeetingId',
|
|
3026
|
+
sipUri: 'locusSipUri',
|
|
3027
|
+
owner: 'locusOwner'
|
|
3028
|
+
}
|
|
3029
|
+
};
|
|
3030
|
+
const FAKE_MEETING_INFO = {
|
|
2886
3031
|
body: {
|
|
2887
3032
|
conversationUrl: uuid1,
|
|
2888
3033
|
locusUrl: url1,
|
|
3034
|
+
meetingJoinUrl: url2,
|
|
3035
|
+
meetingNumber: '12345',
|
|
3036
|
+
permissionToken: 'abc',
|
|
2889
3037
|
sipMeetingUri: test1,
|
|
3038
|
+
sipUrl: test1,
|
|
2890
3039
|
owner: test2
|
|
2891
3040
|
}
|
|
2892
|
-
}
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
3041
|
+
};
|
|
3042
|
+
|
|
3043
|
+
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_LOCUS_MEETING);
|
|
3044
|
+
const expectedInfoToParse = {
|
|
3045
|
+
conversationUrl: 'locusConvURL',
|
|
3046
|
+
locusUrl: 'locusUrl',
|
|
3047
|
+
sipUri: 'locusSipUri',
|
|
3048
|
+
meetingNumber: 'locusMeetingId',
|
|
3049
|
+
meetingJoinUrl: url2,
|
|
3050
|
+
owner: 'locusOwner',
|
|
3051
|
+
permissionToken: 'abc'
|
|
3052
|
+
};
|
|
3053
|
+
|
|
3054
|
+
checkParseMeetingInfo(expectedInfoToParse);
|
|
3055
|
+
});
|
|
3056
|
+
it('should parse meeting info from api return, set values, and return null', () => {
|
|
3057
|
+
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
3058
|
+
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
3059
|
+
const FAKE_MEETING_INFO = {
|
|
3060
|
+
body: {
|
|
3061
|
+
conversationUrl: uuid1,
|
|
3062
|
+
locusUrl: url1,
|
|
3063
|
+
meetingJoinUrl: url2,
|
|
3064
|
+
meetingNumber: '12345',
|
|
3065
|
+
permissionToken: 'abc',
|
|
3066
|
+
sipMeetingUri: test1,
|
|
3067
|
+
sipUrl: test1,
|
|
3068
|
+
owner: test2
|
|
3069
|
+
}
|
|
3070
|
+
};
|
|
3071
|
+
|
|
3072
|
+
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
3073
|
+
const expectedInfoToParse = {
|
|
3074
|
+
conversationUrl: uuid1,
|
|
3075
|
+
locusUrl: url1,
|
|
3076
|
+
sipUri: test1,
|
|
3077
|
+
meetingNumber: '12345',
|
|
3078
|
+
meetingJoinUrl: url2,
|
|
3079
|
+
owner: test2,
|
|
3080
|
+
permissionToken: 'abc'
|
|
3081
|
+
};
|
|
3082
|
+
|
|
3083
|
+
checkParseMeetingInfo(expectedInfoToParse);
|
|
3084
|
+
});
|
|
3085
|
+
it('should parse meeting info, set values, and return null when destination is a string', () => {
|
|
3086
|
+
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
3087
|
+
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
3088
|
+
const FAKE_STRING_DESTINATION = 'sipUrl';
|
|
3089
|
+
const FAKE_MEETING_INFO = {
|
|
3090
|
+
body: {
|
|
3091
|
+
conversationUrl: uuid1,
|
|
3092
|
+
locusUrl: url1,
|
|
3093
|
+
meetingJoinUrl: url2,
|
|
3094
|
+
meetingNumber: '12345',
|
|
3095
|
+
permissionToken: 'abc',
|
|
3096
|
+
sipMeetingUri: test1,
|
|
3097
|
+
sipUrl: test1,
|
|
3098
|
+
owner: test2
|
|
3099
|
+
}
|
|
3100
|
+
};
|
|
3101
|
+
|
|
3102
|
+
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_STRING_DESTINATION);
|
|
3103
|
+
const expectedInfoToParse = {
|
|
3104
|
+
conversationUrl: uuid1,
|
|
3105
|
+
locusUrl: url1,
|
|
3106
|
+
sipUri: test1,
|
|
3107
|
+
meetingNumber: '12345',
|
|
3108
|
+
meetingJoinUrl: url2,
|
|
3109
|
+
owner: test2,
|
|
3110
|
+
permissionToken: 'abc'
|
|
3111
|
+
};
|
|
3112
|
+
|
|
3113
|
+
checkParseMeetingInfo(expectedInfoToParse);
|
|
2897
3114
|
});
|
|
2898
3115
|
});
|
|
2899
3116
|
describe('#parseLocus', () => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import sinon from 'sinon';
|
|
2
2
|
import {assert} from '@webex/test-helper-chai';
|
|
3
3
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
4
|
+
|
|
4
5
|
import Meetings from '@webex/plugin-meetings';
|
|
5
6
|
import MeetingRequest from '@webex/plugin-meetings/src/meeting/request';
|
|
6
7
|
|
|
@@ -249,5 +250,19 @@ describe('plugin-meetings', () => {
|
|
|
249
250
|
assert.equal(requestParams.body.device.deviceType, 'PROVISIONAL');
|
|
250
251
|
});
|
|
251
252
|
});
|
|
253
|
+
|
|
254
|
+
describe('#endMeetingForAll', () => {
|
|
255
|
+
it('sends request to endMeetingForAll', async () => {
|
|
256
|
+
const locusUrl = 'locusURL';
|
|
257
|
+
|
|
258
|
+
await meetingsRequest.endMeetingForAll({
|
|
259
|
+
locusUrl,
|
|
260
|
+
});
|
|
261
|
+
const requestParams = meetingsRequest.request.getCall(0).args[0];
|
|
262
|
+
|
|
263
|
+
assert.equal(requestParams.method, 'POST');
|
|
264
|
+
assert.equal(requestParams.uri, `${locusUrl}/end`);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
252
267
|
});
|
|
253
268
|
});
|
|
@@ -5,6 +5,11 @@ import 'jsdom-global/register';
|
|
|
5
5
|
|
|
6
6
|
import Device from '@webex/internal-plugin-device';
|
|
7
7
|
import Mercury from '@webex/internal-plugin-mercury';
|
|
8
|
+
import {assert} from '@webex/test-helper-chai';
|
|
9
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
10
|
+
import sinon from 'sinon';
|
|
11
|
+
import uuid from 'uuid';
|
|
12
|
+
|
|
8
13
|
import StaticConfig from '@webex/plugin-meetings/src/common/config';
|
|
9
14
|
import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
|
|
10
15
|
import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
|
|
@@ -16,11 +21,8 @@ import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
|
|
|
16
21
|
import MeetingsUtil from '@webex/plugin-meetings/src/meetings/util';
|
|
17
22
|
import PersonalMeetingRoom from '@webex/plugin-meetings/src/personal-meeting-room';
|
|
18
23
|
import Reachability from '@webex/plugin-meetings/src/reachability';
|
|
19
|
-
import {assert} from '@webex/test-helper-chai';
|
|
20
|
-
import MockWebex from '@webex/test-helper-mock-webex';
|
|
21
|
-
import sinon from 'sinon';
|
|
22
|
-
import uuid from 'uuid';
|
|
23
24
|
|
|
25
|
+
import testUtils from '../../../utils/testUtils';
|
|
24
26
|
import {
|
|
25
27
|
LOCUSEVENT,
|
|
26
28
|
OFFLINE,
|
|
@@ -489,12 +491,13 @@ describe('plugin-meetings', () => {
|
|
|
489
491
|
});
|
|
490
492
|
|
|
491
493
|
it('calls createMeeting and returns its promise', async () => {
|
|
492
|
-
const
|
|
494
|
+
const FAKE_USE_RANDOM_DELAY = true;
|
|
495
|
+
const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY);
|
|
493
496
|
|
|
494
497
|
assert.exists(create.then);
|
|
495
498
|
await create;
|
|
496
499
|
assert.calledOnce(webex.meetings.createMeeting);
|
|
497
|
-
assert.calledWith(webex.meetings.createMeeting, test1, test2);
|
|
500
|
+
assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY);
|
|
498
501
|
});
|
|
499
502
|
|
|
500
503
|
it('creates a new meeting when a scheduled meeting exists in the conversation', async () => {
|
|
@@ -582,7 +585,7 @@ describe('plugin-meetings', () => {
|
|
|
582
585
|
assert.calledOnce(webex.meetings.handleLocusEvent);
|
|
583
586
|
assert.calledWith(webex.meetings.handleLocusEvent, {
|
|
584
587
|
eventType: test1
|
|
585
|
-
});
|
|
588
|
+
}, true);
|
|
586
589
|
});
|
|
587
590
|
});
|
|
588
591
|
describe('#handleLocusEvent', () => {
|
|
@@ -753,43 +756,208 @@ describe('plugin-meetings', () => {
|
|
|
753
756
|
TriggerProxy.trigger.reset();
|
|
754
757
|
});
|
|
755
758
|
describe('successful MeetingInfo.#fetchMeetingInfo', () => {
|
|
759
|
+
let clock, setTimeoutSpy, fakeMeetingStartTimeString, FAKE_TIME_TO_START;
|
|
760
|
+
|
|
756
761
|
beforeEach(() => {
|
|
762
|
+
clock = sinon.useFakeTimers();
|
|
763
|
+
setTimeoutSpy = sinon.spy(clock, 'setTimeout');
|
|
757
764
|
webex.meetings.meetingInfo.fetchMeetingInfo = sinon.stub().returns(Promise.resolve({
|
|
758
765
|
body: {
|
|
759
766
|
permissionToken: 'PT', meetingJoinUrl: 'meetingJoinUrl'
|
|
760
767
|
}
|
|
761
768
|
}));
|
|
769
|
+
const nowTimeStamp = Date.now();
|
|
770
|
+
|
|
771
|
+
FAKE_TIME_TO_START = 0.1 * 60 * 1000;
|
|
772
|
+
const fakeMeetingStartTimeStamp = nowTimeStamp + FAKE_TIME_TO_START;
|
|
773
|
+
const fakeMeetingStartTimeDate = new Date(fakeMeetingStartTimeStamp);
|
|
774
|
+
|
|
775
|
+
fakeMeetingStartTimeString = fakeMeetingStartTimeDate.toISOString();
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
afterEach(() => {
|
|
779
|
+
clock.restore();
|
|
762
780
|
});
|
|
763
|
-
it('creates the meeting from a successful meeting info fetch promise testing', async () => {
|
|
764
|
-
const meeting = await webex.meetings.createMeeting('test destination', 'test type');
|
|
765
781
|
|
|
782
|
+
const checkCreateWithoutDelay = (meeting, destination, type, expectedMeetingData = {}) => {
|
|
766
783
|
assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
|
|
767
784
|
assert.calledOnce(MeetingsUtil.getMeetingAddedType);
|
|
768
|
-
assert.
|
|
769
|
-
assert.
|
|
785
|
+
assert.notCalled(setTimeoutSpy);
|
|
786
|
+
assert.calledThrice(TriggerProxy.trigger);
|
|
787
|
+
assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type);
|
|
770
788
|
assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
789
|
+
|
|
790
|
+
if (expectedMeetingData.permissionToken) {
|
|
791
|
+
assert.equal(meeting.permissionToken, expectedMeetingData.permissionToken);
|
|
792
|
+
}
|
|
793
|
+
if (expectedMeetingData.meetingJoinUrl) {
|
|
794
|
+
assert.equal(meeting.meetingJoinUrl, expectedMeetingData.meetingJoinUrl);
|
|
795
|
+
}
|
|
796
|
+
assert.equal(meeting.destination, destination);
|
|
797
|
+
assert.equal(meeting.destinationType, type);
|
|
798
|
+
assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
|
|
799
|
+
file: 'meetings', function: 'createMeeting'
|
|
800
|
+
}, 'meeting:added', {
|
|
801
|
+
meeting: sinon.match.instanceOf(Meeting), type: 'test meeting added type'
|
|
802
|
+
});
|
|
803
|
+
assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
|
|
804
|
+
};
|
|
805
|
+
|
|
806
|
+
it('creates the meeting from a successful meeting info fetch promise testing', async () => {
|
|
807
|
+
const meeting = await webex.meetings.createMeeting('test destination', 'test type');
|
|
808
|
+
|
|
809
|
+
const expectedMeetingData = {
|
|
810
|
+
permissionToken: 'PT',
|
|
811
|
+
meetingJoinUrl: 'meetingJoinUrl'
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
|
|
775
815
|
});
|
|
776
816
|
|
|
777
817
|
it('creates the meeting from a successful meeting info fetch meeting resolve testing', async () => {
|
|
778
818
|
const meeting = await webex.meetings.createMeeting('test destination', 'test type');
|
|
819
|
+
const expectedMeetingData = {
|
|
820
|
+
permissionToken: 'PT',
|
|
821
|
+
meetingJoinUrl: 'meetingJoinUrl'
|
|
822
|
+
};
|
|
779
823
|
|
|
780
824
|
assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
825
|
+
checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
it('creates the meeting from a successful meeting info fetch with random delay', async () => {
|
|
829
|
+
const FAKE_LOCUS_MEETING = {
|
|
830
|
+
conversationUrl: 'locusConvURL',
|
|
831
|
+
url: 'locusUrl',
|
|
832
|
+
info: {
|
|
833
|
+
webExMeetingId: 'locusMeetingId',
|
|
834
|
+
sipUri: 'locusSipUri',
|
|
835
|
+
owner: 'locusOwner'
|
|
836
|
+
},
|
|
837
|
+
meeting: {
|
|
838
|
+
startTime: fakeMeetingStartTimeString
|
|
839
|
+
},
|
|
840
|
+
fullState: {
|
|
841
|
+
active: false
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
const meeting = await webex.meetings.createMeeting(FAKE_LOCUS_MEETING, 'test type', true);
|
|
846
|
+
|
|
847
|
+
assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
|
|
848
|
+
assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
|
|
849
|
+
assert.calledOnce(setTimeoutSpy);
|
|
850
|
+
|
|
851
|
+
// Parse meeting info with locus object
|
|
852
|
+
assert.equal(meeting.conversationUrl, 'locusConvURL');
|
|
853
|
+
assert.equal(meeting.locusUrl, 'locusUrl');
|
|
854
|
+
assert.equal(meeting.sipUri, 'locusSipUri');
|
|
855
|
+
assert.equal(meeting.meetingNumber, 'locusMeetingId');
|
|
856
|
+
assert.isUndefined(meeting.meetingJoinUrl);
|
|
857
|
+
assert.equal(meeting.owner, 'locusOwner');
|
|
858
|
+
assert.isUndefined(meeting.permissionToken);
|
|
859
|
+
|
|
860
|
+
// Add meeting and send trigger
|
|
785
861
|
assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
|
|
862
|
+
assert.calledTwice(TriggerProxy.trigger);
|
|
786
863
|
assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meetings), {
|
|
787
864
|
file: 'meetings', function: 'createMeeting'
|
|
788
865
|
}, 'meeting:added', {
|
|
789
866
|
meeting: sinon.match.instanceOf(Meeting), type: 'test meeting added type'
|
|
790
867
|
});
|
|
868
|
+
|
|
869
|
+
// When timer expires
|
|
870
|
+
clock.tick(FAKE_TIME_TO_START);
|
|
871
|
+
assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, FAKE_LOCUS_MEETING, 'test type');
|
|
872
|
+
|
|
873
|
+
// Parse meeting info is called again with new meeting info
|
|
874
|
+
await testUtils.flushPromises();
|
|
875
|
+
assert.equal(meeting.conversationUrl, 'locusConvURL');
|
|
876
|
+
assert.equal(meeting.locusUrl, 'locusUrl');
|
|
877
|
+
assert.equal(meeting.sipUri, 'locusSipUri');
|
|
878
|
+
assert.equal(meeting.meetingNumber, 'locusMeetingId');
|
|
879
|
+
assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
|
|
880
|
+
assert.equal(meeting.owner, 'locusOwner');
|
|
881
|
+
assert.equal(meeting.permissionToken, 'PT');
|
|
882
|
+
|
|
883
|
+
assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
it('creates the meeting from a successful meeting info fetch that has no random delay because it is active', async () => {
|
|
887
|
+
const FAKE_LOCUS_MEETING = {
|
|
888
|
+
conversationUrl: 'locusConvURL',
|
|
889
|
+
url: 'locusUrl',
|
|
890
|
+
info: {
|
|
891
|
+
webExMeetingId: 'locusMeetingId',
|
|
892
|
+
sipUri: 'locusSipUri',
|
|
893
|
+
owner: 'locusOwner'
|
|
894
|
+
},
|
|
895
|
+
meeting: {
|
|
896
|
+
startTime: fakeMeetingStartTimeString
|
|
897
|
+
},
|
|
898
|
+
fullState: {
|
|
899
|
+
active: true
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
const meeting = await webex.meetings.createMeeting(FAKE_LOCUS_MEETING, 'test type', true);
|
|
904
|
+
|
|
905
|
+
assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
|
|
906
|
+
checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
it('creates the meeting from a successful meeting info fetch that has no random delay because meeting start time is in the past', async () => {
|
|
910
|
+
const FAKE_LOCUS_MEETING = {
|
|
911
|
+
conversationUrl: 'locusConvURL',
|
|
912
|
+
url: 'locusUrl',
|
|
913
|
+
info: {
|
|
914
|
+
webExMeetingId: 'locusMeetingId',
|
|
915
|
+
sipUri: 'locusSipUri',
|
|
916
|
+
owner: 'locusOwner'
|
|
917
|
+
},
|
|
918
|
+
meeting: {
|
|
919
|
+
startTime: fakeMeetingStartTimeString - (1 * 60 * 60 * 1000)
|
|
920
|
+
},
|
|
921
|
+
fullState: {
|
|
922
|
+
active: false
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
const meeting = await webex.meetings.createMeeting(FAKE_LOCUS_MEETING, 'test type', true);
|
|
927
|
+
|
|
928
|
+
assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
|
|
929
|
+
checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
it('creates the meeting from a successful meeting info fetch that has no random delay because enableUnifiedMeetings is disabled', async () => {
|
|
933
|
+
Object.assign(webex.meetings.config, {
|
|
934
|
+
experimental: {
|
|
935
|
+
enableUnifiedMeetings: false
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
const FAKE_LOCUS_MEETING = {
|
|
939
|
+
conversationUrl: 'locusConvURL',
|
|
940
|
+
url: 'locusUrl',
|
|
941
|
+
info: {
|
|
942
|
+
webExMeetingId: 'locusMeetingId',
|
|
943
|
+
sipUri: 'locusSipUri',
|
|
944
|
+
owner: 'locusOwner'
|
|
945
|
+
},
|
|
946
|
+
meeting: {
|
|
947
|
+
startTime: fakeMeetingStartTimeString
|
|
948
|
+
},
|
|
949
|
+
fullState: {
|
|
950
|
+
active: false
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
const meeting = await webex.meetings.createMeeting(FAKE_LOCUS_MEETING, 'test type', true);
|
|
955
|
+
|
|
956
|
+
assert.instanceOf(meeting, Meeting, 'createMeeting should eventually resolve to a Meeting Object');
|
|
957
|
+
checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
|
|
791
958
|
});
|
|
792
959
|
});
|
|
960
|
+
|
|
793
961
|
describe('rejected MeetingInfo.#fetchMeetingInfo', () => {
|
|
794
962
|
beforeEach(() => {
|
|
795
963
|
console.error = sinon.stub().returns(false);
|