Skip to content

Commit acf8f77

Browse files
committed
[RN] Allow passing error details to logError
1 parent 957a7c4 commit acf8f77

File tree

4 files changed

+163
-3
lines changed

4 files changed

+163
-3
lines changed

examples/expo/src/app/App.tsx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ const triggerGlobalJsError = (errorType: ErrorType = 'TypeError') => {
8383
}
8484
};
8585

86+
const triggerLogErrorExample = () => {
87+
try {
88+
const data = JSON.parse('{ invalid json }');
89+
console.log(data);
90+
} catch (err) {
91+
error('JSON parsing failed in example', err);
92+
showToast('Error logged with error API');
93+
}
94+
};
95+
8696

8797
const LOG_LEVEL_ARRAY = Array.from(LOG_LEVELS.keys());
8898

@@ -331,13 +341,30 @@ const HomeScreen = () => {
331341
</View>
332342
<View style={styles.buttonRow}>
333343
<Pressable
334-
style={({ pressed }) => [styles.button, pressed && styles.buttonActive]}
344+
style={({ pressed }) => [
345+
styles.button,
346+
styles.errorButton,
347+
pressed && styles.buttonActive,
348+
]}
335349
onPress={() => triggerGlobalJsError(selectedErrorType)}
336350
>
337351
<Text style={styles.buttonText}>Trigger {selectedErrorType}</Text>
338352
</Pressable>
339353
</View>
340354

355+
<View style={styles.buttonRow}>
356+
<Pressable
357+
style={({ pressed }) => [
358+
styles.button,
359+
styles.logErrorButton,
360+
pressed && styles.buttonActive,
361+
]}
362+
onPress={triggerLogErrorExample}
363+
>
364+
<Text style={styles.buttonText}>Test logError API</Text>
365+
</Pressable>
366+
</View>
367+
341368
</View>
342369
);
343370
};
@@ -387,6 +414,12 @@ const styles = StyleSheet.create({
387414
borderRadius: 5,
388415
marginVertical: 10,
389416
},
417+
errorButton: {
418+
backgroundColor: '#e74c3c',
419+
},
420+
logErrorButton: {
421+
backgroundColor: '#007ACC',
422+
},
390423
buttonActive: {
391424
backgroundColor: '#007867',
392425
},

packages/react-native/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,15 @@ warn('Hello, World!');
109109

110110
error('Hello, World!');
111111

112+
// Optionally pass an Error object to automatically capture error details
113+
try {
114+
// some code that might throw
115+
} catch (err) {
116+
error('Failed to process request', err);
117+
// Or with additional fields
118+
error('Failed to process request', { userId: '123' }, err);
119+
}
120+
112121
```
113122

114123
### Network Integration

packages/react-native/src/index.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,18 @@ export function warn(message: string, fields?: SerializableLogFields): void {
7171
return logInternal('warn', message, fields);
7272
}
7373

74-
export function error(message: string, fields?: SerializableLogFields): void {
75-
return logInternal('error', message, fields);
74+
export function error(
75+
message: string,
76+
fields?: SerializableLogFields,
77+
error?: Error | null,
78+
): void {
79+
const combinedFields = error ? {
80+
...fields,
81+
_error: error.name || 'Error',
82+
_error_details: error.message || '',
83+
} : fields;
84+
85+
return logInternal('error', message, combinedFields);
7686
}
7787

7888
export function log(

packages/react-native/src/log.test.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,20 @@
88
/* eslint-disable no-useless-escape */
99

1010
import { logInternal } from './log';
11+
import { error } from './index';
1112
import Native from './NativeBdReactNative';
1213

1314
jest.mock('react-native', () => ({
1415
TurboModuleRegistry: {
1516
getEnforcing: jest.fn().mockReturnValue({
1617
log: jest.fn(),
18+
init: jest.fn(),
1719
}),
1820
},
21+
NativeModules: {},
22+
Platform: {
23+
select: jest.fn(),
24+
},
1925
}));
2026

2127
describe('log', () => {
@@ -41,3 +47,105 @@ describe('log', () => {
4147
expect(Native.log).toHaveBeenCalledWith(0, 'message', expected);
4248
});
4349
});
50+
51+
describe('error', () => {
52+
beforeEach(() => {
53+
(Native.log as jest.Mock) = jest.fn();
54+
});
55+
56+
it('should log error with just message', () => {
57+
error('Simple error message');
58+
59+
expect(Native.log).toHaveBeenCalledWith(
60+
4,
61+
'Simple error message',
62+
undefined
63+
);
64+
});
65+
66+
it('should log error with message and fields', () => {
67+
error('Error message', { userId: '123' });
68+
69+
expect(Native.log).toHaveBeenCalledWith(
70+
4,
71+
'Error message',
72+
{ userId: '123' }
73+
);
74+
});
75+
76+
it('should log error with Error object', () => {
77+
const err = new Error('Technical error');
78+
err.name = 'TestError';
79+
80+
error('User-friendly message', undefined, err);
81+
82+
expect(Native.log).toHaveBeenCalledWith(
83+
4,
84+
'User-friendly message',
85+
{
86+
_error: 'TestError',
87+
_error_details: 'Technical error',
88+
}
89+
);
90+
});
91+
92+
it('should log error with fields and Error object', () => {
93+
const err = new Error('Technical error');
94+
err.name = 'TestError';
95+
96+
error('User-friendly message', { userId: '123', action: 'submit' }, err);
97+
98+
expect(Native.log).toHaveBeenCalledWith(
99+
4,
100+
'User-friendly message',
101+
{
102+
userId: '123',
103+
action: 'submit',
104+
_error: 'TestError',
105+
_error_details: 'Technical error',
106+
}
107+
);
108+
});
109+
110+
it('should handle null Error', () => {
111+
error('Message with null error', { context: 'test' }, null);
112+
113+
expect(Native.log).toHaveBeenCalledWith(
114+
4,
115+
'Message with null error',
116+
{ context: 'test' }
117+
);
118+
});
119+
120+
it('should handle error with empty message', () => {
121+
const err = new Error();
122+
err.name = 'EmptyError';
123+
124+
error('Error occurred', undefined, err);
125+
126+
expect(Native.log).toHaveBeenCalledWith(
127+
4,
128+
'Error occurred',
129+
{
130+
_error: 'EmptyError',
131+
_error_details: '',
132+
}
133+
);
134+
});
135+
136+
it('should handle error without name', () => {
137+
const err = new Error('Message only');
138+
Object.defineProperty(err, 'name', { value: '' });
139+
140+
error('Operation failed', undefined, err);
141+
142+
expect(Native.log).toHaveBeenCalledWith(
143+
4,
144+
'Operation failed',
145+
{
146+
_error: 'Error',
147+
_error_details: 'Message only',
148+
}
149+
);
150+
});
151+
});

0 commit comments

Comments
 (0)