Skip to content

Commit bb1db25

Browse files
Merge pull request #1417 from Instabug/feat/support-chaining-erros
feat: support chaining errors
2 parents 2a6f0a7 + cd4b238 commit bb1db25

File tree

9 files changed

+145
-15
lines changed

9 files changed

+145
-15
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# Changelog
22

3+
## [16.0.4](https://github.com/Instabug/Instabug-React-Native/compare/v16.0.4...dev)
4+
5+
### Added
6+
7+
- Add support for chaining errors . ([#1417](https://github.com/Instabug/Instabug-React-Native/pull/1417))
8+
9+
## [16.0.3](https://github.com/Instabug/Instabug-React-Native/compare/v16.0.3...dev)
10+
11+
### Changed
12+
13+
- Bump Instabug iOS SDK to v16.0.3 ([#1452](https://github.com/Instabug/Instabug-React-Native/pull/1452)). [See release notes](https://github.com/Instabug/Instabug-iOS/releases/tag/16.0.3).
14+
15+
## [16.0.1](https://github.com/Instabug/Instabug-React-Native/compare/v16.0.0...dev)
16+
17+
### Fixed
18+
19+
- Reading `INSTABUG_APP_TOKEN` when upload sourcemap file ([#1448](https://github.com/Instabug/Instabug-React-Native/pull/1448))
20+
321
## [16.0.0](https://github.com/Instabug/Instabug-React-Native/compare/v15.0.3...dev)
422

523
### Added

android/sourcemaps.gradle

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,17 @@ Task createUploadSourcemapsTask(String flavor, String defaultVersionName, String
4242
def appProject = project(':app')
4343
def appDir = appProject.projectDir
4444
def sourceMapFile = getSourceMapFile(appDir, flavor,task)
45-
println "✅ Resolved sourcemap file path: ${sourceMapFile.absolutePath}"
4645

4746
def jsProjectDir = rootDir.parentFile
4847
def instabugDir = new File(['node', '-p', 'require.resolve("instabug-reactnative/package.json")'].execute(null, rootDir).text.trim()).getParentFile()
4948

5049
def tokenJsFile = new File(instabugDir, 'scripts/find-token.js')
5150
def inferredToken = executeNodeScript(tokenJsFile, jsProjectDir)
51+
def appToken = resolveVar('App Token', 'INSTABUG_APP_TOKEN', inferredToken)
5252

53-
if (!inferredToken) {
53+
if (!appToken) {
5454
throw new GradleException("❌ Unable to infer Instabug token from script: ${tokenShellFile.absolutePath}")
5555
}
56-
57-
def appToken = resolveVar('App Token', 'INSTABUG_APP_TOKEN', inferredToken)
58-
5956
def versionName = resolveVar('Version Name', 'INSTABUG_VERSION_NAME', defaultVersionName)
6057
def versionCode = resolveVar('Version Code', 'INSTABUG_VERSION_CODE', defaultVersionCode)
6158

@@ -77,8 +74,6 @@ Task createUploadSourcemapsTask(String flavor, String defaultVersionName, String
7774
} catch (exception) {
7875
project.logger.error "Failed to upload source map file.\n" +
7976
"Reason: ${exception.message}"
80-
throw exception
81-
8277
}
8378
}
8479
}

examples/default/ios/Podfile.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ PODS:
3131
- hermes-engine (0.75.4):
3232
- hermes-engine/Pre-built (= 0.75.4)
3333
- hermes-engine/Pre-built (0.75.4)
34-
- Instabug (16.0.2)
34+
- Instabug (16.0.3)
3535
- instabug-reactnative-ndk (0.1.0):
3636
- DoubleConversion
3737
- glog
@@ -1625,8 +1625,8 @@ PODS:
16251625
- ReactCommon/turbomodule/bridging
16261626
- ReactCommon/turbomodule/core
16271627
- Yoga
1628-
- RNInstabug (16.0.0):
1629-
- Instabug (= 16.0.2)
1628+
- RNInstabug (16.0.4):
1629+
- Instabug (= 16.0.3)
16301630
- React-Core
16311631
- RNReanimated (3.16.1):
16321632
- DoubleConversion
@@ -2022,7 +2022,7 @@ SPEC CHECKSUMS:
20222022
Google-Maps-iOS-Utils: f77eab4c4326d7e6a277f8e23a0232402731913a
20232023
GoogleMaps: 032f676450ba0779bd8ce16840690915f84e57ac
20242024
hermes-engine: ea92f60f37dba025e293cbe4b4a548fd26b610a0
2025-
Instabug: 125f729dea4e4a43e815ae06f9db0332e2a5fd60
2025+
Instabug: b6290ceceb5d98966aa6f10fbd7970026a916f65
20262026
instabug-reactnative-ndk: d765ac289d56e8896398d02760d9abf2562fc641
20272027
OCMock: 589f2c84dacb1f5aaf6e4cec1f292551fe748e74
20282028
RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
@@ -2090,7 +2090,7 @@ SPEC CHECKSUMS:
20902090
ReactCommon: 6a952e50c2a4b694731d7682aaa6c79bc156e4ad
20912091
RNCClipboard: 2821ac938ef46f736a8de0c8814845dde2dcbdfb
20922092
RNGestureHandler: 511250b190a284388f9dd0d2e56c1df76f14cfb8
2093-
RNInstabug: f06cf043f071311456d3ad14b4f9da628f2cd29b
2093+
RNInstabug: 35e4ac525227429fc1f22fa7dd069f317d69f86e
20942094
RNReanimated: f42a5044d121d68e91680caacb0293f4274228eb
20952095
RNScreens: c7ceced6a8384cb9be5e7a5e88e9e714401fd958
20962096
RNSVG: 8b1a777d54096b8c2a0fd38fc9d5a454332bbb4d

examples/default/src/screens/CrashReportingScreen.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,32 @@ export const CrashReportingScreen: React.FC = () => {
6262
throw error;
6363
}
6464
}
65+
66+
function throwUnhandledChainingException(error: Error, isPromise: boolean = false) {
67+
const appName = 'Instabug Test App';
68+
const rejectionType = isPromise ? 'Promise Rejection ' : '';
69+
const errorMessage = `Unhandled ${rejectionType}${error.name} from ${appName}`;
70+
71+
if (!error.message) {
72+
console.log(`IBG-CRSH | Error message: ${error.message}`);
73+
error.message = errorMessage;
74+
}
75+
76+
if (isPromise) {
77+
console.log('IBG-CRSH | Promise');
78+
Promise.reject(error).then(() =>
79+
Alert.alert(`Promise Rejection Crash report for ${error.name} is Sent!`),
80+
);
81+
} else {
82+
try {
83+
throw ReferenceError();
84+
} catch (e) {
85+
error.cause = e;
86+
throw error;
87+
}
88+
}
89+
}
90+
6591
const [isEnabled, setIsEnabled] = useState(false);
6692

6793
const [userAttributeKey, setUserAttributeKey] = useState('');
@@ -216,6 +242,10 @@ export const CrashReportingScreen: React.FC = () => {
216242
title="Throw Unhandled Syntax Exception"
217243
onPress={() => throwUnhandledException(new SyntaxError())}
218244
/>
245+
<ListTile
246+
title="Throw Unhandled Chaining Exception"
247+
onPress={() => throwUnhandledChainingException(new SyntaxError('level 1 SyntaxError'))}
248+
/>
219249
<ListTile
220250
title="Throw Unhandled Range Exception"
221251
onPress={() => throwUnhandledException(new RangeError())}

ios/native.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
$instabug = { :version => '16.0.2' }
1+
$instabug = { :version => '16.0.3' }
22

33
def use_instabug! (spec = nil)
44
version = $instabug[:version]

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "instabug-reactnative",
33
"description": "React Native plugin for integrating the Instabug SDK",
4-
"version": "16.0.0",
4+
"version": "16.0.4",
55
"author": "Instabug (https://instabug.com)",
66
"repository": "github:Instabug/Instabug-React-Native",
77
"homepage": "https://www.instabug.com/platforms/react-native",

src/native/NativeCrashReporting.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,20 @@ export interface CrashData {
1111
os: (typeof Platform)['OS'];
1212
platform: 'react_native';
1313
exception: StackFrame[];
14+
cause_crash?: CauseCrashData;
15+
}
16+
17+
export interface CauseCrashData {
18+
message: string;
19+
e_message: string;
20+
e_name: string;
21+
exception: StackFrame[];
22+
cause_crash?: CauseCrashData;
1423
}
1524

1625
export interface CrashReportingNativeModule extends NativeModule {
1726
setEnabled(isEnabled: boolean): void;
27+
1828
sendJSCrash(data: CrashData | string): Promise<void>;
1929

2030
sendHandledJSCrash(
@@ -23,6 +33,7 @@ export interface CrashReportingNativeModule extends NativeModule {
2333
fingerprint?: string | null,
2434
nonFatalExceptionLevel?: NonFatalErrorLevel | null,
2535
): Promise<void>;
36+
2637
setNDKCrashesEnabled(isEnabled: boolean): Promise<void>;
2738
}
2839

src/utils/InstabugUtils.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import parseErrorStackLib, {
77
import type { NavigationState as NavigationStateV5, PartialState } from '@react-navigation/native';
88
import type { NavigationState as NavigationStateV4 } from 'react-navigation';
99

10-
import type { CrashData } from '../native/NativeCrashReporting';
10+
import type { CauseCrashData, CrashData } from '../native/NativeCrashReporting';
1111
import { NativeCrashReporting } from '../native/NativeCrashReporting';
1212
import type { NetworkData } from './XhrNetworkInterceptor';
1313
import { NativeInstabug } from '../native/NativeInstabug';
@@ -59,6 +59,23 @@ export const getCrashDataFromError = (error: Error) => {
5959
platform: 'react_native',
6060
exception: jsStackTrace,
6161
};
62+
// Recursively attach inner_crash objects (up to 3 levels)
63+
let currentError: any = error;
64+
let level = 0;
65+
let parentCrash: CauseCrashData | CrashData = jsonObject;
66+
while (currentError.cause && level < 3) {
67+
const cause = currentError.cause as Error;
68+
const innerCrash: CauseCrashData = {
69+
message: `${cause.name} - ${cause.message}`,
70+
e_message: cause.message,
71+
e_name: cause.name,
72+
exception: getStackTrace(cause),
73+
};
74+
parentCrash.cause_crash = innerCrash;
75+
parentCrash = innerCrash;
76+
currentError = cause;
77+
level++;
78+
}
6279
return jsonObject;
6380
};
6481

test/utils/InstabugUtils.spec.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,65 @@ describe('Instabug Utils', () => {
243243
NonFatalErrorLevel.error,
244244
);
245245
});
246+
it('getCrashDataFromError should include one level of cause crash', () => {
247+
const causeError = new TypeError('Cause error');
248+
const rootError = new Error('Root error');
249+
(rootError as any).cause = causeError;
250+
251+
const crashData = InstabugUtils.getCrashDataFromError(rootError);
252+
const jsStackTraceRootError = InstabugUtils.getStackTrace(rootError);
253+
const jsStackTraceCauseError = InstabugUtils.getStackTrace(causeError);
254+
255+
expect(crashData.message).toBe('Error - Root error');
256+
expect(crashData.e_message).toBe('Root error');
257+
expect(crashData.e_name).toBe('Error');
258+
expect(crashData.platform).toBe('react_native');
259+
expect(crashData.exception).toEqual(jsStackTraceRootError);
260+
expect(crashData.cause_crash).toBeDefined();
261+
expect(crashData.cause_crash?.message).toBe('TypeError - Cause error');
262+
expect(crashData.cause_crash?.e_name).toBe('TypeError');
263+
expect(crashData.cause_crash?.exception).toEqual(jsStackTraceCauseError);
264+
});
265+
266+
it('getCrashDataFromError should include up to 3 levels of cause crash', () => {
267+
const errorLevel3 = new Error('Third level error');
268+
const errorLevel2 = new Error('Second level error');
269+
const errorLevel1 = new Error('First level error');
270+
const rootError = new Error('Root error');
271+
272+
(errorLevel2 as any).cause = errorLevel3;
273+
(errorLevel1 as any).cause = errorLevel2;
274+
(rootError as any).cause = errorLevel1;
275+
276+
const crashData = InstabugUtils.getCrashDataFromError(rootError);
277+
278+
expect(crashData.message).toBe('Error - Root error');
279+
expect(crashData.cause_crash?.message).toBe('Error - First level error');
280+
expect(crashData.cause_crash?.cause_crash?.message).toBe('Error - Second level error');
281+
expect(crashData.cause_crash?.cause_crash?.cause_crash?.message).toBe(
282+
'Error - Third level error',
283+
);
284+
expect(crashData.cause_crash?.cause_crash?.cause_crash?.cause_crash).toBeUndefined();
285+
});
286+
287+
it('getCrashDataFromError should stop at 3 levels even if more causes exist', () => {
288+
const errorLevel4 = new Error('Fourth level error');
289+
const errorLevel3 = new Error('Third level error');
290+
const errorLevel2 = new Error('Second level error');
291+
const errorLevel1 = new Error('First level error');
292+
const rootError = new Error('Root error');
293+
294+
(errorLevel3 as any).cause = errorLevel4;
295+
(errorLevel2 as any).cause = errorLevel3;
296+
(errorLevel1 as any).cause = errorLevel2;
297+
(rootError as any).cause = errorLevel1;
298+
299+
const crashData = InstabugUtils.getCrashDataFromError(rootError);
300+
301+
const thirdLevel = crashData.cause_crash?.cause_crash?.cause_crash;
302+
expect(thirdLevel?.message).toBe('Error - Third level error');
303+
expect(thirdLevel?.cause_crash).toBeUndefined(); // should not include 4th level
304+
});
246305
});
247306

248307
describe('reportNetworkLog', () => {

0 commit comments

Comments
 (0)