@webex/plugin-meetings 3.6.0-next.2 → 3.6.0-next.4

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 (34) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/webinar-registration-error.js +50 -0
  4. package/dist/common/errors/webinar-registration-error.js.map +1 -0
  5. package/dist/constants.js +7 -0
  6. package/dist/constants.js.map +1 -1
  7. package/dist/index.js +7 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/interpretation/index.js +1 -1
  10. package/dist/interpretation/siLanguage.js +1 -1
  11. package/dist/meeting/index.js +73 -37
  12. package/dist/meeting/index.js.map +1 -1
  13. package/dist/meeting-info/meeting-info-v2.js +68 -17
  14. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  15. package/dist/meetings/index.js +2 -1
  16. package/dist/meetings/index.js.map +1 -1
  17. package/dist/metrics/constants.js +2 -1
  18. package/dist/metrics/constants.js.map +1 -1
  19. package/dist/types/common/errors/webinar-registration-error.d.ts +14 -0
  20. package/dist/types/constants.d.ts +6 -0
  21. package/dist/types/index.d.ts +2 -1
  22. package/dist/types/meeting-info/meeting-info-v2.d.ts +23 -0
  23. package/dist/types/metrics/constants.d.ts +1 -0
  24. package/dist/webinar/index.js +1 -1
  25. package/package.json +3 -3
  26. package/src/common/errors/webinar-registration-error.ts +27 -0
  27. package/src/constants.ts +6 -0
  28. package/src/index.ts +2 -0
  29. package/src/meeting/index.ts +24 -10
  30. package/src/meeting-info/meeting-info-v2.ts +51 -0
  31. package/src/meetings/index.ts +3 -1
  32. package/src/metrics/constants.ts +1 -0
  33. package/test/unit/spec/meeting/index.js +23 -1
  34. package/test/unit/spec/meeting-info/meetinginfov2.js +37 -0
@@ -406,6 +406,11 @@ export declare const ERROR_DICTIONARY: {
406
406
  MESSAGE: string;
407
407
  CODE: number;
408
408
  };
409
+ WebinarRegistrationError: {
410
+ NAME: string;
411
+ MESSAGE: string;
412
+ CODE: number;
413
+ };
409
414
  };
410
415
  export declare const FLOOR_ACTION: {
411
416
  GRANTED: string;
@@ -1058,6 +1063,7 @@ export declare const MEETING_INFO_FAILURE_REASON: {
1058
1063
  WRONG_PASSWORD: string;
1059
1064
  WRONG_CAPTCHA: string;
1060
1065
  POLICY: string;
1066
+ WEBINAR_REGISTRATION: string;
1061
1067
  OTHER: string;
1062
1068
  };
1063
1069
  export declare const BNR_STATUS: {
@@ -3,6 +3,7 @@ import CaptchaError from './common/errors/captcha-error';
3
3
  import IntentToJoinError from './common/errors/intent-to-join';
4
4
  import PasswordError from './common/errors/password-error';
5
5
  import PermissionError from './common/errors/permission';
6
+ import WebinarRegistrationError from './common/errors/webinar-registration-error';
6
7
  import { ReclaimHostEmptyWrongKeyError, ReclaimHostIsHostAlreadyError, ReclaimHostNotAllowedError, ReclaimHostNotSupportedError } from './common/errors/reclaim-host-role-errors';
7
8
  import Meeting from './meeting';
8
9
  import MeetingInfoUtil from './meeting-info/utilv2';
@@ -14,6 +15,6 @@ export * as REACTIONS from './reactions/reactions';
14
15
  export * as sdkAnnotationTypes from './annotation/annotation.types';
15
16
  export * as MeetingInfoV2 from './meeting-info/meeting-info-v2';
16
17
  export { type Reaction } from './reactions/reactions.type';
17
- export { CaptchaError, IntentToJoinError, JoinMeetingError, PasswordError, PermissionError, ReclaimHostIsHostAlreadyError, ReclaimHostNotAllowedError, ReclaimHostNotSupportedError, ReclaimHostEmptyWrongKeyError, Meeting, MeetingInfoUtil, };
18
+ export { CaptchaError, IntentToJoinError, JoinMeetingError, PasswordError, PermissionError, ReclaimHostIsHostAlreadyError, ReclaimHostNotAllowedError, ReclaimHostNotSupportedError, ReclaimHostEmptyWrongKeyError, Meeting, MeetingInfoUtil, WebinarRegistrationError, };
18
19
  export { RemoteMedia } from './multistream/remoteMedia';
19
20
  export { default as TriggerProxy } from './common/events/trigger-proxy';
@@ -64,6 +64,23 @@ export declare class MeetingInfoV2CaptchaError extends Error {
64
64
  */
65
65
  constructor(wbxAppApiErrorCode?: number, captchaInfo?: object, message?: string);
66
66
  }
67
+ /**
68
+ * Error preventing join because of a webinar registration error
69
+ */
70
+ export declare class MeetingInfoV2WebinarRegistrationError extends Error {
71
+ meetingInfo: any;
72
+ sdkMessage: any;
73
+ wbxAppApiCode: any;
74
+ body: any;
75
+ /**
76
+ *
77
+ * @constructor
78
+ * @param {Number} [wbxAppApiErrorCode]
79
+ * @param {Object} [meetingInfo]
80
+ * @param {String} [message]
81
+ */
82
+ constructor(wbxAppApiErrorCode?: number, meetingInfo?: object, message?: string);
83
+ }
67
84
  /**
68
85
  * @class MeetingInfo
69
86
  */
@@ -89,6 +106,12 @@ export default class MeetingInfoV2 {
89
106
  * @returns {void}
90
107
  */
91
108
  handlePolicyError: (err: any) => void;
109
+ /**
110
+ * Raises a handleWebinarRegistrationError for webinar registration error codes
111
+ * @param {any} err the error from the request
112
+ * @returns {void}
113
+ */
114
+ handleWebinarRegistrationError: (err: any) => void;
92
115
  /**
93
116
  * Creates adhoc space meetings for a space by fetching the conversation infomation
94
117
  * @param {String} conversationUrl conversationUrl to start adhoc meeting on
@@ -67,5 +67,6 @@ declare const BEHAVIORAL_METRICS: {
67
67
  ROAP_HTTP_RESPONSE_MISSING: string;
68
68
  TURN_DISCOVERY_REQUIRES_OK: string;
69
69
  REACHABILITY_COMPLETED: string;
70
+ WEBINAR_REGISTRATION_ERROR: string;
70
71
  };
71
72
  export { BEHAVIORAL_METRICS as default };
@@ -62,7 +62,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
62
62
  updateCanManageWebcast: function updateCanManageWebcast(canManageWebcast) {
63
63
  this.set('canManageWebcast', canManageWebcast);
64
64
  },
65
- version: "3.6.0-next.2"
65
+ version: "3.6.0-next.4"
66
66
  });
67
67
  var _default = exports.default = Webinar;
68
68
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -43,7 +43,7 @@
43
43
  "@webex/eslint-config-legacy": "0.0.0",
44
44
  "@webex/jest-config-legacy": "0.0.0",
45
45
  "@webex/legacy-tools": "0.0.0",
46
- "@webex/plugin-meetings": "3.6.0-next.2",
46
+ "@webex/plugin-meetings": "3.6.0-next.4",
47
47
  "@webex/plugin-rooms": "3.5.0-next.23",
48
48
  "@webex/test-helper-chai": "3.5.0-next.21",
49
49
  "@webex/test-helper-mocha": "3.5.0-next.21",
@@ -70,7 +70,7 @@
70
70
  "@webex/internal-plugin-metrics": "3.5.0-next.21",
71
71
  "@webex/internal-plugin-support": "3.5.0-next.23",
72
72
  "@webex/internal-plugin-user": "3.5.0-next.21",
73
- "@webex/internal-plugin-voicea": "3.6.0-next.2",
73
+ "@webex/internal-plugin-voicea": "3.6.0-next.4",
74
74
  "@webex/media-helpers": "3.5.0-next.22",
75
75
  "@webex/plugin-people": "3.5.0-next.21",
76
76
  "@webex/plugin-rooms": "3.5.0-next.23",
@@ -91,5 +91,5 @@
91
91
  "//": [
92
92
  "TODO: upgrade jwt-decode when moving to node 18"
93
93
  ],
94
- "version": "3.6.0-next.2"
94
+ "version": "3.6.0-next.4"
95
95
  }
@@ -0,0 +1,27 @@
1
+ import {ERROR_DICTIONARY} from '../../constants';
2
+
3
+ /**
4
+ * Error occurred while the webinar required registration
5
+ */
6
+ export default class WebinarRegistrationError extends Error {
7
+ code: number;
8
+ error: any;
9
+ sdkMessage: string;
10
+
11
+ /**
12
+ * @constructor
13
+ * @param {String} [message]
14
+ * @param {Object} [error]
15
+ */
16
+ constructor(
17
+ message: string = ERROR_DICTIONARY.WebinarRegistrationError.MESSAGE,
18
+ error: any = null
19
+ ) {
20
+ super(message);
21
+ this.name = ERROR_DICTIONARY.WebinarRegistrationError.NAME;
22
+ this.sdkMessage = ERROR_DICTIONARY.WebinarRegistrationError.MESSAGE;
23
+ this.error = error;
24
+ this.stack = error ? error.stack : new Error().stack;
25
+ this.code = ERROR_DICTIONARY.WebinarRegistrationError.CODE;
26
+ }
27
+ }
package/src/constants.ts CHANGED
@@ -524,6 +524,11 @@ export const ERROR_DICTIONARY = {
524
524
  'Reconnection was not started, because there is one already in progress or reconnections are disabled in config.',
525
525
  CODE: 15,
526
526
  },
527
+ WebinarRegistrationError: {
528
+ NAME: 'WebinarRegistrationError',
529
+ MESSAGE: 'An error occurred while the webinar required registration.',
530
+ CODE: 16,
531
+ },
527
532
  };
528
533
 
529
534
  export const FLOOR_ACTION = {
@@ -1269,6 +1274,7 @@ export const MEETING_INFO_FAILURE_REASON = {
1269
1274
  WRONG_PASSWORD: 'WRONG_PASSWORD', // meeting requires password and no password or wrong one was provided
1270
1275
  WRONG_CAPTCHA: 'WRONG_CAPTCHA', // wbxappapi requires a captcha code or a wrong captcha code was provided
1271
1276
  POLICY: 'POLICY', // meeting info request violates some meeting policy
1277
+ WEBINAR_REGISTRATION: 'WEBINAR_REGISTRATION', // webinar need registration
1272
1278
  OTHER: 'OTHER', // any other error (network, etc)
1273
1279
  };
1274
1280
 
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import CaptchaError from './common/errors/captcha-error';
8
8
  import IntentToJoinError from './common/errors/intent-to-join';
9
9
  import PasswordError from './common/errors/password-error';
10
10
  import PermissionError from './common/errors/permission';
11
+ import WebinarRegistrationError from './common/errors/webinar-registration-error';
11
12
  import {
12
13
  ReclaimHostEmptyWrongKeyError,
13
14
  ReclaimHostIsHostAlreadyError,
@@ -68,6 +69,7 @@ export {
68
69
  ReclaimHostEmptyWrongKeyError,
69
70
  Meeting,
70
71
  MeetingInfoUtil,
72
+ WebinarRegistrationError,
71
73
  };
72
74
 
73
75
  export {RemoteMedia} from './multistream/remoteMedia';
@@ -128,6 +128,7 @@ import {
128
128
  MeetingInfoV2PasswordError,
129
129
  MeetingInfoV2CaptchaError,
130
130
  MeetingInfoV2PolicyError,
131
+ MeetingInfoV2WebinarRegistrationError,
131
132
  } from '../meeting-info/meeting-info-v2';
132
133
  import {CSI, ReceiveSlotManager} from '../multistream/receiveSlotManager';
133
134
  import SendSlotManager from '../multistream/sendSlotManager';
@@ -156,6 +157,7 @@ import ControlsOptionsManager from '../controls-options-manager';
156
157
  import PermissionError from '../common/errors/permission';
157
158
  import {LocusMediaRequest} from './locusMediaRequest';
158
159
  import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHandler';
160
+ import WebinarRegistrationError from '../common/errors/webinar-registration-error';
159
161
 
160
162
  // default callback so we don't call an undefined function, but in practice it should never be used
161
163
  const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
@@ -1759,8 +1761,16 @@ export default class Meeting extends StatelessWebexPlugin {
1759
1761
  if (err.meetingInfo) {
1760
1762
  this.meetingInfo = err.meetingInfo;
1761
1763
  }
1762
-
1763
1764
  throw new PermissionError();
1765
+ } else if (err instanceof MeetingInfoV2WebinarRegistrationError) {
1766
+ this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WEBINAR_REGISTRATION;
1767
+ this.meetingInfoFailureCode = err.wbxAppApiCode;
1768
+
1769
+ if (err.meetingInfo) {
1770
+ this.meetingInfo = err.meetingInfo;
1771
+ }
1772
+
1773
+ throw new WebinarRegistrationError();
1764
1774
  } else if (err instanceof MeetingInfoV2PasswordError) {
1765
1775
  LoggerProxy.logger.info(
1766
1776
  // @ts-ignore
@@ -8735,15 +8745,19 @@ export default class Meeting extends StatelessWebexPlugin {
8735
8745
  return;
8736
8746
  }
8737
8747
 
8738
- if (
8739
- streams?.microphone?.readyState === 'ended' ||
8740
- streams?.camera?.readyState === 'ended' ||
8741
- streams?.screenShare?.audio?.readyState === 'ended' ||
8742
- streams?.screenShare?.video?.readyState === 'ended'
8743
- ) {
8744
- throw new Error(
8745
- `Attempted to publish stream with ended readyState, correlationId=${this.correlationId}`
8746
- );
8748
+ const streamChecks = [
8749
+ {stream: streams?.microphone, name: 'microphone'},
8750
+ {stream: streams?.camera, name: 'camera'},
8751
+ {stream: streams?.screenShare?.audio, name: 'screenShare audio'},
8752
+ {stream: streams?.screenShare?.video, name: 'screenShare video'},
8753
+ ];
8754
+
8755
+ for (const {stream, name} of streamChecks) {
8756
+ if (stream?.readyState === 'ended') {
8757
+ throw new Error(
8758
+ `Attempted to publish ${name} stream with ended readyState, correlationId=${this.correlationId}`
8759
+ );
8760
+ }
8747
8761
  }
8748
8762
 
8749
8763
  let floorRequestNeeded = false;
@@ -18,6 +18,7 @@ const ADHOC_MEETING_DEFAULT_ERROR =
18
18
  'Failed starting the adhoc meeting, Please contact support team ';
19
19
  const CAPTCHA_ERROR_REQUIRES_PASSWORD_CODES = [423005, 423006];
20
20
  const POLICY_ERROR_CODES = [403049, 403104, 403103, 403048, 403102, 403101];
21
+ const WEBINAR_REGISTRATION_ERROR_CODES = [403021, 403022, 403024];
21
22
  /**
22
23
  * Error to indicate that wbxappapi requires a password
23
24
  */
@@ -124,6 +125,31 @@ export class MeetingInfoV2CaptchaError extends Error {
124
125
  }
125
126
  }
126
127
 
128
+ /**
129
+ * Error preventing join because of a webinar registration error
130
+ */
131
+ export class MeetingInfoV2WebinarRegistrationError extends Error {
132
+ meetingInfo: any;
133
+ sdkMessage: any;
134
+ wbxAppApiCode: any;
135
+ body: any;
136
+ /**
137
+ *
138
+ * @constructor
139
+ * @param {Number} [wbxAppApiErrorCode]
140
+ * @param {Object} [meetingInfo]
141
+ * @param {String} [message]
142
+ */
143
+ constructor(wbxAppApiErrorCode?: number, meetingInfo?: object, message?: string) {
144
+ super(`${message}, code=${wbxAppApiErrorCode}`);
145
+ this.name = 'MeetingInfoV2WebinarRegistrationError';
146
+ this.sdkMessage = message;
147
+ this.stack = new Error().stack;
148
+ this.wbxAppApiCode = wbxAppApiErrorCode;
149
+ this.meetingInfo = meetingInfo;
150
+ }
151
+ }
152
+
127
153
  /**
128
154
  * @class MeetingInfo
129
155
  */
@@ -177,6 +203,29 @@ export default class MeetingInfoV2 {
177
203
  }
178
204
  };
179
205
 
206
+ /**
207
+ * Raises a handleWebinarRegistrationError for webinar registration error codes
208
+ * @param {any} err the error from the request
209
+ * @returns {void}
210
+ */
211
+ handleWebinarRegistrationError = (err) => {
212
+ if (!err.body) {
213
+ return;
214
+ }
215
+
216
+ if (WEBINAR_REGISTRATION_ERROR_CODES.includes(err.body?.code)) {
217
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.WEBINAR_REGISTRATION_ERROR, {
218
+ code: err.body?.code,
219
+ });
220
+
221
+ throw new MeetingInfoV2WebinarRegistrationError(
222
+ err.body?.code,
223
+ err.body?.data?.meetingInfo,
224
+ err.body?.message
225
+ );
226
+ }
227
+ };
228
+
180
229
  /**
181
230
  * Creates adhoc space meetings for a space by fetching the conversation infomation
182
231
  * @param {String} conversationUrl conversationUrl to start adhoc meeting on
@@ -237,6 +286,7 @@ export default class MeetingInfoV2 {
237
286
  })
238
287
  .catch((err) => {
239
288
  this.handlePolicyError(err);
289
+ this.handleWebinarRegistrationError(err);
240
290
 
241
291
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADHOC_MEETING_FAILURE, {
242
292
  reason: err.message,
@@ -391,6 +441,7 @@ export default class MeetingInfoV2 {
391
441
 
392
442
  if (err?.statusCode === 403) {
393
443
  this.handlePolicyError(err);
444
+ this.handleWebinarRegistrationError(err);
394
445
 
395
446
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.VERIFY_PASSWORD_ERROR, {
396
447
  reason: err.message,
@@ -56,6 +56,7 @@ import MeetingCollection from './collection';
56
56
  import {MEETING_KEY, INoiseReductionEffect, IVirtualBackgroundEffect} from './meetings.types';
57
57
  import MeetingsUtil from './util';
58
58
  import PermissionError from '../common/errors/permission';
59
+ import WebinarRegistrationError from '../common/errors/webinar-registration-error';
59
60
  import {SpaceIDDeprecatedError} from '../common/errors/webex-errors';
60
61
  import NoMeetingInfoError from '../common/errors/no-meeting-info';
61
62
 
@@ -1397,7 +1398,8 @@ export default class Meetings extends WebexPlugin {
1397
1398
  if (
1398
1399
  !(err instanceof CaptchaError) &&
1399
1400
  !(err instanceof PasswordError) &&
1400
- !(err instanceof PermissionError)
1401
+ !(err instanceof PermissionError) &&
1402
+ !(err instanceof WebinarRegistrationError)
1401
1403
  ) {
1402
1404
  LoggerProxy.logger.info(
1403
1405
  `Meetings:index#createMeeting --> Info Unable to fetch meeting info for ${destination}.`
@@ -70,6 +70,7 @@ const BEHAVIORAL_METRICS = {
70
70
  ROAP_HTTP_RESPONSE_MISSING: 'js_sdk_roap_http_response_missing',
71
71
  TURN_DISCOVERY_REQUIRES_OK: 'js_sdk_turn_discovery_requires_ok',
72
72
  REACHABILITY_COMPLETED: 'js_sdk_reachability_completed',
73
+ WEBINAR_REGISTRATION_ERROR: 'js_sdk_webinar_registration_error',
73
74
  };
74
75
 
75
76
  export {BEHAVIORAL_METRICS as default};
@@ -90,13 +90,15 @@ import WebExMeetingsErrors from '../../../../src/common/errors/webex-meetings-er
90
90
  import ParameterError from '../../../../src/common/errors/parameter';
91
91
  import PasswordError from '../../../../src/common/errors/password-error';
92
92
  import CaptchaError from '../../../../src/common/errors/captcha-error';
93
- import PermissionError from '../../../../src/common/errors/permission';
93
+ import PermissionError from '../../../../src/common/errors/permission';
94
+ import WebinarRegistrationError from '../../../../src/common/errors/webinar-registration-error';
94
95
  import IntentToJoinError from '../../../../src/common/errors/intent-to-join';
95
96
  import testUtils from '../../../utils/testUtils';
96
97
  import {
97
98
  MeetingInfoV2CaptchaError,
98
99
  MeetingInfoV2PasswordError,
99
100
  MeetingInfoV2PolicyError,
101
+ MeetingInfoV2WebinarRegistrationError,
100
102
  } from '../../../../src/meeting-info/meeting-info-v2';
101
103
  import {
102
104
  DTLS_HANDSHAKE_FAILED_CLIENT_CODE,
@@ -3991,6 +3993,7 @@ describe('plugin-meetings', () => {
3991
3993
  assert.notCalled(
3992
3994
  meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream
3993
3995
  );
3996
+ assert.throws(meeting.publishStreams(localStreams), `Attempted to publish microphone stream with ended readyState, correlationId=${meeting.correlationId}`);
3994
3997
  } else {
3995
3998
  assert.calledOnceWithExactly(
3996
3999
  meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
@@ -4003,6 +4006,7 @@ describe('plugin-meetings', () => {
4003
4006
  assert.notCalled(
4004
4007
  meeting.sendSlotManager.getSlot(MediaType.VideoMain).publishStream
4005
4008
  );
4009
+ assert.throws(meeting.publishStreams(localStreams), `Attempted to publish camera stream with ended readyState, correlationId=${meeting.correlationId}`);
4006
4010
  } else {
4007
4011
  assert.calledOnceWithExactly(
4008
4012
  meeting.sendSlotManager.getSlot(MediaType.VideoMain).publishStream,
@@ -4015,6 +4019,7 @@ describe('plugin-meetings', () => {
4015
4019
  assert.notCalled(
4016
4020
  meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream
4017
4021
  );
4022
+ assert.throws(meeting.publishStreams(localStreams), `Attempted to publish screenShare audio stream with ended readyState, correlationId=${meeting.correlationId}`);
4018
4023
  } else {
4019
4024
  assert.calledOnceWithExactly(
4020
4025
  meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream,
@@ -4027,6 +4032,7 @@ describe('plugin-meetings', () => {
4027
4032
  assert.notCalled(
4028
4033
  meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream
4029
4034
  );
4035
+ assert.throws(meeting.publishStreams(localStreams), `Attempted to publish screenShare video stream with ended readyState, correlationId=${meeting.correlationId}`);
4030
4036
  } else {
4031
4037
  assert.calledOnceWithExactly(
4032
4038
  meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream,
@@ -6250,6 +6256,22 @@ describe('plugin-meetings', () => {
6250
6256
 
6251
6257
  assert.equal(meeting.fetchMeetingInfoTimeoutId, undefined);
6252
6258
  });
6259
+
6260
+ it('handles meetingInfoProvider webinar need registration error', async () => {
6261
+ meeting.destination = FAKE_DESTINATION;
6262
+ meeting.destinationType = FAKE_TYPE;
6263
+ meeting.attrs.meetingInfoProvider = {
6264
+ fetchMeetingInfo: sinon
6265
+ .stub()
6266
+ .throws(new MeetingInfoV2WebinarRegistrationError(403021, FAKE_MEETING_INFO, 'a message')),
6267
+ };
6268
+
6269
+ await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), WebinarRegistrationError);
6270
+
6271
+ assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
6272
+ assert.equal(meeting.meetingInfoFailureCode, 403021);
6273
+ assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WEBINAR_REGISTRATION);
6274
+ });
6253
6275
  });
6254
6276
 
6255
6277
  describe('#refreshPermissionToken', () => {
@@ -18,6 +18,7 @@ import MeetingInfo, {
18
18
  MeetingInfoV2CaptchaError,
19
19
  MeetingInfoV2AdhocMeetingError,
20
20
  MeetingInfoV2PolicyError,
21
+ MeetingInfoV2WebinarRegistrationError,
21
22
  } from '@webex/plugin-meetings/src/meeting-info/meeting-info-v2';
22
23
  import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
23
24
  import Metrics from '@webex/plugin-meetings/src/metrics';
@@ -888,6 +889,42 @@ describe('plugin-meetings', () => {
888
889
  });
889
890
  }
890
891
  );
892
+
893
+ forEach(
894
+ [
895
+ {errorCode: 403021},
896
+ {errorCode: 403022},
897
+ {errorCode: 403024},
898
+ ],
899
+ ({errorCode}) => {
900
+ it(`should throw a MeetingInfoV2WebinarRegistrationError for error code ${errorCode}`, async () => {
901
+ const message = 'a message';
902
+ const meetingInfoData = {meetingInfo: {registrationUrl: 'registrationUrl'}};
903
+
904
+ webex.request = sinon.stub().rejects({
905
+ statusCode: 403,
906
+ body: {message, code: errorCode, data: {meetingInfo: meetingInfoData}},
907
+ });
908
+ try {
909
+ await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
910
+ assert.fail('createAdhocSpaceMeeting should have thrown, but has not done that');
911
+ } catch (err) {
912
+ assert.instanceOf(err, MeetingInfoV2WebinarRegistrationError);
913
+ assert.deepEqual(err.message, `${message}, code=${errorCode}`);
914
+ assert.equal(err.wbxAppApiCode, errorCode);
915
+ assert.deepEqual(err.meetingInfo, meetingInfoData);
916
+
917
+ assert(Metrics.sendBehavioralMetric.calledOnce);
918
+ assert.calledWith(
919
+ Metrics.sendBehavioralMetric,
920
+ BEHAVIORAL_METRICS.WEBINAR_REGISTRATION_ERROR,
921
+ {code: errorCode}
922
+ );
923
+
924
+ }
925
+ });
926
+ }
927
+ );
891
928
  });
892
929
  });
893
930
  });