From ded266ec85000461eb2cce8fe26b18aa463d575d Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Fri, 30 Jan 2026 22:57:51 +0000
Subject: [PATCH 1/3] Optimize SettingsSwitch event handlers with useCallback
Wrapped the `onValueChange` handlers for 'Case Sensitive Search' and 'Search Absence of Text' switches in `useCallback` to prevent unnecessary function re-creations on every render.
Also wrapped the `persist` helper function in `useCallback` to ensure its stability as a dependency.
Added a regression test to verify handler stability.
Co-authored-by: xRahul <1639945+xRahul@users.noreply.github.com>
---
__tests__/AppOptimization.test.js | 139 ++++++++++++++++++++++++++
package.json | 2 +
src/App.js | 36 ++++---
yarn.lock | 160 +++++++++++++++++++++++++++++-
4 files changed, 323 insertions(+), 14 deletions(-)
create mode 100644 __tests__/AppOptimization.test.js
diff --git a/__tests__/AppOptimization.test.js b/__tests__/AppOptimization.test.js
new file mode 100644
index 0000000..dcddae3
--- /dev/null
+++ b/__tests__/AppOptimization.test.js
@@ -0,0 +1,139 @@
+
+import React from 'react';
+import renderer from 'react-test-renderer';
+// We don't import TextInput from react-native here because we are mocking it.
+// We will access it via the mock or just by string type if necessary.
+
+// Mock dependencies
+jest.mock('react-native-background-timer', () => ({
+ stopBackgroundTimer: jest.fn(),
+ runBackgroundTimer: jest.fn(),
+}));
+
+jest.mock('react-native-push-notification', () => ({
+ configure: jest.fn(),
+ localNotification: jest.fn(),
+}));
+
+jest.mock('@react-native-community/async-storage', () => ({
+ setItem: jest.fn(() => Promise.resolve()),
+ multiSet: jest.fn(() => Promise.resolve()),
+ getItem: jest.fn(() => Promise.resolve(null)),
+ getAllKeys: jest.fn(() => Promise.resolve([])),
+ multiGet: jest.fn(() => Promise.resolve([])),
+ removeItem: jest.fn(() => Promise.resolve()),
+}));
+
+jest.mock('react-native-webview', () => {
+ return {
+ WebView: () => null,
+ };
+});
+
+jest.mock('../src/services/BackgroundService', () => ({
+ checkUrlForText: jest.fn(),
+ background_task: jest.fn(),
+}));
+
+// Fully mock react-native to avoid renderer issues
+jest.mock('react-native', () => {
+ // eslint-disable-next-line no-shadow
+ const React = require('react');
+ const View = props => React.createElement('View', props, props.children);
+ const Text = props => React.createElement('Text', props, props.children);
+ const ScrollView = props =>
+ React.createElement('ScrollView', props, props.children);
+ const TextInput = React.forwardRef((props, ref) =>
+ React.createElement('TextInput', {...props, ref}),
+ );
+ const Switch = props => React.createElement('Switch', props);
+ const Button = props => React.createElement('Button', props);
+ const ActivityIndicator = props =>
+ React.createElement('ActivityIndicator', props);
+
+ const Picker = props => React.createElement('Picker', props, props.children);
+ Picker.Item = props => React.createElement('Picker.Item', props);
+
+ const PushNotificationIOS = {
+ addEventListener: jest.fn(),
+ removeEventListener: jest.fn(),
+ requestPermissions: jest.fn(() => Promise.resolve({})),
+ checkPermissions: jest.fn(),
+ FetchResult: {
+ NoData: 'NoData',
+ NewData: 'NewData',
+ Failed: 'Failed',
+ },
+ };
+
+ return {
+ Platform: {
+ OS: 'ios',
+ select: obj => obj.ios,
+ },
+ View,
+ Text,
+ ScrollView,
+ TextInput,
+ Switch,
+ Button,
+ ActivityIndicator,
+ Picker,
+ PushNotificationIOS,
+ StyleSheet: {
+ create: obj => obj,
+ flatten: obj => obj,
+ },
+ };
+});
+
+// Import App after mocking react-native
+const App = require('../src/App').default;
+
+it('Case Sensitive Search handler reference check', () => {
+ const component = renderer.create();
+ const root = component.root;
+
+ const findSettingsSwitch = () => root.findAll(node =>
+ node.type.name === 'SettingsSwitch' && node.props.label === 'Case Sensitive Search:'
+ )[0];
+
+ let switchComp = findSettingsSwitch();
+ const handler1 = switchComp.props.onValueChange;
+
+ // Find the TextInput. Since we mocked it as 'TextInput', we can find it by type 'TextInput'
+ // But wait, the mock returns a React component.
+ // In the mock: const TextInput = React.forwardRef...
+ // So we need to find that component.
+
+ // We can find by prop if needed, or by type name if the mock sets displayName.
+ // Or we can just inspect the tree.
+
+ // Let's rely on finding by type name "TextInput" if react-test-renderer supports it for functional components.
+ // Or better, we can find by props passed to it. UrlInput passes 'autoCapitalize="none"'.
+
+ const allTextInputs = root.findAll(node => node.type === 'TextInput' || (node.type.render && node.type.render.name === 'TextInput') || node.type.name === 'TextInput' || (node.props.onChangeText && node.props.value !== undefined));
+
+ // The mock uses createElement('TextInput'...), so the type in the output tree will be 'TextInput'.
+ // However, the component in the tree is the Mocked TextInput.
+
+ // Let's filter by checking if it has onChangeText
+ const textInputs = root.findAll(node => node.props.onChangeText);
+ const urlInput = textInputs[0];
+
+ renderer.act(() => {
+ urlInput.props.onChangeText('new url');
+ });
+
+ // Re-find the switch component
+ switchComp = findSettingsSwitch();
+ const handler2 = switchComp.props.onValueChange;
+
+ if (handler1 === handler2) {
+ console.log('Handler is stable (OPTIMIZED)');
+ } else {
+ console.log('Handler is new instance (UNOPTIMIZED)');
+ }
+
+ expect(handler1).toBe(handler2);
+});
diff --git a/package.json b/package.json
index ece4105..4f6804e 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,8 @@
"@babel/core": "^7.6.4",
"@babel/runtime": "^7.6.3",
"@react-native-community/eslint-config": "^0.0.5",
+ "@testing-library/jest-native": "^5.4.3",
+ "@testing-library/react-native": "^13.3.3",
"babel-jest": "^24.9.0",
"eslint": "^6.5.1",
"eslint-plugin-react": "^7.37.5",
diff --git a/src/App.js b/src/App.js
index a5641d9..23a8ed5 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,4 +1,4 @@
-import React, {useState, useEffect, useRef} from 'react';
+import React, {useState, useEffect, useRef, useCallback} from 'react';
import {
Platform,
Text,
@@ -114,13 +114,13 @@ const App = () => {
loadState();
}, []);
- const persist = async (key, value) => {
+ const persist = useCallback(async (key, value) => {
try {
await AsyncStorage.setItem(key, value);
} catch (error) {
console.log(error);
}
- };
+ }, []);
const createPrefetchJobs = async () => {
try {
@@ -189,6 +189,24 @@ const App = () => {
refreshWebView();
};
+ const handleCaseSensitiveChange = useCallback(
+ value => {
+ const valStr = value ? 'yes' : 'no';
+ setCaseSensitiveSearch(valStr);
+ persist('caseSensitiveSearch', valStr);
+ },
+ [persist],
+ );
+
+ const handleSearchAbsenceChange = useCallback(
+ value => {
+ const valStr = value ? 'yes' : 'no';
+ setSearchAbsence(valStr);
+ persist('searchAbsence', valStr);
+ },
+ [persist],
+ );
+
const webViewProps = {};
if (webPlatformType === WEB_PLATFORM_DESKTOP) {
webViewProps.userAgent = USER_AGENT_DESKTOP;
@@ -217,21 +235,13 @@ const App = () => {
{
- const valStr = value ? 'yes' : 'no';
- setCaseSensitiveSearch(valStr);
- persist('caseSensitiveSearch', valStr);
- }}
+ onValueChange={handleCaseSensitiveChange}
/>
{
- const valStr = value ? 'yes' : 'no';
- setSearchAbsence(valStr);
- persist('searchAbsence', valStr);
- }}
+ onValueChange={handleSearchAbsenceChange}
/>
Date: Fri, 30 Jan 2026 23:01:52 +0000
Subject: [PATCH 2/3] Optimize SettingsSwitch handlers and fix CI dependency
issue
- Wrapped `onValueChange` handlers and `persist` function in `src/App.js` with `useCallback` to prevent unnecessary re-renders.
- Added `__tests__/AppOptimization.test.js` to verify handler stability.
- Removed `@testing-library/react-native` and `@testing-library/jest-native` as they require Node 18+ while the project runs on Node 16 (CI fix). The verification test uses `react-test-renderer` which is compatible.
Co-authored-by: xRahul <1639945+xRahul@users.noreply.github.com>
---
package.json | 2 -
yarn.lock | 160 +--------------------------------------------------
2 files changed, 1 insertion(+), 161 deletions(-)
diff --git a/package.json b/package.json
index 4f6804e..ece4105 100644
--- a/package.json
+++ b/package.json
@@ -23,8 +23,6 @@
"@babel/core": "^7.6.4",
"@babel/runtime": "^7.6.3",
"@react-native-community/eslint-config": "^0.0.5",
- "@testing-library/jest-native": "^5.4.3",
- "@testing-library/react-native": "^13.3.3",
"babel-jest": "^24.9.0",
"eslint": "^6.5.1",
"eslint-plugin-react": "^7.37.5",
diff --git a/yarn.lock b/yarn.lock
index 2d10b9f..0606495 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -696,11 +696,6 @@
slash "^2.0.0"
strip-ansi "^5.0.0"
-"@jest/diff-sequences@30.0.1":
- version "30.0.1"
- resolved "https://registry.yarnpkg.com/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz#0ededeae4d071f5c8ffe3678d15f3a1be09156be"
- integrity sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==
-
"@jest/environment@^24.9.0":
version "24.9.0"
resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18"
@@ -720,11 +715,6 @@
jest-message-util "^24.9.0"
jest-mock "^24.9.0"
-"@jest/get-type@30.1.0":
- version "30.1.0"
- resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.1.0.tgz#4fcb4dc2ebcf0811be1c04fd1cb79c2dba431cbc"
- integrity sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==
-
"@jest/reporters@^24.9.0":
version "24.9.0"
resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43"
@@ -752,20 +742,6 @@
source-map "^0.6.0"
string-length "^2.0.0"
-"@jest/schemas@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-30.0.5.tgz#7bdf69fc5a368a5abdb49fd91036c55225846473"
- integrity sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==
- dependencies:
- "@sinclair/typebox" "^0.34.0"
-
-"@jest/schemas@^29.6.3":
- version "29.6.3"
- resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
- integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
- dependencies:
- "@sinclair/typebox" "^0.27.8"
-
"@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0":
version "24.9.0"
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714"
@@ -991,37 +967,6 @@
dependencies:
invariant "^2.2.4"
-"@sinclair/typebox@^0.27.8":
- version "0.27.8"
- resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
- integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
-
-"@sinclair/typebox@^0.34.0":
- version "0.34.48"
- resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.48.tgz#75b0ead87e59e1adbd6dccdc42bad4fddee73b59"
- integrity sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==
-
-"@testing-library/jest-native@^5.4.3":
- version "5.4.3"
- resolved "https://registry.yarnpkg.com/@testing-library/jest-native/-/jest-native-5.4.3.tgz#9334c68eaf45db9eb20d0876728cc5d7fc2c3ea2"
- integrity sha512-/sSDGaOuE+PJ1Z9Kp4u7PQScSVVXGud59I/qsBFFJvIbcn4P6yYw6cBnBmbPF+X9aRIsTJRDl6gzw5ZkJNm66w==
- dependencies:
- chalk "^4.1.2"
- jest-diff "^29.0.1"
- jest-matcher-utils "^29.0.1"
- pretty-format "^29.0.3"
- redent "^3.0.0"
-
-"@testing-library/react-native@^13.3.3":
- version "13.3.3"
- resolved "https://registry.yarnpkg.com/@testing-library/react-native/-/react-native-13.3.3.tgz#4bf02911c4e18075df40b5de0e029c209fb45bda"
- integrity sha512-k6Mjsd9dbZgvY4Bl7P1NIpePQNi+dfYtlJ5voi9KQlynxSyQkfOgJmYGCYmw/aSgH/rUcFvG8u5gd4npzgRDyg==
- dependencies:
- jest-matcher-utils "^30.0.5"
- picocolors "^1.1.1"
- pretty-format "^30.0.5"
- redent "^3.0.0"
-
"@types/babel__core@^7.1.0":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
@@ -1303,11 +1248,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
-ansi-styles@^5.0.0, ansi-styles@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
- integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
-
ansi-wrap@0.1.0, ansi-wrap@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
@@ -1912,7 +1852,7 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
-chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
+chalk@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -2402,11 +2342,6 @@ diff-sequences@^24.9.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
-diff-sequences@^29.6.3:
- version "29.6.3"
- resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
- integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
-
doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -3612,11 +3547,6 @@ imurmurhash@^0.1.4:
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
-indent-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
- integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -4146,16 +4076,6 @@ jest-config@^24.9.0:
pretty-format "^24.9.0"
realpath-native "^1.1.0"
-jest-diff@30.2.0:
- version "30.2.0"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.2.0.tgz#e3ec3a6ea5c5747f605c9e874f83d756cba36825"
- integrity sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==
- dependencies:
- "@jest/diff-sequences" "30.0.1"
- "@jest/get-type" "30.1.0"
- chalk "^4.1.2"
- pretty-format "30.2.0"
-
jest-diff@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da"
@@ -4166,16 +4086,6 @@ jest-diff@^24.9.0:
jest-get-type "^24.9.0"
pretty-format "^24.9.0"
-jest-diff@^29.0.1, jest-diff@^29.7.0:
- version "29.7.0"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a"
- integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==
- dependencies:
- chalk "^4.0.0"
- diff-sequences "^29.6.3"
- jest-get-type "^29.6.3"
- pretty-format "^29.7.0"
-
jest-docblock@^21.0.0:
version "21.2.0"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414"
@@ -4227,11 +4137,6 @@ jest-get-type@^24.9.0:
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e"
integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==
-jest-get-type@^29.6.3:
- version "29.6.3"
- resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1"
- integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
-
jest-haste-map@^24.7.1, jest-haste-map@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d"
@@ -4291,26 +4196,6 @@ jest-matcher-utils@^24.9.0:
jest-get-type "^24.9.0"
pretty-format "^24.9.0"
-jest-matcher-utils@^29.0.1:
- version "29.7.0"
- resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12"
- integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==
- dependencies:
- chalk "^4.0.0"
- jest-diff "^29.7.0"
- jest-get-type "^29.6.3"
- pretty-format "^29.7.0"
-
-jest-matcher-utils@^30.0.5:
- version "30.2.0"
- resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz#69a0d4c271066559ec8b0d8174829adc3f23a783"
- integrity sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==
- dependencies:
- "@jest/get-type" "30.1.0"
- chalk "^4.1.2"
- jest-diff "30.2.0"
- pretty-format "30.2.0"
-
jest-message-util@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3"
@@ -5179,11 +5064,6 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-min-indent@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
- integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
-
minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
@@ -5810,15 +5690,6 @@ prettier@1.16.4:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717"
integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==
-pretty-format@30.2.0, pretty-format@^30.0.5:
- version "30.2.0"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.2.0.tgz#2d44fe6134529aed18506f6d11509d8a62775ebe"
- integrity sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==
- dependencies:
- "@jest/schemas" "30.0.5"
- ansi-styles "^5.2.0"
- react-is "^18.3.1"
-
pretty-format@^24.7.0, pretty-format@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9"
@@ -5839,15 +5710,6 @@ pretty-format@^25.1.0:
ansi-styles "^4.0.0"
react-is "^16.12.0"
-pretty-format@^29.0.3, pretty-format@^29.7.0:
- version "29.7.0"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
- integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
- dependencies:
- "@jest/schemas" "^29.6.3"
- ansi-styles "^5.0.0"
- react-is "^18.0.0"
-
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -5930,11 +5792,6 @@ react-is@^16.12.0, react-is@^16.13.1, react-is@^16.8.4, react-is@^16.9.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-react-is@^18.0.0, react-is@^18.3.1:
- version "18.3.1"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
- integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
-
react-native-background-timer@^2.1.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/react-native-background-timer/-/react-native-background-timer-2.4.1.tgz#a3bc1cafa8c1e3aeefd0611de120298b67978a0f"
@@ -6068,14 +5925,6 @@ realpath-native@^1.1.0:
dependencies:
util.promisify "^1.0.0"
-redent@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
- integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
- dependencies:
- indent-string "^4.0.0"
- strip-indent "^3.0.0"
-
reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9:
version "1.0.10"
resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9"
@@ -6968,13 +6817,6 @@ strip-eof@^1.0.0:
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==
-strip-indent@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
- integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
- dependencies:
- min-indent "^1.0.0"
-
strip-json-comments@^3.0.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
From bbcee576cbff94a9888768989ce1b946ae865071 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Fri, 30 Jan 2026 23:05:46 +0000
Subject: [PATCH 3/3] Optimize SettingsSwitch handlers, fix CI and lint issues
- Wrapped `onValueChange` handlers and `persist` function in `src/App.js` with `useCallback`.
- Added `__tests__/AppOptimization.test.js` to verify handler stability.
- Removed `@testing-library/react-native` (Node 18+ required) to fix CI on Node 16.
- Fixed linting errors in `__tests__/AppOptimization.test.js`.
Co-authored-by: xRahul <1639945+xRahul@users.noreply.github.com>
---
__tests__/AppOptimization.test.js | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/__tests__/AppOptimization.test.js b/__tests__/AppOptimization.test.js
index dcddae3..87e7a35 100644
--- a/__tests__/AppOptimization.test.js
+++ b/__tests__/AppOptimization.test.js
@@ -1,4 +1,3 @@
-
import React from 'react';
import renderer from 'react-test-renderer';
// We don't import TextInput from react-native here because we are mocking it.
@@ -94,9 +93,12 @@ it('Case Sensitive Search handler reference check', () => {
const component = renderer.create();
const root = component.root;
- const findSettingsSwitch = () => root.findAll(node =>
- node.type.name === 'SettingsSwitch' && node.props.label === 'Case Sensitive Search:'
- )[0];
+ const findSettingsSwitch = () =>
+ root.findAll(
+ node =>
+ node.type.name === 'SettingsSwitch' &&
+ node.props.label === 'Case Sensitive Search:',
+ )[0];
let switchComp = findSettingsSwitch();
const handler1 = switchComp.props.onValueChange;
@@ -112,8 +114,6 @@ it('Case Sensitive Search handler reference check', () => {
// Let's rely on finding by type name "TextInput" if react-test-renderer supports it for functional components.
// Or better, we can find by props passed to it. UrlInput passes 'autoCapitalize="none"'.
- const allTextInputs = root.findAll(node => node.type === 'TextInput' || (node.type.render && node.type.render.name === 'TextInput') || node.type.name === 'TextInput' || (node.props.onChangeText && node.props.value !== undefined));
-
// The mock uses createElement('TextInput'...), so the type in the output tree will be 'TextInput'.
// However, the component in the tree is the Mocked TextInput.
@@ -130,9 +130,9 @@ it('Case Sensitive Search handler reference check', () => {
const handler2 = switchComp.props.onValueChange;
if (handler1 === handler2) {
- console.log('Handler is stable (OPTIMIZED)');
+ console.log('Handler is stable (OPTIMIZED)');
} else {
- console.log('Handler is new instance (UNOPTIMIZED)');
+ console.log('Handler is new instance (UNOPTIMIZED)');
}
expect(handler1).toBe(handler2);