diff --git a/packages/@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.ts b/packages/@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.ts index 81bf12c7b7c..90e23fa8d00 100644 --- a/packages/@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.ts +++ b/packages/@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.ts @@ -19,6 +19,7 @@ import { isNetworkError, isUnauthorizedError, isSdpOfferCreationError, + isTypeError, } from './call-diagnostic-metrics.util'; import {CLIENT_NAME} from '../config'; import { @@ -56,6 +57,7 @@ import { AUTHENTICATION_FAILED_CODE, WEBEX_SUB_SERVICE_TYPES, SDP_OFFER_CREATION_ERROR_MAP, + TYPE_ERROR_CLIENT_CODE, } from './config'; const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection(); @@ -526,6 +528,17 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin { generateClientEventErrorPayload(rawError: any) { const rawErrorMessage = rawError.message; const httpStatusCode = rawError.statusCode; + + if (isTypeError(rawError)) { + return this.getErrorPayloadForClientErrorCode({ + serviceErrorCode: undefined, + clientErrorCode: TYPE_ERROR_CLIENT_CODE, + serviceErrorName: rawError.name, + rawErrorMessage, + httpStatusCode, + }); + } + if (rawError.name) { if (isBrowserMediaErrorName(rawError.name)) { return this.getErrorPayloadForClientErrorCode({ diff --git a/packages/@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.util.ts b/packages/@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.util.ts index 3c673580f1f..afed974aedc 100644 --- a/packages/@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.util.ts +++ b/packages/@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.util.ts @@ -178,6 +178,15 @@ export const isSdpOfferCreationError = (rawError: any) => { return false; }; +/** + * Any service can return a TypeError, which tells little about the service it came from + * Documentation can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError/TypeError + * + * @param errorCode + * @returns + */ +export const isTypeError = (error: any) => error instanceof TypeError; + /** * MDN Media Devices getUserMedia() method returns a name if it errs * Documentation can be found here: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia diff --git a/packages/@webex/internal-plugin-metrics/src/call-diagnostic/config.ts b/packages/@webex/internal-plugin-metrics/src/call-diagnostic/config.ts index a9a8350d06c..5e476fbea5d 100644 --- a/packages/@webex/internal-plugin-metrics/src/call-diagnostic/config.ts +++ b/packages/@webex/internal-plugin-metrics/src/call-diagnostic/config.ts @@ -16,6 +16,7 @@ export const MISSING_ROAP_ANSWER_CLIENT_CODE = 2007; export const DTLS_HANDSHAKE_FAILED_CLIENT_CODE = 2008; export const ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE = 2010; export const ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE = 2009; +export const TYPE_ERROR_CLIENT_CODE = 2011; export const WBX_APP_API_URL = 'wbxappapi'; // MeetingInfo WebexAppApi response object normally contains a body.url that includes the string 'wbxappapi' export const WEBEX_SUB_SERVICE_TYPES: Record = { @@ -33,7 +34,6 @@ const BROWSER_MEDIA_ERROR_NAMES = { NOT_FOUND_ERROR: 'NotFoundError', OVERCONSTRAINED_ERROR: 'OverconstrainedError', SECURITY_ERROR: 'SecurityError', - TYPE_ERROR: 'TypeError', }; export const BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP = { @@ -44,7 +44,6 @@ export const BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP = { [BROWSER_MEDIA_ERROR_NAMES.NOT_FOUND_ERROR]: 2729, // User did not grant permission [BROWSER_MEDIA_ERROR_NAMES.OVERCONSTRAINED_ERROR]: 2729, // Thrown if the specified constraints resulted in no candidate devices which met the criteria requested. [BROWSER_MEDIA_ERROR_NAMES.SECURITY_ERROR]: 2729, // Thrown if user media support is disabled on the Document on which getUserMedia() was called. The mechanism by which user media support is enabled and disabled is left up to the individual user agent. - [BROWSER_MEDIA_ERROR_NAMES.TYPE_ERROR]: 2729, // Thrown if the list of constraints specified is empty, or has all constraints set to false. This can also happen if you try to call getUserMedia() in an insecure context, since navigator.mediaDevices is undefined in an insecure context. }; export const SDP_OFFER_CREATION_ERROR_MAP = { @@ -127,6 +126,7 @@ export const ERROR_DESCRIPTIONS = { ICE_FAILED_WITH_TURN_TLS: 'ICEFailedWithTURN_TLS', SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError', SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec', + TYPE_ERROR: 'TypeError', }; export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = { @@ -395,6 +395,11 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record { rawErrorMessage: 'bad times', }; + const checkTypeError = (payload: any, isExpectedToBeCalled: boolean) => { + const res = cd.generateClientEventErrorPayload(payload); + const expectedResult = { + category: 'other', + errorDescription: 'TypeError', + fatal: true, + name: 'other', + shownToUser: false, + serviceErrorCode: undefined, + errorCode: 2011, + errorData: {errorName: payload.name}, + rawErrorMessage: payload.message, + }; + + if (isExpectedToBeCalled) { + assert.deepEqual(res, expectedResult); + } else { + console.log(res); + assert.notDeepEqual(res, expectedResult); + } + }; + + + it('should generate type error payload if rawError isTypeError', () => { + const typeError = new TypeError; + checkTypeError(typeError, true); + }); + + it('should not generate type error payload if rawError is not TypeError', () => { + const typeError = new Error; + checkTypeError(typeError, false); + }); + const checkNameError = (payload: any, isExpectedToBeCalled: boolean) => { const res = cd.generateClientEventErrorPayload(payload); const expectedResult = { diff --git a/packages/@webex/internal-plugin-metrics/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts b/packages/@webex/internal-plugin-metrics/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts index fedf4ed0a2c..3736f311694 100644 --- a/packages/@webex/internal-plugin-metrics/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +++ b/packages/@webex/internal-plugin-metrics/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts @@ -25,6 +25,7 @@ const { isUnauthorizedError, generateClientErrorCodeForIceFailure, isSdpOfferCreationError, + isTypeError, } = CallDiagnosticUtils; describe('internal-plugin-metrics', () => { @@ -205,6 +206,21 @@ describe('internal-plugin-metrics', () => { }); }); + describe('isTypeError', () => { + [ + [new TypeError, true], + [new TypeError('oh no'), true], + [new Error, false], + [new Error('oh no'), false], + [{name: 'TypeError'}, false], + ].forEach(([error, expected]) => { + it(`for rawError ${error} returns the correct result`, () => { + //@ts-ignore + assert.deepEqual(isTypeError(error), expected); + }); + }); + }); + describe('isBrowserMediaErrorName', () => { [ ['PermissionDeniedError', true], @@ -221,8 +237,6 @@ describe('internal-plugin-metrics', () => { ['OverconstrainedErrors', false], ['SecurityError', true], ['SecurityErrors', false], - ['TypeError', true], - ['TypeErrors', false], ['', false], ['SomethingElse', false], [{name: 'SomethingElse'}, false],