@webex/plugin-meetings 3.8.0-web-workers-keepalive.1 → 3.8.1-next.1

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.
Files changed (168) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +70 -6
  3. package/dist/breakouts/index.js.map +1 -1
  4. package/dist/common/errors/webex-errors.js +12 -2
  5. package/dist/common/errors/webex-errors.js.map +1 -1
  6. package/dist/config.js +4 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/constants.js +22 -123
  9. package/dist/constants.js.map +1 -1
  10. package/dist/controls-options-manager/enums.js +2 -0
  11. package/dist/controls-options-manager/enums.js.map +1 -1
  12. package/dist/controls-options-manager/types.js.map +1 -1
  13. package/dist/controls-options-manager/util.js +52 -0
  14. package/dist/controls-options-manager/util.js.map +1 -1
  15. package/dist/interpretation/index.js +1 -1
  16. package/dist/interpretation/siLanguage.js +1 -1
  17. package/dist/locus-info/controlsUtils.js +30 -10
  18. package/dist/locus-info/controlsUtils.js.map +1 -1
  19. package/dist/locus-info/index.js +83 -12
  20. package/dist/locus-info/index.js.map +1 -1
  21. package/dist/locus-info/selfUtils.js +432 -418
  22. package/dist/locus-info/selfUtils.js.map +1 -1
  23. package/dist/media/index.js +17 -17
  24. package/dist/media/index.js.map +1 -1
  25. package/dist/media/properties.js +94 -6
  26. package/dist/media/properties.js.map +1 -1
  27. package/dist/meeting/brbState.js +9 -2
  28. package/dist/meeting/brbState.js.map +1 -1
  29. package/dist/meeting/in-meeting-actions.js +17 -1
  30. package/dist/meeting/in-meeting-actions.js.map +1 -1
  31. package/dist/meeting/index.js +568 -328
  32. package/dist/meeting/index.js.map +1 -1
  33. package/dist/meeting/locusMediaRequest.js +0 -17
  34. package/dist/meeting/locusMediaRequest.js.map +1 -1
  35. package/dist/meeting/muteState.js +4 -4
  36. package/dist/meeting/muteState.js.map +1 -1
  37. package/dist/meeting/request.js +30 -0
  38. package/dist/meeting/request.js.map +1 -1
  39. package/dist/meeting/request.type.js.map +1 -1
  40. package/dist/meeting/util.js +9 -1
  41. package/dist/meeting/util.js.map +1 -1
  42. package/dist/meeting-info/meeting-info-v2.js +19 -13
  43. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  44. package/dist/meeting-info/utilv2.js +5 -1
  45. package/dist/meeting-info/utilv2.js.map +1 -1
  46. package/dist/meetings/index.js +76 -0
  47. package/dist/meetings/index.js.map +1 -1
  48. package/dist/meetings/util.js +14 -0
  49. package/dist/meetings/util.js.map +1 -1
  50. package/dist/member/index.js +45 -9
  51. package/dist/member/index.js.map +1 -1
  52. package/dist/member/types.js +3 -0
  53. package/dist/member/types.js.map +1 -1
  54. package/dist/member/util.js +335 -356
  55. package/dist/member/util.js.map +1 -1
  56. package/dist/members/collection.js.map +1 -1
  57. package/dist/members/index.js +137 -29
  58. package/dist/members/index.js.map +1 -1
  59. package/dist/members/request.js +38 -0
  60. package/dist/members/request.js.map +1 -1
  61. package/dist/members/util.js +36 -1
  62. package/dist/members/util.js.map +1 -1
  63. package/dist/metrics/constants.js +1 -0
  64. package/dist/metrics/constants.js.map +1 -1
  65. package/dist/reachability/clusterReachability.js +23 -31
  66. package/dist/reachability/clusterReachability.js.map +1 -1
  67. package/dist/reachability/index.js +42 -2
  68. package/dist/reachability/index.js.map +1 -1
  69. package/dist/reconnection-manager/index.js +2 -2
  70. package/dist/reconnection-manager/index.js.map +1 -1
  71. package/dist/roap/index.js.map +1 -1
  72. package/dist/roap/turnDiscovery.js +45 -27
  73. package/dist/roap/turnDiscovery.js.map +1 -1
  74. package/dist/roap/types.js +17 -0
  75. package/dist/roap/types.js.map +1 -0
  76. package/dist/types/common/errors/webex-errors.d.ts +7 -1
  77. package/dist/types/config.d.ts +2 -0
  78. package/dist/types/constants.d.ts +15 -85
  79. package/dist/types/controls-options-manager/enums.d.ts +3 -1
  80. package/dist/types/controls-options-manager/types.d.ts +7 -1
  81. package/dist/types/locus-info/index.d.ts +3 -3
  82. package/dist/types/locus-info/selfUtils.d.ts +216 -1
  83. package/dist/types/media/properties.d.ts +15 -0
  84. package/dist/types/meeting/in-meeting-actions.d.ts +16 -0
  85. package/dist/types/meeting/index.d.ts +35 -1
  86. package/dist/types/meeting/muteState.d.ts +0 -1
  87. package/dist/types/meeting/request.d.ts +12 -1
  88. package/dist/types/meeting/request.type.d.ts +6 -0
  89. package/dist/types/meeting/util.d.ts +3 -1
  90. package/dist/types/meeting-info/meeting-info-v2.d.ts +2 -1
  91. package/dist/types/meetings/index.d.ts +28 -0
  92. package/dist/types/member/index.d.ts +20 -6
  93. package/dist/types/member/types.d.ts +73 -14
  94. package/dist/types/member/util.d.ts +156 -1
  95. package/dist/types/members/collection.d.ts +6 -5
  96. package/dist/types/members/index.d.ts +32 -43
  97. package/dist/types/members/request.d.ts +26 -0
  98. package/dist/types/members/util.d.ts +27 -0
  99. package/dist/types/metrics/constants.d.ts +1 -0
  100. package/dist/types/reachability/clusterReachability.d.ts +2 -6
  101. package/dist/types/reachability/index.d.ts +8 -0
  102. package/dist/types/roap/index.d.ts +3 -2
  103. package/dist/types/roap/turnDiscovery.d.ts +5 -17
  104. package/dist/types/roap/types.d.ts +16 -0
  105. package/dist/webinar/index.js +1 -1
  106. package/package.json +24 -23
  107. package/src/breakouts/index.ts +69 -0
  108. package/src/common/errors/webex-errors.ts +8 -1
  109. package/src/config.ts +2 -0
  110. package/src/constants.ts +23 -90
  111. package/src/controls-options-manager/enums.ts +2 -0
  112. package/src/controls-options-manager/types.ts +11 -1
  113. package/src/controls-options-manager/util.ts +62 -0
  114. package/src/locus-info/controlsUtils.ts +48 -12
  115. package/src/locus-info/index.ts +88 -13
  116. package/src/locus-info/selfUtils.ts +496 -442
  117. package/src/media/index.ts +23 -21
  118. package/src/media/properties.ts +96 -0
  119. package/src/meeting/brbState.ts +11 -2
  120. package/src/meeting/in-meeting-actions.ts +32 -0
  121. package/src/meeting/index.ts +356 -87
  122. package/src/meeting/locusMediaRequest.ts +0 -18
  123. package/src/meeting/muteState.ts +4 -4
  124. package/src/meeting/request.ts +36 -1
  125. package/src/meeting/request.type.ts +7 -0
  126. package/src/meeting/util.ts +9 -1
  127. package/src/meeting-info/meeting-info-v2.ts +7 -2
  128. package/src/meeting-info/utilv2.ts +5 -0
  129. package/src/meetings/index.ts +76 -0
  130. package/src/meetings/util.ts +18 -0
  131. package/src/member/index.ts +57 -22
  132. package/src/member/types.ts +82 -16
  133. package/src/member/util.ts +357 -353
  134. package/src/members/collection.ts +4 -3
  135. package/src/members/index.ts +137 -18
  136. package/src/members/request.ts +44 -0
  137. package/src/members/util.ts +43 -1
  138. package/src/metrics/constants.ts +1 -0
  139. package/src/reachability/clusterReachability.ts +26 -25
  140. package/src/reachability/index.ts +55 -1
  141. package/src/reconnection-manager/index.ts +2 -2
  142. package/src/roap/index.ts +3 -7
  143. package/src/roap/turnDiscovery.ts +34 -39
  144. package/src/roap/types.ts +23 -0
  145. package/test/unit/spec/breakouts/index.ts +167 -95
  146. package/test/unit/spec/controls-options-manager/util.js +120 -0
  147. package/test/unit/spec/locus-info/controlsUtils.js +131 -9
  148. package/test/unit/spec/locus-info/index.js +195 -73
  149. package/test/unit/spec/locus-info/selfUtils.js +98 -24
  150. package/test/unit/spec/media/index.ts +150 -18
  151. package/test/unit/spec/media/properties.ts +130 -0
  152. package/test/unit/spec/meeting/brbState.ts +40 -2
  153. package/test/unit/spec/meeting/in-meeting-actions.ts +19 -4
  154. package/test/unit/spec/meeting/index.js +553 -36
  155. package/test/unit/spec/meeting/locusMediaRequest.ts +0 -30
  156. package/test/unit/spec/meeting/muteState.js +73 -2
  157. package/test/unit/spec/meeting/request.js +32 -1
  158. package/test/unit/spec/meeting/utils.js +79 -33
  159. package/test/unit/spec/meeting-info/meetinginfov2.js +41 -0
  160. package/test/unit/spec/meeting-info/utilv2.js +19 -0
  161. package/test/unit/spec/meetings/index.js +68 -1
  162. package/test/unit/spec/members/index.js +304 -78
  163. package/test/unit/spec/members/request.js +68 -22
  164. package/test/unit/spec/members/utils.js +75 -0
  165. package/test/unit/spec/reachability/clusterReachability.ts +41 -55
  166. package/test/unit/spec/reachability/index.ts +89 -0
  167. package/test/unit/spec/reconnection-manager/index.js +4 -4
  168. package/test/unit/spec/roap/turnDiscovery.ts +110 -28
@@ -4,11 +4,11 @@ import {Defer} from '@webex/common';
4
4
  import Metrics from '../metrics';
5
5
  import BEHAVIORAL_METRICS from '../metrics/constants';
6
6
  import LoggerProxy from '../common/logs/logger-proxy';
7
- import {ROAP, Enum} from '../constants';
7
+ import {ROAP} from '../constants';
8
8
 
9
9
  import RoapRequest from './request';
10
10
  import Meeting from '../meeting';
11
- import MeetingUtil from '../meeting/util';
11
+ import {TurnDiscoverySkipReason, TurnServerInfo, TurnDiscoveryResult} from './types';
12
12
 
13
13
  const TURN_DISCOVERY_TIMEOUT = 10; // in seconds
14
14
 
@@ -18,28 +18,6 @@ const TURN_DISCOVERY_TIMEOUT = 10; // in seconds
18
18
  // and do the SDP offer with seq=1
19
19
  const TURN_DISCOVERY_SEQ = 0;
20
20
 
21
- const TurnDiscoverySkipReason = {
22
- missingHttpResponse: 'missing http response', // when we asked for the TURN discovery response to be in the http response, but it wasn't there
23
- reachability: 'reachability', // when udp reachability to public clusters is ok, so we don't need TURN (this doens't apply when joinWithMedia() is used)
24
- alreadyInProgress: 'already in progress', // when we try to start TURN discovery while it's already in progress
25
- } as const;
26
-
27
- export type TurnDiscoverySkipReason =
28
- | Enum<typeof TurnDiscoverySkipReason> // this is a kind of FYI, because in practice typescript will infer the type of TurnDiscoverySkipReason as a string
29
- | string // used in case of errors, contains the error message
30
- | undefined; // used when TURN discovery is not skipped
31
-
32
- export type TurnServerInfo = {
33
- url: string;
34
- username: string;
35
- password: string;
36
- };
37
-
38
- export type TurnDiscoveryResult = {
39
- turnServerInfo?: TurnServerInfo;
40
- turnDiscoverySkippedReason: TurnDiscoverySkipReason;
41
- };
42
-
43
21
  /**
44
22
  * Handles the process of finding out TURN server information from Linus.
45
23
  * This is achieved by sending a TURN_DISCOVERY_REQUEST.
@@ -53,6 +31,17 @@ export default class TurnDiscovery {
53
31
 
54
32
  private responseTimer?: ReturnType<typeof setTimeout>;
55
33
 
34
+ /** Resets the turnInfo structure to the defaults
35
+ * @returns {void}
36
+ */
37
+ private resetTurnInfo() {
38
+ this.turnInfo = {
39
+ urls: [],
40
+ username: '',
41
+ password: '',
42
+ };
43
+ }
44
+
56
45
  /**
57
46
  * Constructor
58
47
  *
@@ -60,11 +49,7 @@ export default class TurnDiscovery {
60
49
  */
61
50
  constructor(roapRequest: RoapRequest) {
62
51
  this.roapRequest = roapRequest;
63
- this.turnInfo = {
64
- url: '',
65
- username: '',
66
- password: '',
67
- };
52
+ this.resetTurnInfo();
68
53
  }
69
54
 
70
55
  /**
@@ -134,21 +119,29 @@ export default class TurnDiscovery {
134
119
  }
135
120
 
136
121
  const expectedHeaders = [
137
- {headerName: 'x-cisco-turn-url', field: 'url'},
138
- {headerName: 'x-cisco-turn-username', field: 'username'},
139
- {headerName: 'x-cisco-turn-password', field: 'password'},
122
+ {headerName: 'x-cisco-turn-url', field: 'urls', multipleAllowed: true},
123
+ {headerName: 'x-cisco-turn-username', field: 'username', multipleAllowed: false},
124
+ {headerName: 'x-cisco-turn-password', field: 'password', multipleAllowed: false},
140
125
  ];
141
126
 
142
- let foundHeaders = 0;
127
+ const foundHeaders = {};
128
+
129
+ this.resetTurnInfo();
143
130
 
144
131
  headers?.forEach((receivedHeader) => {
145
132
  // check if it matches any of our expected headers
146
133
  expectedHeaders.forEach((expectedHeader) => {
147
134
  if (receivedHeader.startsWith(`${expectedHeader.headerName}=`)) {
148
- this.turnInfo[expectedHeader.field] = receivedHeader.substring(
149
- expectedHeader.headerName.length + 1
150
- );
151
- foundHeaders += 1;
135
+ foundHeaders[expectedHeader.headerName] = true;
136
+
137
+ const headerValue = receivedHeader.substring(expectedHeader.headerName.length + 1);
138
+
139
+ if (expectedHeader.multipleAllowed) {
140
+ this.turnInfo[expectedHeader.field].push(headerValue);
141
+ } else {
142
+ // just store the last one we find
143
+ this.turnInfo[expectedHeader.field] = headerValue;
144
+ }
152
145
  }
153
146
  });
154
147
  });
@@ -156,7 +149,7 @@ export default class TurnDiscovery {
156
149
  clearTimeout(this.responseTimer);
157
150
  this.responseTimer = undefined;
158
151
 
159
- if (foundHeaders !== expectedHeaders.length) {
152
+ if (expectedHeaders.some((header) => !foundHeaders[header.headerName])) {
160
153
  LoggerProxy.logger.warn(
161
154
  `Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received ${from}: ${JSON.stringify(
162
155
  headers
@@ -169,9 +162,11 @@ export default class TurnDiscovery {
169
162
  );
170
163
  } else {
171
164
  LoggerProxy.logger.info(
172
- `Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response ${from}, url=${this.turnInfo.url}`
165
+ `Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response ${from}, urls=${this.turnInfo.urls}`
173
166
  );
174
167
 
168
+ this.turnInfo.urls = this.turnInfo.urls.filter((url) => url !== ''); // remove empty urls, we might get them if we land on video-mesh nodes (VMN)
169
+
175
170
  this.defer.resolve({isOkRequired: !headers?.includes('noOkInTransaction')});
176
171
  }
177
172
  }
@@ -0,0 +1,23 @@
1
+ import {Enum} from '../constants';
2
+
3
+ export const TurnDiscoverySkipReason = {
4
+ missingHttpResponse: 'missing http response', // when we asked for the TURN discovery response to be in the http response, but it wasn't there
5
+ reachability: 'reachability', // when udp reachability to public clusters is ok, so we don't need TURN (this doens't apply when joinWithMedia() is used)
6
+ alreadyInProgress: 'already in progress', // when we try to start TURN discovery while it's already in progress
7
+ } as const;
8
+
9
+ export type TurnDiscoverySkipReason =
10
+ | Enum<typeof TurnDiscoverySkipReason> // this is a kind of FYI, because in practice typescript will infer the type of TurnDiscoverySkipReason as a string
11
+ | string // used in case of errors, contains the error message
12
+ | undefined; // used when TURN discovery is not skipped
13
+
14
+ export type TurnServerInfo = {
15
+ urls: string[];
16
+ username: string;
17
+ password: string;
18
+ };
19
+
20
+ export type TurnDiscoveryResult = {
21
+ turnServerInfo?: TurnServerInfo;
22
+ turnDiscoverySkippedReason: TurnDiscoverySkipReason;
23
+ };
@@ -114,39 +114,58 @@ describe('plugin-meetings', () => {
114
114
  assert.notCalled(breakoutClosingHandler);
115
115
  breakouts.set(deps);
116
116
  assert.calledOnce(breakoutClosingHandler);
117
- }
118
-
119
- checkIsCalled({sessionType: BREAKOUTS.SESSION_TYPES.MAIN, groups: undefined, status: undefined}, {
120
- sessionType: BREAKOUTS.SESSION_TYPES.MAIN,
121
- groups: [{status: BREAKOUTS.STATUS.CLOSING}],
122
- status: undefined
123
- });
117
+ };
124
118
 
125
- checkIsCalled({sessionType: BREAKOUTS.SESSION_TYPES.MAIN, groups: [{status: BREAKOUTS.STATUS.OPEN}], status: undefined}, {
126
- sessionType: BREAKOUTS.SESSION_TYPES.MAIN,
127
- groups: [{status: BREAKOUTS.STATUS.CLOSING}],
128
- status: undefined
129
- });
119
+ checkIsCalled(
120
+ {sessionType: BREAKOUTS.SESSION_TYPES.MAIN, groups: undefined, status: undefined},
121
+ {
122
+ sessionType: BREAKOUTS.SESSION_TYPES.MAIN,
123
+ groups: [{status: BREAKOUTS.STATUS.CLOSING}],
124
+ status: undefined,
125
+ }
126
+ );
130
127
 
131
- checkIsCalled({sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT, groups: undefined, status: undefined}, {
132
- sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT,
133
- groups: undefined,
134
- status: BREAKOUTS.STATUS.CLOSING
135
- });
128
+ checkIsCalled(
129
+ {
130
+ sessionType: BREAKOUTS.SESSION_TYPES.MAIN,
131
+ groups: [{status: BREAKOUTS.STATUS.OPEN}],
132
+ status: undefined,
133
+ },
134
+ {
135
+ sessionType: BREAKOUTS.SESSION_TYPES.MAIN,
136
+ groups: [{status: BREAKOUTS.STATUS.CLOSING}],
137
+ status: undefined,
138
+ }
139
+ );
136
140
 
137
- checkIsCalled({sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT, groups: undefined, status: BREAKOUTS.STATUS.OPEN}, {
138
- sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT,
139
- groups: undefined,
140
- status: BREAKOUTS.STATUS.CLOSING
141
- });
141
+ checkIsCalled(
142
+ {sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT, groups: undefined, status: undefined},
143
+ {
144
+ sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT,
145
+ groups: undefined,
146
+ status: BREAKOUTS.STATUS.CLOSING,
147
+ }
148
+ );
142
149
 
150
+ checkIsCalled(
151
+ {
152
+ sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT,
153
+ groups: undefined,
154
+ status: BREAKOUTS.STATUS.OPEN,
155
+ },
156
+ {
157
+ sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT,
158
+ groups: undefined,
159
+ status: BREAKOUTS.STATUS.CLOSING,
160
+ }
161
+ );
143
162
  });
144
163
 
145
164
  it('should not emits BREAKOUTS_CLOSING event when just sessionType changed from BREAKOUT to MAIN', () => {
146
165
  breakouts.set({
147
166
  sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT,
148
167
  groups: undefined,
149
- status: BREAKOUTS.STATUS.CLOSING
168
+ status: BREAKOUTS.STATUS.CLOSING,
150
169
  });
151
170
 
152
171
  const breakoutClosingHandler = sinon.stub();
@@ -155,7 +174,7 @@ describe('plugin-meetings', () => {
155
174
  breakouts.set({
156
175
  sessionType: BREAKOUTS.SESSION_TYPES.MAIN,
157
176
  groups: [{status: BREAKOUTS.STATUS.CLOSING}],
158
- status: undefined
177
+ status: undefined,
159
178
  });
160
179
 
161
180
  assert.notCalled(breakoutClosingHandler);
@@ -171,14 +190,22 @@ describe('plugin-meetings', () => {
171
190
  it('call triggerReturnToMainEvent correctly when requested breakout add', () => {
172
191
  breakouts.triggerReturnToMainEvent = sinon.stub();
173
192
  breakouts.breakouts.add({sessionId: 'session1', sessionType: 'MAIN'});
174
- assert.calledOnceWithExactly(breakouts.triggerReturnToMainEvent, breakouts.breakouts.get('session1'));
193
+ assert.calledOnceWithExactly(
194
+ breakouts.triggerReturnToMainEvent,
195
+ breakouts.breakouts.get('session1')
196
+ );
175
197
  });
176
198
 
177
199
  it('call triggerReturnToMainEvent correctly when breakout requestedLastModifiedTime change', () => {
178
200
  breakouts.breakouts.add({sessionId: 'session1', sessionType: 'MAIN'});
179
201
  breakouts.triggerReturnToMainEvent = sinon.stub();
180
- breakouts.breakouts.get('session1').set({requestedLastModifiedTime: "2023-05-09T17:16:01.000Z"});
181
- assert.calledOnceWithExactly(breakouts.triggerReturnToMainEvent, breakouts.breakouts.get('session1'));
202
+ breakouts.breakouts
203
+ .get('session1')
204
+ .set({requestedLastModifiedTime: '2023-05-09T17:16:01.000Z'});
205
+ assert.calledOnceWithExactly(
206
+ breakouts.triggerReturnToMainEvent,
207
+ breakouts.breakouts.get('session1')
208
+ );
182
209
  });
183
210
 
184
211
  it('call queryPreAssignments correctly when should query preAssignments is true', () => {
@@ -195,7 +222,7 @@ describe('plugin-meetings', () => {
195
222
  describe('#listenToCurrentSessionTypeChange', () => {
196
223
  it('triggers leave breakout event when sessionType changed from SESSION to MAIN', () => {
197
224
  const handler = sinon.stub();
198
- breakouts.currentBreakoutSession.set({sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT})
225
+ breakouts.currentBreakoutSession.set({sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT});
199
226
  breakouts.listenTo(breakouts, BREAKOUTS.EVENTS.LEAVE_BREAKOUT, handler);
200
227
  breakouts.currentBreakoutSession.set({sessionType: BREAKOUTS.SESSION_TYPES.MAIN});
201
228
 
@@ -206,7 +233,7 @@ describe('plugin-meetings', () => {
206
233
 
207
234
  it('should not triggers leave breakout event when sessionType changed from undefined to MAIN', () => {
208
235
  const handler = sinon.stub();
209
- breakouts.currentBreakoutSession.set({sessionType: undefined})
236
+ breakouts.currentBreakoutSession.set({sessionType: undefined});
210
237
  breakouts.listenTo(breakouts, BREAKOUTS.EVENTS.LEAVE_BREAKOUT, handler);
211
238
  breakouts.currentBreakoutSession.set({sessionType: BREAKOUTS.SESSION_TYPES.MAIN});
212
239
 
@@ -217,7 +244,7 @@ describe('plugin-meetings', () => {
217
244
 
218
245
  it('should not triggers leave breakout event when sessionType changed from MAIN to SESSION', () => {
219
246
  const handler = sinon.stub();
220
- breakouts.currentBreakoutSession.set({sessionType: BREAKOUTS.SESSION_TYPES.MAIN})
247
+ breakouts.currentBreakoutSession.set({sessionType: BREAKOUTS.SESSION_TYPES.MAIN});
221
248
  breakouts.listenTo(breakouts, BREAKOUTS.EVENTS.LEAVE_BREAKOUT, handler);
222
249
  breakouts.currentBreakoutSession.set({sessionType: BREAKOUTS.SESSION_TYPES.BREAKOUT});
223
250
 
@@ -268,7 +295,7 @@ describe('plugin-meetings', () => {
268
295
  callback({
269
296
  data: {
270
297
  participant: 'participant',
271
- sessionId: 'sessionId'
298
+ sessionId: 'sessionId',
272
299
  },
273
300
  });
274
301
 
@@ -321,38 +348,38 @@ describe('plugin-meetings', () => {
321
348
 
322
349
  it('update the startTime correctly when no attribute startTime exists on params', () => {
323
350
  breakouts.updateBreakout({
324
- startTime: "startTime"
325
- })
351
+ startTime: 'startTime',
352
+ });
326
353
  assert.equal(breakouts.startTime, 'startTime');
327
354
 
328
- breakouts.updateBreakout({})
355
+ breakouts.updateBreakout({});
329
356
  assert.equal(breakouts.startTime, undefined);
330
357
  });
331
358
 
332
359
  it('update the status correctly when no attribute status exists on params', () => {
333
360
  breakouts.updateBreakout({
334
- status: 'CLOSING'
335
- })
361
+ status: 'CLOSING',
362
+ });
336
363
  assert.equal(breakouts.status, 'CLOSING');
337
364
 
338
- breakouts.updateBreakout({})
365
+ breakouts.updateBreakout({});
339
366
  assert.equal(breakouts.status, undefined);
340
367
  });
341
368
 
342
369
  it('call clearBreakouts if current breakout is not in-progress', () => {
343
370
  breakouts.clearBreakouts = sinon.stub();
344
- breakouts.updateBreakout({status: 'CLOSED'})
371
+ breakouts.updateBreakout({status: 'CLOSED'});
345
372
  assert.calledOnce(breakouts.clearBreakouts);
346
373
  });
347
374
 
348
375
  it('updates the current breakout session, call onBreakoutJoinResponse when session changed', () => {
349
376
  breakouts.webex.meetings = {
350
377
  getMeetingByType: sinon.stub().returns({
351
- id: 'meeting-id'
352
- })
378
+ id: 'meeting-id',
379
+ }),
353
380
  };
354
- const onBreakoutJoinResponseSpy = sinon.stub(breakoutEvent,'onBreakoutJoinResponse')
355
- breakouts.currentBreakoutSession.sessionId = "sessionId-old";
381
+ const onBreakoutJoinResponseSpy = sinon.stub(breakoutEvent, 'onBreakoutJoinResponse');
382
+ breakouts.currentBreakoutSession.sessionId = 'sessionId-old';
356
383
  breakouts.updateBreakout({
357
384
  sessionId: 'sessionId-new',
358
385
  groupId: 'groupId',
@@ -370,19 +397,18 @@ describe('plugin-meetings', () => {
370
397
 
371
398
  assert.calledOnce(onBreakoutJoinResponseSpy);
372
399
 
373
- onBreakoutJoinResponseSpy.restore()
374
-
400
+ onBreakoutJoinResponseSpy.restore();
375
401
  });
376
402
 
377
403
  it('updates the current breakout session, not call onBreakoutJoinResponse when session no changed', () => {
378
404
  breakouts.webex.meetings = {
379
405
  getMeetingByType: sinon.stub().returns({
380
- id: 'meeting-id'
381
- })
406
+ id: 'meeting-id',
407
+ }),
382
408
  };
383
409
  const onBreakoutJoinResponseSpy = sinon.stub(breakoutEvent, 'onBreakoutJoinResponse');
384
- breakouts.currentBreakoutSession.sessionId = "sessionId";
385
- breakouts.currentBreakoutSession.groupId = "groupId";
410
+ breakouts.currentBreakoutSession.sessionId = 'sessionId';
411
+ breakouts.currentBreakoutSession.groupId = 'groupId';
386
412
  breakouts.updateBreakout({
387
413
  sessionId: 'sessionId',
388
414
  groupId: 'groupId',
@@ -399,8 +425,7 @@ describe('plugin-meetings', () => {
399
425
  });
400
426
 
401
427
  assert.notCalled(onBreakoutJoinResponseSpy);
402
- onBreakoutJoinResponseSpy.restore()
403
-
428
+ onBreakoutJoinResponseSpy.restore();
404
429
  });
405
430
  });
406
431
 
@@ -446,13 +471,16 @@ describe('plugin-meetings', () => {
446
471
  const payload = {
447
472
  breakoutSessions: {
448
473
  assigned: [{sessionId: 'sessionId1'}],
449
- requested: [{sessionId: 'sessionId2', modifiedAt: "2023-05-09T17:16:01.000Z"}],
474
+ requested: [{sessionId: 'sessionId2', modifiedAt: '2023-05-09T17:16:01.000Z'}],
450
475
  },
451
476
  };
452
477
 
453
478
  breakouts.updateBreakoutSessions(payload);
454
- assert.equal(breakouts.breakouts.get('sessionId1').requestedLastModifiedTime, undefined)
455
- assert.equal(breakouts.breakouts.get('sessionId2').requestedLastModifiedTime, "2023-05-09T17:16:01.000Z")
479
+ assert.equal(breakouts.breakouts.get('sessionId1').requestedLastModifiedTime, undefined);
480
+ assert.equal(
481
+ breakouts.breakouts.get('sessionId2').requestedLastModifiedTime,
482
+ '2023-05-09T17:16:01.000Z'
483
+ );
456
484
  });
457
485
 
458
486
  it('not update breakout sessions when breakouts is closing', () => {
@@ -603,15 +631,15 @@ describe('plugin-meetings', () => {
603
631
 
604
632
  describe('#breakoutStatus', () => {
605
633
  it('return status from groups with session type', () => {
606
- breakouts.set('groups', [{status: "OPEN"}]);
607
- breakouts.set('status', "CLOSED");
634
+ breakouts.set('groups', [{status: 'OPEN'}]);
635
+ breakouts.set('status', 'CLOSED');
608
636
  breakouts.set('sessionType', BREAKOUTS.SESSION_TYPES.MAIN);
609
637
 
610
- assert.equal(breakouts.breakoutStatus, "OPEN")
638
+ assert.equal(breakouts.breakoutStatus, 'OPEN');
611
639
 
612
640
  breakouts.set('sessionType', BREAKOUTS.SESSION_TYPES.BREAKOUT);
613
641
 
614
- assert.equal(breakouts.breakoutStatus, "CLOSED")
642
+ assert.equal(breakouts.breakoutStatus, 'CLOSED');
615
643
  });
616
644
  });
617
645
 
@@ -634,7 +662,7 @@ describe('plugin-meetings', () => {
634
662
  it('return breakout is in progress depends on the status(groups/breakouts)', () => {
635
663
  breakouts.set('groups', [{status: 'CLOSING'}]);
636
664
 
637
- assert.equal(breakouts.isBreakoutInProgress(), true)
665
+ assert.equal(breakouts.isBreakoutInProgress(), true);
638
666
 
639
667
  breakouts.set('groups', undefined);
640
668
  breakouts.set('status', 'OPEN');
@@ -1107,7 +1135,7 @@ describe('plugin-meetings', () => {
1107
1135
  someOtherParam: 'someOtherParam',
1108
1136
  });
1109
1137
  assert.deepEqual(result, {body: mockedReturnBody});
1110
- assert.calledWithExactly(breakouts._setManageGroups, {body: mockedReturnBody})
1138
+ assert.calledWithExactly(breakouts._setManageGroups, {body: mockedReturnBody});
1111
1139
  });
1112
1140
 
1113
1141
  it('rejects when edit lock token mismatch', async () => {
@@ -1668,29 +1696,29 @@ describe('plugin-meetings', () => {
1668
1696
  describe('#queryPreAssignments', () => {
1669
1697
  it('makes the expected query', async () => {
1670
1698
  const mockPreAssignments = [
1671
- {
1672
- sessions: [
1673
- {
1674
- name: 'Breakout session 1',
1675
- assignedEmails: ['aa@aa.com', 'bb@bb.com', 'cc@cc.com'],
1676
- anyoneCanJoin: false,
1677
- },
1678
- {
1679
- name: 'Breakout session 2',
1680
- anyoneCanJoin: false,
1681
- },
1682
- {
1683
- name: 'Breakout session 3',
1684
- assignedEmails: ['cc@cc.com'],
1685
- anyoneCanJoin: false,
1686
- },
1687
- ],
1688
- unassignedInvitees: {
1689
- emails: ['dd@dd.com'],
1699
+ {
1700
+ sessions: [
1701
+ {
1702
+ name: 'Breakout session 1',
1703
+ assignedEmails: ['aa@aa.com', 'bb@bb.com', 'cc@cc.com'],
1704
+ anyoneCanJoin: false,
1690
1705
  },
1691
- type: 'BREAKOUT',
1706
+ {
1707
+ name: 'Breakout session 2',
1708
+ anyoneCanJoin: false,
1709
+ },
1710
+ {
1711
+ name: 'Breakout session 3',
1712
+ assignedEmails: ['cc@cc.com'],
1713
+ anyoneCanJoin: false,
1714
+ },
1715
+ ],
1716
+ unassignedInvitees: {
1717
+ emails: ['dd@dd.com'],
1692
1718
  },
1693
- ];
1719
+ type: 'BREAKOUT',
1720
+ },
1721
+ ];
1694
1722
  webex.request.returns(
1695
1723
  Promise.resolve({
1696
1724
  body: {
@@ -1705,7 +1733,7 @@ describe('plugin-meetings', () => {
1705
1733
  uri: 'url/preassignments',
1706
1734
  qs: {
1707
1735
  locusUrl: 'dGVzdA==',
1708
- }
1736
+ },
1709
1737
  });
1710
1738
 
1711
1739
  assert.deepEqual(breakouts.preAssignments, mockPreAssignments);
@@ -1721,7 +1749,10 @@ describe('plugin-meetings', () => {
1721
1749
  };
1722
1750
  webex.request.rejects(response);
1723
1751
  LoggerProxy.logger.error = sinon.stub();
1724
- const result = await breakouts.queryPreAssignments({enableBreakoutSession: true, hasBreakoutPreAssignments: true});
1752
+ const result = await breakouts.queryPreAssignments({
1753
+ enableBreakoutSession: true,
1754
+ hasBreakoutPreAssignments: true,
1755
+ });
1725
1756
  await testUtils.flushPromises();
1726
1757
  assert.calledOnceWithExactly(
1727
1758
  LoggerProxy.logger.error,
@@ -1730,20 +1761,35 @@ describe('plugin-meetings', () => {
1730
1761
  );
1731
1762
  });
1732
1763
 
1733
- it('fail when no correct params', () => {
1734
-
1764
+ it('fail when no correct params', () => {
1735
1765
  assert.deepEqual(breakouts.queryPreAssignments(undefined), undefined);
1736
1766
 
1737
1767
  assert.deepEqual(breakouts.queryPreAssignments({}), undefined);
1738
1768
 
1739
- assert.deepEqual(breakouts.queryPreAssignments({ enableBreakoutSession: true, hasBreakoutPreAssignments: false }), undefined);
1740
-
1741
- assert.deepEqual(breakouts.queryPreAssignments({ enableBreakoutSession: false, hasBreakoutPreAssignments: true }), undefined);
1769
+ assert.deepEqual(
1770
+ breakouts.queryPreAssignments({
1771
+ enableBreakoutSession: true,
1772
+ hasBreakoutPreAssignments: false,
1773
+ }),
1774
+ undefined
1775
+ );
1742
1776
 
1743
- assert.deepEqual(breakouts.queryPreAssignments({ enableBreakoutSession: false, hasBreakoutPreAssignments: false }), undefined);
1777
+ assert.deepEqual(
1778
+ breakouts.queryPreAssignments({
1779
+ enableBreakoutSession: false,
1780
+ hasBreakoutPreAssignments: true,
1781
+ }),
1782
+ undefined
1783
+ );
1744
1784
 
1785
+ assert.deepEqual(
1786
+ breakouts.queryPreAssignments({
1787
+ enableBreakoutSession: false,
1788
+ hasBreakoutPreAssignments: false,
1789
+ }),
1790
+ undefined
1791
+ );
1745
1792
  });
1746
-
1747
1793
  });
1748
1794
 
1749
1795
  describe('#dynamicAssign', () => {
@@ -1775,6 +1821,32 @@ describe('plugin-meetings', () => {
1775
1821
  });
1776
1822
  });
1777
1823
 
1824
+ describe('#moveToLobby', () => {
1825
+ it('should make a PUT request with correct body and return the result', async () => {
1826
+ breakouts.moveToLobby = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
1827
+
1828
+ const expectedBody = {
1829
+ groups: [
1830
+ {
1831
+ id: 'mainGroupId',
1832
+ sessions: [
1833
+ {
1834
+ id: 'mainSessionId',
1835
+ participants: ['participant1'],
1836
+ targetState: 'LOBBY',
1837
+ },
1838
+ ],
1839
+ },
1840
+ ],
1841
+ };
1842
+
1843
+ const result = await breakouts.moveToLobby(expectedBody);
1844
+
1845
+ assert.calledOnceWithExactly(breakouts.moveToLobby, expectedBody);
1846
+ assert.equal(result, 'REQUEST_RETURN_VALUE');
1847
+ });
1848
+ });
1849
+
1778
1850
  describe('#triggerReturnToMainEvent', () => {
1779
1851
  const checkTrigger = ({breakout, shouldTrigger}) => {
1780
1852
  breakouts.trigger = sinon.stub();
@@ -1784,19 +1856,19 @@ describe('plugin-meetings', () => {
1784
1856
  } else {
1785
1857
  assert.notCalled(breakouts.trigger);
1786
1858
  }
1787
- }
1859
+ };
1788
1860
  it('should trigger ASK_RETURN_TO_MAIN event correctly', () => {
1789
1861
  const breakout = {
1790
1862
  isMain: true,
1791
- requested: true
1863
+ requested: true,
1792
1864
  };
1793
- checkTrigger({breakout, shouldTrigger: true})
1865
+ checkTrigger({breakout, shouldTrigger: true});
1794
1866
  });
1795
1867
 
1796
1868
  it('should not trigger ASK_RETURN_TO_MAIN event when sessionType is not MAIN', () => {
1797
1869
  const breakout = {
1798
1870
  isMain: false,
1799
- requested: true
1871
+ requested: true,
1800
1872
  };
1801
1873
  checkTrigger({breakout, shouldTrigger: false});
1802
1874
  });
@@ -1804,9 +1876,9 @@ describe('plugin-meetings', () => {
1804
1876
  it('should not trigger ASK_RETURN_TO_MAIN event when session is not requested', () => {
1805
1877
  const breakout = {
1806
1878
  isMain: true,
1807
- requested: false
1879
+ requested: false,
1808
1880
  };
1809
- checkTrigger({breakout, shouldTrigger: false})
1881
+ checkTrigger({breakout, shouldTrigger: false});
1810
1882
  });
1811
1883
  });
1812
1884
  });