@webex/plugin-meetings 3.12.0-next.1 → 3.12.0-next.3
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/aiEnableRequest/index.js +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +57 -33
- package/dist/meeting/index.js.map +1 -1
- package/dist/types/meeting/index.d.ts +13 -1
- package/dist/webinar/index.js +42 -12
- package/dist/webinar/index.js.map +1 -1
- package/package.json +13 -13
- package/src/meeting/index.ts +67 -46
- package/src/webinar/index.ts +46 -18
- package/test/unit/spec/meeting/index.js +125 -12
- package/test/unit/spec/webinar/index.ts +133 -8
|
@@ -1552,6 +1552,22 @@ describe('plugin-meetings', () => {
|
|
|
1552
1552
|
EVENT_TRIGGERS.MEETING_STOPPED_RECEIVING_TRANSCRIPTION
|
|
1553
1553
|
);
|
|
1554
1554
|
});
|
|
1555
|
+
|
|
1556
|
+
it('should stop listening to voicea events even when transcription is undefined', () => {
|
|
1557
|
+
meeting.transcription = undefined;
|
|
1558
|
+
meeting.stopTranscription();
|
|
1559
|
+
assert.equal(webex.internal.voicea.off.callCount, 4);
|
|
1560
|
+
assert.equal(meeting.areVoiceaEventsSetup, false);
|
|
1561
|
+
assert.calledWith(
|
|
1562
|
+
TriggerProxy.trigger,
|
|
1563
|
+
sinon.match.instanceOf(Meeting),
|
|
1564
|
+
{
|
|
1565
|
+
file: 'meeting/index',
|
|
1566
|
+
function: 'triggerStopReceivingTranscriptionEvent',
|
|
1567
|
+
},
|
|
1568
|
+
EVENT_TRIGGERS.MEETING_STOPPED_RECEIVING_TRANSCRIPTION
|
|
1569
|
+
);
|
|
1570
|
+
});
|
|
1555
1571
|
});
|
|
1556
1572
|
|
|
1557
1573
|
describe('#setCaptionLanguage', () => {
|
|
@@ -12745,6 +12761,93 @@ describe('plugin-meetings', () => {
|
|
|
12745
12761
|
});
|
|
12746
12762
|
});
|
|
12747
12763
|
|
|
12764
|
+
describe('#saveDataChannelToken', () => {
|
|
12765
|
+
beforeEach(() => {
|
|
12766
|
+
webex.internal.llm.setDatachannelToken = sinon.stub();
|
|
12767
|
+
});
|
|
12768
|
+
|
|
12769
|
+
it('saves datachannelToken into LLM as Default', () => {
|
|
12770
|
+
meeting.saveDataChannelToken({
|
|
12771
|
+
locus: {
|
|
12772
|
+
self: {datachannelToken: 'default-token'},
|
|
12773
|
+
},
|
|
12774
|
+
});
|
|
12775
|
+
|
|
12776
|
+
assert.calledWithExactly(
|
|
12777
|
+
webex.internal.llm.setDatachannelToken,
|
|
12778
|
+
'default-token',
|
|
12779
|
+
'llm-default-session'
|
|
12780
|
+
);
|
|
12781
|
+
});
|
|
12782
|
+
|
|
12783
|
+
it('saves practiceSessionDatachannelToken into LLM as PracticeSession', () => {
|
|
12784
|
+
meeting.saveDataChannelToken({
|
|
12785
|
+
locus: {
|
|
12786
|
+
self: {practiceSessionDatachannelToken: 'ps-token'},
|
|
12787
|
+
},
|
|
12788
|
+
});
|
|
12789
|
+
|
|
12790
|
+
assert.calledWithExactly(
|
|
12791
|
+
webex.internal.llm.setDatachannelToken,
|
|
12792
|
+
'ps-token',
|
|
12793
|
+
'llm-practice-session'
|
|
12794
|
+
);
|
|
12795
|
+
});
|
|
12796
|
+
|
|
12797
|
+
it('saves both tokens when both are present', () => {
|
|
12798
|
+
meeting.saveDataChannelToken({
|
|
12799
|
+
locus: {
|
|
12800
|
+
self: {
|
|
12801
|
+
datachannelToken: 'default-token',
|
|
12802
|
+
practiceSessionDatachannelToken: 'ps-token',
|
|
12803
|
+
},
|
|
12804
|
+
},
|
|
12805
|
+
});
|
|
12806
|
+
|
|
12807
|
+
assert.calledTwice(webex.internal.llm.setDatachannelToken);
|
|
12808
|
+
assert.calledWithExactly(
|
|
12809
|
+
webex.internal.llm.setDatachannelToken,
|
|
12810
|
+
'default-token',
|
|
12811
|
+
'llm-default-session'
|
|
12812
|
+
);
|
|
12813
|
+
assert.calledWithExactly(
|
|
12814
|
+
webex.internal.llm.setDatachannelToken,
|
|
12815
|
+
'ps-token',
|
|
12816
|
+
'llm-practice-session'
|
|
12817
|
+
);
|
|
12818
|
+
});
|
|
12819
|
+
|
|
12820
|
+
it('does not call setDatachannelToken when no tokens are present', () => {
|
|
12821
|
+
meeting.saveDataChannelToken({locus: {self: {}}});
|
|
12822
|
+
|
|
12823
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
12824
|
+
});
|
|
12825
|
+
|
|
12826
|
+
it('handles undefined join gracefully', () => {
|
|
12827
|
+
meeting.saveDataChannelToken(undefined);
|
|
12828
|
+
|
|
12829
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
12830
|
+
});
|
|
12831
|
+
|
|
12832
|
+
it('handles missing locus.self gracefully', () => {
|
|
12833
|
+
meeting.saveDataChannelToken({locus: {}});
|
|
12834
|
+
|
|
12835
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
12836
|
+
});
|
|
12837
|
+
});
|
|
12838
|
+
|
|
12839
|
+
describe('#clearDataChannelToken', () => {
|
|
12840
|
+
beforeEach(() => {
|
|
12841
|
+
webex.internal.llm.resetDatachannelTokens = sinon.stub();
|
|
12842
|
+
});
|
|
12843
|
+
|
|
12844
|
+
it('calls resetDatachannelTokens on LLM', () => {
|
|
12845
|
+
meeting.clearDataChannelToken();
|
|
12846
|
+
|
|
12847
|
+
assert.calledOnce(webex.internal.llm.resetDatachannelTokens);
|
|
12848
|
+
});
|
|
12849
|
+
});
|
|
12850
|
+
|
|
12748
12851
|
describe('#updateLLMConnection', () => {
|
|
12749
12852
|
beforeEach(() => {
|
|
12750
12853
|
webex.internal.llm.isConnected = sinon.stub().returns(false);
|
|
@@ -13011,15 +13114,14 @@ describe('plugin-meetings', () => {
|
|
|
13011
13114
|
undefined
|
|
13012
13115
|
);
|
|
13013
13116
|
});
|
|
13014
|
-
it('passes dataChannelToken to registerAndConnect', async () => {
|
|
13117
|
+
it('passes dataChannelToken from LLM to registerAndConnect', async () => {
|
|
13015
13118
|
meeting.joinedWith = {state: 'JOINED'};
|
|
13016
13119
|
meeting.locusInfo = {
|
|
13017
13120
|
url: 'a url',
|
|
13018
13121
|
info: {datachannelUrl: 'a datachannel url'},
|
|
13019
|
-
self: {datachannelToken: 'token-123'},
|
|
13020
13122
|
};
|
|
13021
13123
|
|
|
13022
|
-
webex.internal.llm.getDatachannelToken.returns(
|
|
13124
|
+
webex.internal.llm.getDatachannelToken.withArgs('llm-default-session').returns('token-123');
|
|
13023
13125
|
|
|
13024
13126
|
await meeting.updateLLMConnection();
|
|
13025
13127
|
|
|
@@ -13029,17 +13131,16 @@ describe('plugin-meetings', () => {
|
|
|
13029
13131
|
'a datachannel url',
|
|
13030
13132
|
'token-123'
|
|
13031
13133
|
);
|
|
13032
|
-
assert.
|
|
13134
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
13033
13135
|
});
|
|
13034
|
-
it('
|
|
13136
|
+
it('passes undefined token when LLM has no token stored', async () => {
|
|
13035
13137
|
meeting.joinedWith = {state: 'JOINED'};
|
|
13036
13138
|
meeting.locusInfo = {
|
|
13037
13139
|
url: 'a url',
|
|
13038
13140
|
info: {datachannelUrl: 'a datachannel url'},
|
|
13039
|
-
self: {datachannelToken: 'locus-token'},
|
|
13040
13141
|
};
|
|
13041
13142
|
|
|
13042
|
-
webex.internal.llm.getDatachannelToken.
|
|
13143
|
+
webex.internal.llm.getDatachannelToken.returns(undefined);
|
|
13043
13144
|
|
|
13044
13145
|
await meeting.updateLLMConnection();
|
|
13045
13146
|
|
|
@@ -13047,7 +13148,7 @@ describe('plugin-meetings', () => {
|
|
|
13047
13148
|
webex.internal.llm.registerAndConnect,
|
|
13048
13149
|
'a url',
|
|
13049
13150
|
'a datachannel url',
|
|
13050
|
-
|
|
13151
|
+
undefined
|
|
13051
13152
|
);
|
|
13052
13153
|
|
|
13053
13154
|
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
@@ -13058,7 +13159,6 @@ describe('plugin-meetings', () => {
|
|
|
13058
13159
|
meeting.locusInfo = {
|
|
13059
13160
|
url: 'a url',
|
|
13060
13161
|
info: {datachannelUrl: 'a datachannel url'},
|
|
13061
|
-
self: {datachannelToken: 'token-123'},
|
|
13062
13162
|
};
|
|
13063
13163
|
|
|
13064
13164
|
webex.internal.llm.getDatachannelToken.returns(undefined);
|
|
@@ -13070,9 +13170,9 @@ describe('plugin-meetings', () => {
|
|
|
13070
13170
|
webex.internal.llm.registerAndConnect,
|
|
13071
13171
|
'a url',
|
|
13072
13172
|
'a datachannel url',
|
|
13073
|
-
|
|
13173
|
+
undefined
|
|
13074
13174
|
);
|
|
13075
|
-
assert.
|
|
13175
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
13076
13176
|
});
|
|
13077
13177
|
|
|
13078
13178
|
describe('#clearMeetingData', () => {
|
|
@@ -13083,7 +13183,7 @@ describe('plugin-meetings', () => {
|
|
|
13083
13183
|
meeting.annotation.deregisterEvents = sinon.stub();
|
|
13084
13184
|
meeting.clearLLMHealthCheckTimer = sinon.stub();
|
|
13085
13185
|
meeting.stopTranscription = sinon.stub();
|
|
13086
|
-
meeting.
|
|
13186
|
+
meeting.clearDataChannelToken = sinon.stub();
|
|
13087
13187
|
meeting.shareStatus = 'no-share';
|
|
13088
13188
|
});
|
|
13089
13189
|
|
|
@@ -13107,6 +13207,8 @@ describe('plugin-meetings', () => {
|
|
|
13107
13207
|
);
|
|
13108
13208
|
assert.calledOnce(meeting.clearLLMHealthCheckTimer);
|
|
13109
13209
|
assert.calledOnce(meeting.stopTranscription);
|
|
13210
|
+
assert.isUndefined(meeting.transcription);
|
|
13211
|
+
assert.calledOnce(meeting.clearDataChannelToken);
|
|
13110
13212
|
assert.calledOnce(meeting.annotation.deregisterEvents);
|
|
13111
13213
|
});
|
|
13112
13214
|
it('continues cleanup when disconnectLLM fails during meeting data cleanup', async () => {
|
|
@@ -13127,8 +13229,19 @@ describe('plugin-meetings', () => {
|
|
|
13127
13229
|
);
|
|
13128
13230
|
assert.calledOnce(meeting.clearLLMHealthCheckTimer);
|
|
13129
13231
|
assert.calledOnce(meeting.stopTranscription);
|
|
13232
|
+
assert.isUndefined(meeting.transcription);
|
|
13233
|
+
assert.calledOnce(meeting.clearDataChannelToken);
|
|
13130
13234
|
assert.calledOnce(meeting.annotation.deregisterEvents);
|
|
13131
13235
|
});
|
|
13236
|
+
it('always calls stopTranscription even when transcription is undefined', async () => {
|
|
13237
|
+
meeting.transcription = undefined;
|
|
13238
|
+
|
|
13239
|
+
await meeting.clearMeetingData();
|
|
13240
|
+
|
|
13241
|
+
assert.calledOnce(meeting.stopTranscription);
|
|
13242
|
+
assert.isUndefined(meeting.transcription);
|
|
13243
|
+
assert.calledOnce(meeting.clearDataChannelToken);
|
|
13244
|
+
});
|
|
13132
13245
|
});
|
|
13133
13246
|
});
|
|
13134
13247
|
|
|
@@ -210,6 +210,26 @@ describe('plugin-meetings', () => {
|
|
|
210
210
|
meeting.processRelayEvent
|
|
211
211
|
);
|
|
212
212
|
});
|
|
213
|
+
|
|
214
|
+
it('removes a pending online listener if one exists', async () => {
|
|
215
|
+
const listener = sinon.stub();
|
|
216
|
+
webinar._pendingOnlineListener = listener;
|
|
217
|
+
|
|
218
|
+
await webinar.cleanupPSDataChannel();
|
|
219
|
+
|
|
220
|
+
assert.calledWith(webex.internal.llm.off, 'online', listener);
|
|
221
|
+
assert.isNull(webinar._pendingOnlineListener);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('skips online listener removal when none is pending', async () => {
|
|
225
|
+
webinar._pendingOnlineListener = null;
|
|
226
|
+
|
|
227
|
+
await webinar.cleanupPSDataChannel();
|
|
228
|
+
|
|
229
|
+
// 'off' should only be called for the relay event, not for 'online'
|
|
230
|
+
const onlineOffCalls = webex.internal.llm.off.args.filter(([event]) => event === 'online');
|
|
231
|
+
assert.equal(onlineOffCalls.length, 0);
|
|
232
|
+
});
|
|
213
233
|
});
|
|
214
234
|
|
|
215
235
|
describe('#updatePSDataChannel', () => {
|
|
@@ -224,12 +244,22 @@ describe('plugin-meetings', () => {
|
|
|
224
244
|
locusInfo: {
|
|
225
245
|
url: 'locus-url',
|
|
226
246
|
info: {practiceSessionDatachannelUrl: 'dc-url'},
|
|
227
|
-
self: {practiceSessionDatachannelToken: 'ps-token'},
|
|
228
247
|
},
|
|
229
248
|
};
|
|
230
249
|
|
|
231
250
|
webex.meetings.getMeetingByType = sinon.stub().returns(meeting);
|
|
232
251
|
|
|
252
|
+
// Default session is connected by default; practice session is not
|
|
253
|
+
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
254
|
+
return sessionId !== LLM_PRACTICE_SESSION;
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Token is pre-saved into LLM by saveDataChannelToken
|
|
258
|
+
webex.internal.llm.getDatachannelToken = sinon.stub().callsFake((tokenType) => {
|
|
259
|
+
if (tokenType === DataChannelTokenType.PracticeSession) return 'ps-token';
|
|
260
|
+
return undefined;
|
|
261
|
+
});
|
|
262
|
+
|
|
233
263
|
// Ensure connect path is eligible
|
|
234
264
|
webinar.selfIsPanelist = true;
|
|
235
265
|
webinar.practiceSessionEnabled = true;
|
|
@@ -284,11 +314,6 @@ describe('plugin-meetings', () => {
|
|
|
284
314
|
it('connects when eligible', async () => {
|
|
285
315
|
const result = await webinar.updatePSDataChannel();
|
|
286
316
|
|
|
287
|
-
assert.calledOnceWithExactly(
|
|
288
|
-
webex.internal.llm.setDatachannelToken,
|
|
289
|
-
'ps-token',
|
|
290
|
-
DataChannelTokenType.PracticeSession
|
|
291
|
-
);
|
|
292
317
|
assert.calledOnce(webex.internal.llm.registerAndConnect);
|
|
293
318
|
assert.calledWith(
|
|
294
319
|
webex.internal.llm.registerAndConnect,
|
|
@@ -301,8 +326,11 @@ describe('plugin-meetings', () => {
|
|
|
301
326
|
assert.equal(result, 'REGISTER_AND_CONNECT_RESULT');
|
|
302
327
|
});
|
|
303
328
|
|
|
304
|
-
it('uses
|
|
305
|
-
webex.internal.llm.getDatachannelToken.
|
|
329
|
+
it('uses token from LLM', async () => {
|
|
330
|
+
webex.internal.llm.getDatachannelToken = sinon.stub().callsFake((tokenType) => {
|
|
331
|
+
if (tokenType === DataChannelTokenType.PracticeSession) return 'cached-token';
|
|
332
|
+
return undefined;
|
|
333
|
+
});
|
|
306
334
|
|
|
307
335
|
await webinar.updatePSDataChannel();
|
|
308
336
|
|
|
@@ -360,6 +388,101 @@ describe('plugin-meetings', () => {
|
|
|
360
388
|
|
|
361
389
|
assert.notCalled(webex.internal.voicea.updateSubchannelSubscriptions);
|
|
362
390
|
});
|
|
391
|
+
|
|
392
|
+
it('defers connect when default session is not yet connected', async () => {
|
|
393
|
+
// Default session is not connected initially
|
|
394
|
+
webex.internal.llm.isConnected = sinon.stub().returns(false);
|
|
395
|
+
|
|
396
|
+
const result = await webinar.updatePSDataChannel();
|
|
397
|
+
|
|
398
|
+
// Should return undefined immediately (deferred)
|
|
399
|
+
assert.isUndefined(result);
|
|
400
|
+
// Should register an 'online' listener but NOT call registerAndConnect yet
|
|
401
|
+
assert.calledWith(webex.internal.llm.on, 'online', sinon.match.func);
|
|
402
|
+
assert.notCalled(webex.internal.llm.registerAndConnect);
|
|
403
|
+
// Should store the pending listener
|
|
404
|
+
assert.isNotNull(webinar._pendingOnlineListener);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it('does not register duplicate online listeners on repeated calls', async () => {
|
|
408
|
+
webex.internal.llm.isConnected = sinon.stub().returns(false);
|
|
409
|
+
|
|
410
|
+
await webinar.updatePSDataChannel();
|
|
411
|
+
await webinar.updatePSDataChannel();
|
|
412
|
+
await webinar.updatePSDataChannel();
|
|
413
|
+
|
|
414
|
+
// Only one 'online' listener should have been registered
|
|
415
|
+
const onlineCalls = webex.internal.llm.on.args.filter(([event]) => event === 'online');
|
|
416
|
+
assert.equal(onlineCalls.length, 1, 'should register exactly one online listener');
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it('re-invokes updatePSDataChannel when default session comes online', async () => {
|
|
420
|
+
// Default session is not connected initially
|
|
421
|
+
webex.internal.llm.isConnected = sinon.stub().returns(false);
|
|
422
|
+
|
|
423
|
+
const updatePSDataChannelSpy = sinon.spy(webinar, 'updatePSDataChannel');
|
|
424
|
+
|
|
425
|
+
// First call defers
|
|
426
|
+
await webinar.updatePSDataChannel();
|
|
427
|
+
|
|
428
|
+
// Capture the 'online' listener
|
|
429
|
+
const onlineCall = webex.internal.llm.on.args.find(([event]) => event === 'online');
|
|
430
|
+
assert.isDefined(onlineCall, 'should have registered an online listener');
|
|
431
|
+
|
|
432
|
+
// Now simulate default session coming online
|
|
433
|
+
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
434
|
+
return sessionId !== LLM_PRACTICE_SESSION;
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// Fire the captured listener
|
|
438
|
+
onlineCall[1]();
|
|
439
|
+
|
|
440
|
+
// The listener should have cleared itself, removed itself, and re-called updatePSDataChannel
|
|
441
|
+
assert.isNull(webinar._pendingOnlineListener);
|
|
442
|
+
assert.calledWith(webex.internal.llm.off, 'online', sinon.match.func);
|
|
443
|
+
assert.equal(updatePSDataChannelSpy.callCount, 2);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it('does not reconnect with stale data if demoted before default session comes online', async () => {
|
|
447
|
+
// Default session is not connected initially
|
|
448
|
+
webex.internal.llm.isConnected = sinon.stub().returns(false);
|
|
449
|
+
|
|
450
|
+
await webinar.updatePSDataChannel();
|
|
451
|
+
|
|
452
|
+
// Capture the 'online' listener
|
|
453
|
+
const onlineCall = webex.internal.llm.on.args.find(([event]) => event === 'online');
|
|
454
|
+
assert.isDefined(onlineCall);
|
|
455
|
+
|
|
456
|
+
// Simulate demotion while waiting
|
|
457
|
+
webinar.selfIsPanelist = false;
|
|
458
|
+
|
|
459
|
+
// Now default session comes online
|
|
460
|
+
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
461
|
+
return sessionId !== LLM_PRACTICE_SESSION;
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// Fire the listener — re-invokes updatePSDataChannel which will see isPracticeSession = false
|
|
465
|
+
onlineCall[1]();
|
|
466
|
+
|
|
467
|
+
// Should NOT have called registerAndConnect since the user is no longer eligible
|
|
468
|
+
assert.notCalled(webex.internal.llm.registerAndConnect);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
it('proceeds immediately when default session is already connected', async () => {
|
|
472
|
+
// Default session already connected, practice session not
|
|
473
|
+
webex.internal.llm.isConnected = sinon.stub().callsFake((sessionId) => {
|
|
474
|
+
return sessionId !== LLM_PRACTICE_SESSION;
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
const result = await webinar.updatePSDataChannel();
|
|
478
|
+
|
|
479
|
+
// The 'online' listener is registered then immediately removed since default session is already connected
|
|
480
|
+
assert.calledWith(webex.internal.llm.on, 'online', sinon.match.func);
|
|
481
|
+
assert.calledWith(webex.internal.llm.off, 'online', sinon.match.func);
|
|
482
|
+
assert.isNull(webinar._pendingOnlineListener);
|
|
483
|
+
assert.calledOnce(webex.internal.llm.registerAndConnect);
|
|
484
|
+
assert.equal(result, 'REGISTER_AND_CONNECT_RESULT');
|
|
485
|
+
});
|
|
363
486
|
});
|
|
364
487
|
|
|
365
488
|
describe('#updateStatusByRole', () => {
|
|
@@ -369,6 +492,7 @@ describe('plugin-meetings', () => {
|
|
|
369
492
|
webinar.webex.meetings = {
|
|
370
493
|
getMeetingByType: sinon.stub().returns({
|
|
371
494
|
id: 'meeting-id',
|
|
495
|
+
isJoined: sinon.stub().returns(false),
|
|
372
496
|
updateLLMConnection: sinon.stub(),
|
|
373
497
|
shareStatus: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE,
|
|
374
498
|
locusInfo: {
|
|
@@ -423,6 +547,7 @@ describe('plugin-meetings', () => {
|
|
|
423
547
|
webinar.webex.meetings = {
|
|
424
548
|
getMeetingByType: sinon.stub().returns({
|
|
425
549
|
id: 'meeting-id',
|
|
550
|
+
isJoined: sinon.stub().returns(false),
|
|
426
551
|
updateLLMConnection: sinon.stub(),
|
|
427
552
|
shareStatus: SHARE_STATUS.REMOTE_SHARE_ACTIVE,
|
|
428
553
|
locusInfo: {
|