Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions app/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.4.0)
aws-partitions (1.1150.0)
aws-sdk-core (3.230.0)
aws-partitions (1.1152.0)
aws-sdk-core (3.231.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
bigdecimal
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-kms (1.110.0)
aws-sdk-core (~> 3, >= 3.228.0)
aws-sdk-kms (1.112.0)
aws-sdk-core (~> 3, >= 3.231.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.197.0)
aws-sdk-core (~> 3, >= 3.228.0)
aws-sdk-s3 (1.198.0)
aws-sdk-core (~> 3, >= 3.231.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
Expand Down Expand Up @@ -99,7 +99,7 @@ GEM
drb (2.2.3)
emoji_regex (3.2.3)
escape (0.0.4)
ethon (0.17.0)
ethon (0.15.0)
ffi (>= 1.15.0)
excon (0.112.0)
faraday (1.10.4)
Expand Down Expand Up @@ -256,17 +256,17 @@ GEM
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.4.1)
rexml (3.4.2)
rouge (3.28.0)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)
rubyzip (2.4.1)
securerandom (0.4.1)
security (0.1.5)
signet (0.20.0)
signet (0.21.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
jwt (>= 1.5, < 4.0)
multi_json (~> 1.10)
simctl (1.6.10)
CFPropertyList
Expand All @@ -280,8 +280,8 @@ GEM
tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
typhoeus (1.4.1)
ethon (>= 0.9.0)
typhoeus (1.5.0)
ethon (>= 0.9.0, < 0.16.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
Expand Down
3 changes: 2 additions & 1 deletion app/android/react-native-passport-reader/index.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const DATE_REGEX = /^\d{6}$/

module.exports = {
...RNPassportReader,
scan
scan,
reset: RNPassportReader.reset
}

function scan({ documentNumber, dateOfBirth, dateOfExpiry, canNumber, useCan, quality=1 }) {
Expand Down
130 changes: 65 additions & 65 deletions app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2192,7 +2192,7 @@ SPEC CHECKSUMS:
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
hermes-engine: ea92f60f37dba025e293cbe4b4a548fd26b610a0
lottie-ios: a881093fab623c467d3bce374367755c272bdd59
lottie-react-native: d97e225bb686cf6ddda429229b370faa9599d584
lottie-react-native: b0dc69202923f4baf341b360ab636f742b84a36a
Mixpanel-swift: e9bef28a9648faff384d5ba6f48ecc2787eb24c0
nanopb: 438bc412db1928dac798aa6fd75726007be04262
NFCPassportReader: 48873f856f91215dbfa1eaaec20eae639672862e
Expand All @@ -2206,80 +2206,80 @@ SPEC CHECKSUMS:
RCTTypeSafety: 28e24a6e44f5cbf912c66dde6ab7e07d1059a205
React: c2830fa483b0334bda284e46a8579ebbe0c5447e
React-callinvoker: 4aecde929540c26b841a4493f70ebf6016691eb8
React-Core: 9c059899f00d46b5cec3ed79251f77d9c469553d
React-CoreModules: 9fac2d31803c0ed03e4ddaa17f1481714f8633a5
React-cxxreact: a979810a3ca4045ceb09407a17563046a7f71494
React-Core: 32a581847d74ce9b5f51d9d11a4e4d132ad61553
React-CoreModules: f53e0674e1747fa41c83bc970e82add97b14ad87
React-cxxreact: 86f3b1692081fd954a0cb27cc90d14674645b64b
React-debug: 7e346b6eeacd2ee1118a0ee7d39f613b428b4be8
React-defaultsnativemodule: 02b3b73698aca4f8ebfe03e3802bbb8eafb30d6c
React-domnativemodule: 90e3bc5a3e57b367b9787c78a39d7e8dc15cb3b0
React-Fabric: 7e3f79f77929338739d4f6936ecc12cca23644ac
React-FabricComponents: ba910350959d665f6335bdf6cf6347e99661cdac
React-FabricImage: df5337c9b500542ce744c98327625c420dcd1256
React-defaultsnativemodule: 5ab6844adce01f0e52671eaa6d806e2214bbfc44
React-domnativemodule: 448609757e37684cf407cda13d1f6c47deec44cf
React-Fabric: bfef5f9db01f81b73eed5a58fe1e46949c0c665e
React-FabricComponents: 4e845f93a35050a7c0f9dac7805caa62552be939
React-FabricImage: 3478af0ed02c8728680b23f2dd890e59069856ea
React-featureflags: 4c45b3c06f9a124d2598aff495bfc59470f40597
React-featureflagsnativemodule: daee66dc32dd85a16bfd912911cc33fc7d50542d
React-graphics: a2e6209991a191c94405a234460e05291fa986b9
React-hermes: 2069b08e965e48b7f8aa2c0ca0a2f383349ed55d
React-idlecallbacksnativemodule: 8e1d156b4e47cc6a5f80f53869131417979f7c64
React-ImageManager: 17772f78d93539a1a10901b5f537031772fa930c
React-jserrorhandler: 62af5111f6444688182a5850d4b584cbc0c5d6a8
React-jsi: d68f1d516e5120a510afe356647a6a1e1f98f2db
React-jsiexecutor: 6366a08a0fc01c9b65736f8deacd47c4a397912a
React-jsinspector: e21448249ea4a247f1b5786089e3cfe63d5c0111
React-jsitracing: dab78a74a581f63320604c9de4ab9039209e0501
React-logger: d79b704bf215af194f5213a6b7deec50ba8e6a9b
React-Mapbuffer: 42c779748af341935a63ad8831723b8cb1e97830
React-microtasksnativemodule: fc15e6b9e8cc5a99d1cfa0f31c454c4c3de4e7ae
react-native-app-auth: 149f01d2c824758453c9e7815217ded451974683
react-native-biometrics: 352e5a794bfffc46a0c86725ea7dc62deb085bdc
react-native-cloud-storage: 9343984544441a394b72d79de845640e3abfbc45
react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06
react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac
react-native-nfc-manager: 5213321cf6c18d879c8092c0bf56806b771ec5ac
react-native-safe-area-context: 657def25b5590dfbde705aec2925b06725f27450
react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261
React-featureflagsnativemodule: 1c482a7ea0e69330cc59895192a73a2f6f737c33
React-graphics: eb61d404819486a2d9335c043a967a0c4b8ca743
React-hermes: cad69ee9a53870cc38e5386889aa7ea81c75b6a1
React-idlecallbacksnativemodule: 1e3f0212792ace82cc6f3b91f53f5d034f533acc
React-ImageManager: 6652c4cc3de260b5269d58277de383cacd53a234
React-jserrorhandler: 552c5fcd2ee64307c568734b965ea082e1be25cf
React-jsi: bc1f6073e203fb540edd6d26f926ad041809b443
React-jsiexecutor: 1e8fc70dd9614c3e9d5c3c876b2ea3cd1d931ee4
React-jsinspector: 11cf0ade960351b76217a16e31418b9d7f881513
React-jsitracing: e512a1023a25de831b51be1c773caa6036125a44
React-logger: 80d87daf2f98bf95ab668b79062c1e0c3f0c2f8a
React-Mapbuffer: b2642edd9be75d51ead8cda109c986665eae09cf
React-microtasksnativemodule: 94f7e35c4984282f04f946fb1be1d008aff4bdf0
react-native-app-auth: eb42594042a25455119a8c57194b4fd25b9352f4
react-native-biometrics: 43ed5b828646a7862dbc7945556446be00798e7d
react-native-cloud-storage: eeffe84e54f693bd2c6cdda098f006039ee8bdf9
react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
react-native-nfc-manager: a280ef94cd4871a471b052f0dc70381cf1223049
react-native-safe-area-context: 827032edf27079702cbd006f11dc79451a2d744b
react-native-sqlite-storage: 0c84826214baaa498796c7e46a5ccc9a82e114ed
React-nativeconfig: 31072ab0146e643594f6959c7f970a04b6c9ddd0
React-NativeModulesApple: f49bb0befd8650ac3ff8fc2684072b16c09bf478
React-NativeModulesApple: 356d0eb7e3b79603e9d611cd3bac658a998c71db
React-perflogger: 59e1a3182dca2cee7b9f1f7aab204018d46d1914
React-performancetimeline: 3d70a278cc3344def506e97aff3640e658656110
React-performancetimeline: 2bf8625ff44f482cba84e48e4ab21dee405d68cd
React-RCTActionSheet: d80e68d3baa163e4012a47c1f42ddd8bcd9672cc
React-RCTAnimation: bde981f6bd7f8493696564da9b3bd05721d3b3cc
React-RCTAppDelegate: 0176615c51476c88212bf3edbafb840d39ea7631
React-RCTBlob: 520a0382bf8e89b9153d60e3c6293e51615834e9
React-RCTFabric: f04c63400264f44a252ebba62dfb8cff8e5bd9b4
React-RCTImage: 90448d2882464af6015ed57c98f463f8748be465
React-RCTLinking: 1bd95d0a704c271d21d758e0f0388cced768d77d
React-RCTNetwork: 218af6e63eb9b47935cc5a775b7a1396cf10ff91
React-RCTSettings: e10b8e42b0fce8a70fbf169de32a2ae03243ef6b
React-RCTText: e7bf9f4997a1a0b45c052d4ad9a0fe653061cf29
React-RCTVibration: 5b70b7f11e48d1c57e0d4832c2097478adbabe93
React-RCTAnimation: 051f0781709c5ed80ba8aa2b421dfb1d72a03162
React-RCTAppDelegate: 106d225d076988b06aa4834e68d1ab754f40cacf
React-RCTBlob: 895eaf8bca2e76ee1c95b479235c6ccebe586fc6
React-RCTFabric: 1d736a1f539ae72dcefd473f964f532a0e658309
React-RCTImage: b73149c0cd54b641dba2d6250aaf168fee784d9f
React-RCTLinking: 23e519712285427e50372fbc6e0265d422abf462
React-RCTNetwork: a5d06d122588031989115f293654b13353753630
React-RCTSettings: 87d03b5d94e6eadd1e8c1d16a62f790751aafb55
React-RCTText: 75e9dd39684f4bcd1836134ac2348efaca7437b3
React-RCTVibration: 033c161fe875e6fa096d0d9733c2e2501682e3d4
React-rendererconsistency: 35cef4bc4724194c544b6e5e2bd9b3f7aff52082
React-rendererdebug: 9b1a6a2d4f8086a438f75f28350ccba16b7b706a
React-rendererdebug: 4e801e9f8d16d21877565dca2845a2e56202b8c6
React-rncore: 2c7c94d6e92db0850549223eb2fa8272e0942ac2
React-RuntimeApple: 90f1dfd648cae853afb60eb13a9579c942b2df33
React-RuntimeCore: 355ee6b0c3a7f4e66afe44f757a7585fc6008c9e
React-RuntimeApple: ff845be41902d053f1348541a647e669a2f509f4
React-RuntimeCore: 8b30ac97af1bdd5d2622ee2a75becf1e552b89c7
React-runtimeexecutor: ea90d8e3a9e0f4326939858dafc6ab17c031a5d3
React-RuntimeHermes: 13d33b49355663bdbbca6719abcbc4f534f274b9
React-runtimescheduler: 1132af91176dcc8ac566b10f7b57b10873125564
React-utils: d1bae5ac6a5fb94a772ebfc7a7e1aba3a6706a3a
ReactCodegen: 18aa2cb03418f6ea9f318785e339128accab12f0
ReactCommon: 1007c09a406a451ddbd874e51511aa541d6034f6
RNCAsyncStorage: 23e56519cc41d3bade3c8d4479f7760cb1c11996
RNCClipboard: 60fed4b71560d7bfe40e9d35dea9762b024da86d
RNDeviceInfo: feea80a690d2bde1fe51461cf548039258bd03f2
RNFBApp: dd35ba8340b89c36e42c4c137915c01d3c792143
RNFBMessaging: c8d34d9ad44a3258a77e548bba6dc3561af7cf2d
RNFBRemoteConfig: 7e219246c63c47f56cfe07eee1a044ed298261c8
RNGestureHandler: a52601cdccc6213650ad4a9eb2911360d13f4447
RNKeychain: a58690e4450434e8e900ed47032fa58c59cc5570
RNLocalize: 06991b9c31e7a898a9fa6ddb204ce0f53a967248
RNReactNativeHapticFeedback: 293365e4df1faef21be8b8efe22c7b217c5e695a
RNScreens: eee0beadb969b9c1c0ceca4e89744c8d69d782e0
RNSentry: 9ecfddd2650b783586da93871ca87561c61facf8
RNSVG: 28b61fc4856abe8eaea46794419f848986ee7e80
segment-analytics-react-native: de13f89e52d49c1f4ed33ba86ae24f055722a643
React-RuntimeHermes: 6a5be21d1f8a603989d8734a0021c0534df23dd9
React-runtimescheduler: 21ad58e37e35a132f2a5ecad78e68ea7fbc8e2ba
React-utils: 0dbea1179726ad65a1b13470a3f3c73da98f4496
ReactCodegen: 688a0970a2fc6a4481718d8ca86ff504f2a21723
ReactCommon: 23eed247b5c8e57b59a823ce209353883da61dd2
RNCAsyncStorage: b44e8a4e798c3e1f56bffccd0f591f674fb9198f
RNCClipboard: 4abb037e8fe3b98a952564c9e0474f91c492df6d
RNDeviceInfo: d863506092aef7e7af3a1c350c913d867d795047
RNFBApp: 4097f75673f8b42a7cd1ba17e6ea85a94b45e4d1
RNFBMessaging: 92325b0d5619ac90ef023a23cfd16fd3b91d0a88
RNFBRemoteConfig: a569bacaa410acfcaba769370e53a787f80fd13b
RNGestureHandler: 4a7cce66468343e82d601e8f6cdc0148b18b6c6b
RNKeychain: 42a94ceb08a6c33db453bc34cae46458b6a14a08
RNLocalize: 15463c4d79c7da45230064b4adcf5e9bb984667e
RNReactNativeHapticFeedback: c873497ad3f9fa80447baa18daa9474e671d24bf
RNScreens: 584a35ba1a56a628fc564216b0b6f7b9f070c282
RNSentry: d66e96602d8e05b7789e3e095aca53a9f21dab55
RNSVG: e3ad69848b6357587545e0a49628b1148acf082c
segment-analytics-react-native: 5c3e8a4ee6d7532a011ed862d7c7d4fb5e5303e2
Sentry: 2cbbe3592f30050c60e916c63c7f5a2fa584005e
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
sovran-react-native: eec37f82e4429f0e3661f46aaf4fcd85d1b54f60
sovran-react-native: a3ad3f8ff90c2002b2aa9790001a78b0b0a38594
SwiftQRScanner: e85a25f9b843e9231dab89a96e441472fe54a724
SwiftyTesseract: 1f3d96668ae92dc2208d9842c8a59bea9fad2cbb
Yoga: b05994d1933f507b0a28ceaa4fdb968dc18da178
Expand Down
24 changes: 23 additions & 1 deletion app/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ require('react-native-gesture-handler/jestSetup');

jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');

jest.mock('@env', () => ({
ENABLE_DEBUG_LOGS: 'false',
MIXPANEL_NFC_PROJECT_TOKEN: 'test-token',
}));

global.FileReader = class {
constructor() {
this.onload = null;
Expand Down Expand Up @@ -197,13 +202,30 @@ jest.mock('react-native-nfc-manager', () => ({
// Mock react-native-passport-reader
jest.mock('react-native-passport-reader', () => ({
default: {
initialize: jest.fn(),
configure: jest.fn(),
scanPassport: jest.fn(),
readPassport: jest.fn(),
cancelPassportRead: jest.fn(),
trackEvent: jest.fn(),
flush: jest.fn(),
reset: jest.fn(),
},
}));
Comment on lines 208 to 218
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Mock parity with types: add scan alias to match d.ts and potential callsites

The default export for react-native-passport-reader only exposes scanPassport, while the d.ts (and likely some callsites) reference scan. This will cause test failures or undefined calls in environments that import the default module instead of NativeModules.

Apply this diff to add a scan alias:

 jest.mock('react-native-passport-reader', () => ({
   default: {
     configure: jest.fn(),
-    scanPassport: jest.fn(),
+    scanPassport: jest.fn(),
+    // Alias to align with TS types/callsites
+    scan: jest.fn(),
     readPassport: jest.fn(),
     cancelPassportRead: jest.fn(),
     trackEvent: jest.fn(),
     flush: jest.fn(),
     reset: jest.fn(),
   },
 }));

Run to spot any lingering scanPassport( vs scan( mismatches:


🏁 Script executed:

#!/bin/bash
rg -nP -C2 --type=ts --type=tsx '\bPassportReader\b.*\bscan(Passport)?\s*\('
rg -nP -C2 --type=ts --type=tsx '\bNativeModules\.PassportReader\b.*\bscan(Passport)?\s*\('

Length of output: 228


🏁 Script executed:

#!/bin/bash
# Search for both scanPassport and scan callsites across TS/TSX/JS/JSX files
rg -nP -C2 '\bPassportReader\b.*\bscan(?:Passport)?\s*\(' -g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx'
rg -nP -C2 '\bNativeModules\.PassportReader\b.*\bscan(?:Passport)?\s*\(' -g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx'

Length of output: 1200


Add scan alias to the PassportReader mock to cover Android callsites

Your Android scanner helper calls PassportReader.scan(…) (app/src/utils/nfcScanner.ts line 128), but your Jest setup only mocks scanPassport. Without a scan mock, tests hitting scanAndroid will fail with undefined is not a function.

Apply this diff in app/jest.setup.js (around lines 203–213):

 jest.mock('react-native-passport-reader', () => ({
   default: {
     configure: jest.fn(),
     scanPassport: jest.fn(),
+    // Alias to align with TS types/callsites (e.g. scanAndroid)
+    scan: jest.fn(),
     readPassport: jest.fn(),
     cancelPassportRead: jest.fn(),
     trackEvent: jest.fn(),
     flush: jest.fn(),
     reset: jest.fn(),
   },
 }));

— without this, any PassportReader.scan(...) calls will be unmocked and break your Android tests.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
jest.mock('react-native-passport-reader', () => ({
default: {
initialize: jest.fn(),
configure: jest.fn(),
scanPassport: jest.fn(),
readPassport: jest.fn(),
cancelPassportRead: jest.fn(),
trackEvent: jest.fn(),
flush: jest.fn(),
reset: jest.fn(),
},
}));
jest.mock('react-native-passport-reader', () => ({
default: {
configure: jest.fn(),
scanPassport: jest.fn(),
// Alias to align with TS types/callsites (e.g. scanAndroid)
scan: jest.fn(),
readPassport: jest.fn(),
cancelPassportRead: jest.fn(),
trackEvent: jest.fn(),
flush: jest.fn(),
reset: jest.fn(),
},
}));
🤖 Prompt for AI Agents
In app/jest.setup.js around lines 203 to 213, the PassportReader mock only
provides scanPassport/readPassport/etc. but not the Android alias scan, so tests
calling PassportReader.scan(...) will fail; update the mock to add a scan
property that points to the same jest.fn() used by scanPassport (i.e., add scan:
jest.fn() or set scan: mock.scanPassport) so PassportReader.scan(...) is defined
and uses the existing mock behavior.


const { NativeModules } = require('react-native');

NativeModules.PassportReader = {
configure: jest.fn(),
scanPassport: jest.fn(),
trackEvent: jest.fn(),
flush: jest.fn(),
};

Comment on lines +220 to +228
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Keep NativeModules mock consistent and complete

NativeModules.PassportReader mirrors only some methods. To avoid drift between the default export and NativeModules, provide a scan alias here too (and, ideally, share the same jest.fn where practical).

Apply this diff:

 const { NativeModules } = require('react-native');

 NativeModules.PassportReader = {
   configure: jest.fn(),
-  scanPassport: jest.fn(),
+  scanPassport: jest.fn(),
+  // Alias for parity with d.ts and default export
+  scan: jest.fn(),
   trackEvent: jest.fn(),
   flush: jest.fn(),
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { NativeModules } = require('react-native');
NativeModules.PassportReader = {
configure: jest.fn(),
scanPassport: jest.fn(),
trackEvent: jest.fn(),
flush: jest.fn(),
};
const { NativeModules } = require('react-native');
NativeModules.PassportReader = {
configure: jest.fn(),
scanPassport: jest.fn(),
// Alias for parity with d.ts and default export
scan: jest.fn(),
trackEvent: jest.fn(),
flush: jest.fn(),
};
🤖 Prompt for AI Agents
In app/jest.setup.js around lines 215 to 223, NativeModules.PassportReader
defines configure, scanPassport, trackEvent, and flush but is missing the scan
alias; update the mock to include scan and make it reference the same jest.fn()
as scanPassport (i.e., create one jest.fn for the passport scan and assign it to
both scanPassport and scan) so the mock stays consistent and methods remain in
sync.

jest.mock('@react-native-community/netinfo', () => ({
addEventListener: jest.fn(() => jest.fn()),
fetch: jest.fn(() => Promise.resolve({ isConnected: true })),
}));
Comment on lines +229 to +232
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Duplicate NetInfo mock overrides earlier one (breaks useNetInfo/behavior)

This second jest.mock('@react-native-community/netinfo', ...) overrides the earlier mock (Lines 147–160), dropping useNetInfo and changing method shapes. That can cause test flakiness or crashes.

Apply this diff to remove the duplicate:

-jest.mock('@react-native-community/netinfo', () => ({
-  addEventListener: jest.fn(() => jest.fn()),
-  fetch: jest.fn(() => Promise.resolve({ isConnected: true })),
-}));

Then, update the first NetInfo mock (Lines 147–160) to return an unsubscribe from addEventListener and a resolved value from fetch:

// In the first mock block (existing):
addEventListener: jest.fn(() => jest.fn()), // returns unsubscribe
fetch: jest.fn().mockResolvedValue({ isConnected: true, isInternetReachable: true }),

If you want, I can push a combined single mock that covers useNetInfo, addEventListener, and fetch consistently.

🤖 Prompt for AI Agents
In app/jest.setup.js around lines 224–227 there is a duplicate
jest.mock('@react-native-community/netinfo') that overrides the earlier mock and
drops useNetInfo/changes method shapes; remove this second mock block and
instead update the first mock block (around lines 147–160) so addEventListener
returns an unsubscribe function (e.g., jest.fn(() => jest.fn())) and fetch is a
resolved promise (e.g., jest.fn().mockResolvedValue({ isConnected: true,
isInternetReachable: true })), ensuring the single mock covers useNetInfo,
addEventListener, and fetch consistently.


// Mock @stablelib packages
jest.mock('@stablelib/cbor', () => ({
encode: jest.fn(),
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"mobile-local-deploy": "FORCE_UPLOAD_LOCAL_DEV=true node scripts/mobile-deploy-confirm.cjs both",
"mobile-local-deploy:android": "FORCE_UPLOAD_LOCAL_DEV=true node scripts/mobile-deploy-confirm.cjs android",
"mobile-local-deploy:ios": "FORCE_UPLOAD_LOCAL_DEV=true node scripts/mobile-deploy-confirm.cjs ios",
"nice": "yarn imports:fix && yarn lint:fix && yarn fmt:fix",
"nice": "yarn build:deps && yarn imports:fix && yarn lint:fix && yarn fmt:fix",
"reinstall": "yarn clean && yarn install && yarn install-app",
"release": "./scripts/release.sh",
"release:major": "./scripts/release.sh major",
Expand Down
5 changes: 4 additions & 1 deletion app/src/Segment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
createClient,
EventPlugin,
PluginType,
StartupFlushPolicy,
} from '@segment/analytics-react-native';

import '@ethersproject/shims';
Expand Down Expand Up @@ -48,14 +49,16 @@ export const createSegmentClient = () => {
return segmentClient;
}

const flushPolicies = [new BackgroundFlushPolicy()];
const flushPolicies = [new BackgroundFlushPolicy(), new StartupFlushPolicy()];

const client = createClient({
writeKey: SEGMENT_KEY,
trackAppLifecycleEvents: true,
trackDeepLinks: true,
debug: __DEV__,
collectDeviceId: false,
flushAt: 20, // Flush every 20 events
flushInterval: 20000, // Flush every 20 seconds
defaultSettings: {
integrations: {
'Segment.io': {
Expand Down
12 changes: 7 additions & 5 deletions app/src/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import React, { Component } from 'react';
import { Text, View } from 'react-native';

import { captureException } from '@/Sentry';
import analytics from '@/utils/analytics';

const { flush: flushAnalytics } = analytics();
import { flushAllAnalytics, trackNfcEvent } from '@/utils/analytics';

interface Props {
children: React.ReactNode;
Expand All @@ -30,8 +28,12 @@ class ErrorBoundary extends Component<Props, State> {
}

componentDidCatch(error: Error, info: ErrorInfo) {
// Flush analytics before the app crashes
flushAnalytics();
trackNfcEvent('error_boundary', {
message: error.message,
stack: info.componentStack,
});
// Flush all analytics before the app crashes
flushAllAnalytics();
captureException(error, {
componentStack: info.componentStack,
errorBoundary: true,
Expand Down
13 changes: 13 additions & 0 deletions app/src/mocks/react-native-passport-reader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.

// Web mock for react-native-passport-reader
export const reset = async () => {
// No-op for web
return Promise.resolve();
};

export const scan = async () => {
throw new Error('NFC scanning is not supported on web');
};
Loading
Loading