diff --git a/change/@react-native-windows-telemetry-990667a5-918a-4348-8861-ce4ad8fc7a47.json b/change/@react-native-windows-telemetry-990667a5-918a-4348-8861-ce4ad8fc7a47.json new file mode 100644 index 00000000000..a36a1591ac1 --- /dev/null +++ b/change/@react-native-windows-telemetry-990667a5-918a-4348-8861-ce4ad8fc7a47.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Fix bug in error telemetry collection.", + "packageName": "@react-native-windows/telemetry", + "email": "14967941+danielayala94@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/@react-native-windows/telemetry/src/e2etest/telemetry.test.ts b/packages/@react-native-windows/telemetry/src/e2etest/telemetry.test.ts index 00df0c63a14..790ff617a9f 100644 --- a/packages/@react-native-windows/telemetry/src/e2etest/telemetry.test.ts +++ b/packages/@react-native-windows/telemetry/src/e2etest/telemetry.test.ts @@ -22,6 +22,18 @@ import * as errorUtils from '../utils/errorUtils'; import * as projectUtils from '../utils/projectUtils'; import * as versionUtils from '../utils/versionUtils'; +class CustomTestError extends Error { + // Declare a mock errno field, so it is picked up by trackException() (see syscallExceptionFieldsToCopy) + // to copy it into codedError.data. + errno: string; + + constructor(message: string) { + super(message); + this.name = 'CustomTestError'; + this.errno = '123'; + } +} + export class TelemetryTest extends Telemetry { protected static hasTestTelemetryProviders: boolean; protected static testTelemetryProvidersRan: boolean; @@ -391,8 +403,16 @@ function verifyTestCommandTelemetryProcessor( : 'Unknown', ); + // If the exception type is not CodedError but any data got copied into envelope.CodedError.data, + // for instance autolinking error info, build the expected CodedError.data. + let expectedCodedErrorData = {}; + if (expectedError instanceof CustomTestError) { + expectedCodedErrorData = {errno: expectedError.errno}; + } + expect(codedError.data).toStrictEqual( - (expectedError as errorUtils.CodedError).data ?? {}, + (expectedError as errorUtils.CodedError).data ?? + expectedCodedErrorData, ); } else { // If this is not error scenario, it must be a command successful event. @@ -694,3 +714,29 @@ test.each(testTelemetryOptions)( }); }, ); + +test.each(testTelemetryOptions)( + 'A custom Error-based object with MS Build error info is copied into codedError.data appropriately by trackException()', + async options => { + await TelemetryTest.startTest(options); + + const expectedError = new CustomTestError('some message'); + + // AI eats errors thrown in telemetry processors + const caughtErrors: Error[] = []; + TelemetryTest.addTelemetryInitializer( + verifyTestCommandTelemetryProcessor( + caughtErrors, + 'Unknown', + expectedError, + ), + ); + + await runTestCommandE2E(() => testCommandBody(expectedError)); + + TelemetryTest.endTest(() => { + // Check if any errors were thrown + expect(caughtErrors).toHaveLength(0); + }); + }, +); diff --git a/packages/@react-native-windows/telemetry/src/telemetry.ts b/packages/@react-native-windows/telemetry/src/telemetry.ts index c14ca9b4793..509a578ac03 100644 --- a/packages/@react-native-windows/telemetry/src/telemetry.ts +++ b/packages/@react-native-windows/telemetry/src/telemetry.ts @@ -463,7 +463,7 @@ export class Telemetry { const syscallExceptionFieldsToCopy = ['errno', 'syscall', 'code']; for (const f of syscallExceptionFieldsToCopy) { if ((error as any)[f]) { - codedErrorStruct.data.codedError.data[f] = (error as any)[f]; + codedErrorStruct.data[f] = (error as any)[f]; } }