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);