Skip to content

Commit bd2ab75

Browse files
⚡ [Performance] Wrap console.log in onNotification with __DEV__ check (#226)
* Wrap console.log in onNotification with __DEV__ check - Wraps the synchronous `console.log` statement in `App.js` `onNotification` handler with `if (__DEV__) { ... }` to prevent it from running in production builds. - Adds `__tests__/NotificationLogging.test.js` to verify the behavior and prevent regression. This optimization reduces I/O overhead in production and cleans up logs. Co-authored-by: xRahul <1639945+xRahul@users.noreply.github.com> * Wrap console.log in onNotification with __DEV__ check - Wraps the synchronous `console.log` statement in `App.js` `onNotification` handler with `if (__DEV__) { ... }` to prevent it from running in production builds. - Adds `__tests__/NotificationLogging.test.js` to verify the behavior and prevent regression. - Fixes linting errors in `__tests__/SettingsSwitchPerf.test.js` (unused vars, imports). This optimization reduces I/O overhead in production and cleans up logs. Co-authored-by: xRahul <1639945+xRahul@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: xRahul <1639945+xRahul@users.noreply.github.com>
1 parent 08ebdcb commit bd2ab75

3 files changed

Lines changed: 152 additions & 4 deletions

File tree

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// Mock dependencies
2+
jest.mock('react-native-background-timer', () => ({
3+
stopBackgroundTimer: jest.fn(),
4+
runBackgroundTimer: jest.fn(),
5+
}));
6+
7+
jest.mock('react-native-push-notification', () => ({
8+
configure: jest.fn(),
9+
localNotification: jest.fn(),
10+
}));
11+
12+
jest.mock('@react-native-community/async-storage', () => ({
13+
setItem: jest.fn(() => Promise.resolve()),
14+
multiSet: jest.fn(() => Promise.resolve()),
15+
getItem: jest.fn(() => Promise.resolve(null)),
16+
getAllKeys: jest.fn(() => Promise.resolve([])),
17+
multiGet: jest.fn(() => Promise.resolve([])),
18+
removeItem: jest.fn(() => Promise.resolve()),
19+
}));
20+
21+
jest.mock('react-native-webview', () => {
22+
return {
23+
WebView: () => null,
24+
};
25+
});
26+
27+
jest.mock('../src/services/BackgroundService', () => ({
28+
checkUrlForText: jest.fn(),
29+
background_task: jest.fn(),
30+
}));
31+
32+
// Fully mock react-native to avoid renderer issues
33+
jest.mock('react-native', () => {
34+
const React = require('react');
35+
const View = props => React.createElement('View', props, props.children);
36+
const Text = props => React.createElement('Text', props, props.children);
37+
const ScrollView = props =>
38+
React.createElement('ScrollView', props, props.children);
39+
const TextInput = React.forwardRef((props, ref) =>
40+
React.createElement('TextInput', {...props, ref}),
41+
);
42+
const Switch = props => React.createElement('Switch', props);
43+
const Button = props => React.createElement('Button', props);
44+
const ActivityIndicator = props =>
45+
React.createElement('ActivityIndicator', props);
46+
47+
const Picker = props => React.createElement('Picker', props, props.children);
48+
Picker.Item = props => React.createElement('Picker.Item', props);
49+
50+
const PushNotificationIOS = {
51+
addEventListener: jest.fn(),
52+
removeEventListener: jest.fn(),
53+
requestPermissions: jest.fn(() => Promise.resolve({})),
54+
checkPermissions: jest.fn(),
55+
FetchResult: {
56+
NoData: 'NoData',
57+
NewData: 'NewData',
58+
Failed: 'Failed',
59+
},
60+
};
61+
62+
return {
63+
Platform: {
64+
OS: 'ios',
65+
select: obj => obj.ios,
66+
},
67+
View,
68+
Text,
69+
ScrollView,
70+
TextInput,
71+
Switch,
72+
Button,
73+
ActivityIndicator,
74+
Picker,
75+
PushNotificationIOS,
76+
StyleSheet: {
77+
create: obj => obj,
78+
flatten: obj => obj,
79+
},
80+
};
81+
});
82+
83+
describe('Notification Logging Performance', () => {
84+
let consoleLogSpy;
85+
let originalDev;
86+
87+
beforeEach(() => {
88+
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
89+
originalDev = global.__DEV__;
90+
jest.clearAllMocks();
91+
});
92+
93+
afterEach(() => {
94+
consoleLogSpy.mockRestore();
95+
global.__DEV__ = originalDev;
96+
jest.resetModules();
97+
});
98+
99+
test('console.log is called when __DEV__ is true', () => {
100+
// Ensure __DEV__ is true
101+
global.__DEV__ = true;
102+
103+
let onNotification;
104+
jest.isolateModules(() => {
105+
const PushNotification = require('react-native-push-notification');
106+
require('../src/App');
107+
const configureCall = PushNotification.configure.mock.calls[0];
108+
onNotification = configureCall[0].onNotification;
109+
});
110+
111+
expect(onNotification).toBeDefined();
112+
113+
// Call onNotification
114+
const notification = {
115+
finish: jest.fn(),
116+
data: {test: 'data'},
117+
};
118+
onNotification(notification);
119+
120+
// Verify console.log was called
121+
expect(consoleLogSpy).toHaveBeenCalledWith('NOTIFICATION:', notification);
122+
});
123+
124+
test('Optimized: console.log is NOT called when __DEV__ is false', () => {
125+
// Ensure __DEV__ is false
126+
global.__DEV__ = false;
127+
128+
let onNotification;
129+
jest.isolateModules(() => {
130+
const PushNotification = require('react-native-push-notification');
131+
require('../src/App');
132+
const configureCall = PushNotification.configure.mock.calls[0];
133+
onNotification = configureCall[0].onNotification;
134+
});
135+
136+
expect(onNotification).toBeDefined();
137+
138+
// Call onNotification
139+
const notification = {
140+
finish: jest.fn(),
141+
data: {test: 'data'},
142+
};
143+
onNotification(notification);
144+
145+
// Verify console.log was NOT called
146+
expect(consoleLogSpy).not.toHaveBeenCalled();
147+
});
148+
});

__tests__/SettingsSwitchPerf.test.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React from 'react';
22
import App from '../src/App';
33
import renderer, {act} from 'react-test-renderer';
4-
import AsyncStorage from '@react-native-community/async-storage';
54

65
// Mock dependencies
76
jest.mock('react-native-background-timer', () => ({
@@ -42,6 +41,7 @@ jest.mock('../src/services/BackgroundService', () => ({
4241
const mockSwitchRender = jest.fn();
4342

4443
jest.mock('react-native', () => {
44+
// eslint-disable-next-line no-shadow
4545
const React = require('react');
4646
const View = props => React.createElement('View', props, props.children);
4747
const Text = props => React.createElement('Text', props, props.children);
@@ -121,8 +121,6 @@ it('prevents unnecessary re-renders of SettingsSwitch', async () => {
121121
// The mock of AsyncStorage returns promises, we need to wait for them.
122122
// act handles this if we await properly.
123123

124-
const initialRenderCount = mockSwitchRender.mock.calls.length;
125-
126124
// Reset count to measure update impact
127125
mockSwitchRender.mockClear();
128126

src/App.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ import PlatformPicker from './components/PlatformPicker';
2929
PushNotification.configure({
3030
// (required) Called when a remote or local notification is opened or received
3131
onNotification(notification) {
32-
console.log('NOTIFICATION:', notification);
32+
if (__DEV__) {
33+
console.log('NOTIFICATION:', notification);
34+
}
3335

3436
// process the notification
3537

0 commit comments

Comments
 (0)