diff --git a/android/gradle.properties b/android/gradle.properties index 2496886ca..35236542b 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -31,7 +31,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. -newArchEnabled=false +newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. diff --git a/e2e/aiCamera.e2e.js b/e2e/aiCamera.e2e.js index df3fda088..5c033b5ba 100644 --- a/e2e/aiCamera.e2e.js +++ b/e2e/aiCamera.e2e.js @@ -35,9 +35,6 @@ describe( "AICamera", () => { await waitFor( aiCameraButton ).toBeVisible().withTimeout( TIMEOUT ); await aiCameraButton.tap(); - // Check that the camera screen is visible - const cameraContainer = element( by.id( "CameraWithDevice" ) ); - await waitFor( cameraContainer ).toBeVisible().withTimeout( TIMEOUT ); // Check that the mocked cv suggestion is visible const taxonResult = element( by.id( "AICamera.taxa.51779" ) ); await waitFor( taxonResult ).toBeVisible().withTimeout( TIMEOUT ); diff --git a/e2e/sharedFlows/closeOnboarding.js b/e2e/sharedFlows/closeOnboarding.js index 24a6da2b4..7cd8aa171 100644 --- a/e2e/sharedFlows/closeOnboarding.js +++ b/e2e/sharedFlows/closeOnboarding.js @@ -7,9 +7,7 @@ import { const VISIBILITY_TIMEOUT = 10_000; export default async function closeOnboarding( ) { - const closeOnboardingButton = element( - by.label( "Close" ).withAncestor( by.id( "OnboardingCarousel" ) ) - ); + const closeOnboardingButton = element( by.label( "Close" ) ); await waitFor( closeOnboardingButton ).toBeVisible( ).withTimeout( VISIBILITY_TIMEOUT ); return closeOnboardingButton.tap( ); } diff --git a/e2e/sharedFlows/deleteObservation.js b/e2e/sharedFlows/deleteObservation.js index f2e46af2b..75a277e3f 100644 --- a/e2e/sharedFlows/deleteObservation.js +++ b/e2e/sharedFlows/deleteObservation.js @@ -2,29 +2,31 @@ import { by, element, expect, waitFor } from "detox"; +const TIMEOUT = 10_000; + // Start this on ObsEdit or ObsDetails via uploaded = false / true export default async function deleteObservation( options = { uploaded: false } ) { if ( options.uploaded ) { const editButton = element( by.id( "ObsDetail.editButton" ) ); - await waitFor( editButton ).toBeVisible().withTimeout( 10000 ); + await waitFor( editButton ).toBeVisible().withTimeout( TIMEOUT ); // Navigate to the edit screen await editButton.tap(); } // Check that the edit screen is visible await waitFor( element( by.text( "EVIDENCE" ) ) ) .toBeVisible() - .withTimeout( 10000 ); + .withTimeout( TIMEOUT ); // Press header kebab menu const headerKebabMenu = element( by.id( "KebabMenu.Button" ) ); await expect( headerKebabMenu ).toBeVisible(); await headerKebabMenu.tap(); // Press delete observation const deleteObservationMenuItem = element( by.id( "Header.delete-observation" ) ); - await waitFor( deleteObservationMenuItem ).toBeVisible().withTimeout( 10000 ); + await waitFor( deleteObservationMenuItem ).toBeVisible().withTimeout( TIMEOUT ); await deleteObservationMenuItem.tap(); // Check that the delete button is visible const deleteObservationButton = element( by.text( "DELETE" ) ); - await waitFor( deleteObservationButton ).toBeVisible().withTimeout( 10000 ); + await waitFor( deleteObservationButton ).toBeVisible().withTimeout( TIMEOUT ); // Press delete observation await deleteObservationButton.tap(); } diff --git a/e2e/sharedFlows/dismissAnnouncements.js b/e2e/sharedFlows/dismissAnnouncements.js index 5281b9527..a05e247a5 100644 --- a/e2e/sharedFlows/dismissAnnouncements.js +++ b/e2e/sharedFlows/dismissAnnouncements.js @@ -2,12 +2,14 @@ import { by, element, waitFor } from "detox"; +const TIMEOUT = 10_000; + export default async function dismissAnnouncements() { try { // wait briefly to see if the announcement appears - await waitFor( - element( by.id( "announcements-container" ) ) - ).toBeVisible().withTimeout( 1000 ); + await waitFor( element( by.id( "announcements-container" ) ) ) + .toBeVisible() + .withTimeout( TIMEOUT ); // if we get here, the announcement is visible, so dismiss it await element( by.id( "announcements-dismiss" ) ).tap(); diff --git a/e2e/sharedFlows/signIn.js b/e2e/sharedFlows/signIn.js index 6de7cbd45..0ae767c23 100644 --- a/e2e/sharedFlows/signIn.js +++ b/e2e/sharedFlows/signIn.js @@ -6,6 +6,8 @@ import Config from "react-native-config-node"; import dismissAnnouncements from "./dismissAnnouncements"; import switchPowerMode from "./switchPowerMode"; +const TIMEOUT = 10_000; + export default async function signIn() { /* Switch UI to power user mode @@ -13,19 +15,19 @@ export default async function signIn() { await switchPowerMode(); // Find the Menu item from tabs const openDrawerMenuItem = element( by.id( "OPEN_DRAWER" ) ); - await waitFor( openDrawerMenuItem ).toBeVisible().withTimeout( 10000 ); + await waitFor( openDrawerMenuItem ).toBeVisible().withTimeout( TIMEOUT ); await expect( openDrawerMenuItem ).toBeVisible(); - await element( by.id( "OPEN_DRAWER" ) ).tap(); + await element( by.id( "OPEN_DRAWER" ) ).tap( { x: 0, y: 0 } ); // Tap the Log-In menu item // TODO: consider this a temporary solution as it only checks for the drawer-top-banner // which can be a login prompt or the logged in user's details. If the user is already // logged in, this should fail instead. const loginMenuItem = element( by.id( "drawer-top-banner" ) ); - await waitFor( loginMenuItem ).toBeVisible().withTimeout( 10000 ); + await waitFor( loginMenuItem ).toBeVisible().withTimeout( TIMEOUT ); await expect( loginMenuItem ).toBeVisible(); await element( by.id( "drawer-top-banner" ) ).tap(); const usernameInput = element( by.id( "Login.email" ) ); - await waitFor( usernameInput ).toBeVisible().withTimeout( 10000 ); + await waitFor( usernameInput ).toBeVisible().withTimeout( TIMEOUT ); await expect( usernameInput ).toBeVisible(); await element( by.id( "Login.email" ) ).tap(); await element( by.id( "Login.email" ) ).typeText( Config.E2E_TEST_USERNAME ); @@ -37,7 +39,7 @@ export default async function signIn() { await expect( loginButton ).toBeVisible(); await element( by.id( "Login.loginButton" ) ).tap(); const username = element( by.text( `${Config.E2E_TEST_USERNAME}` ) ).atIndex( 1 ); - await waitFor( username ).toBeVisible().withTimeout( 10000 ); + await waitFor( username ).toBeVisible().withTimeout( TIMEOUT ); await expect( username ).toBeVisible(); /* diff --git a/e2e/sharedFlows/switchPowerMode.js b/e2e/sharedFlows/switchPowerMode.js index 0f396160e..754af5d87 100644 --- a/e2e/sharedFlows/switchPowerMode.js +++ b/e2e/sharedFlows/switchPowerMode.js @@ -2,16 +2,18 @@ import { by, element, waitFor } from "detox"; +const TIMEOUT = 10_000; + export default async function switchPowerMode() { const drawerButton = element( by.id( "OPEN_DRAWER" ) ); - await waitFor( drawerButton ).toBeVisible().withTimeout( 10000 ); - await drawerButton.tap(); + await waitFor( drawerButton ).toBeVisible().withTimeout( TIMEOUT ); + await drawerButton.tap( { x: 0, y: 0 } ); // Tap the settings drawer menu item const settingsDrawerMenuItem = element( by.id( "settings" ) ); - await waitFor( settingsDrawerMenuItem ).toBeVisible().withTimeout( 10000 ); + await waitFor( settingsDrawerMenuItem ).toBeVisible().withTimeout( TIMEOUT ); await settingsDrawerMenuItem.tap(); // Switch settings to advanced interface mode const advancedInterfaceSwitch = element( by.id( "advanced-interface-switch.switch" ) ); - await waitFor( advancedInterfaceSwitch ).toBeVisible().withTimeout( 10000 ); + await waitFor( advancedInterfaceSwitch ).toBeVisible().withTimeout( TIMEOUT ); await advancedInterfaceSwitch.tap(); } diff --git a/e2e/sharedFlows/uploadObservation.js b/e2e/sharedFlows/uploadObservation.js index 3934ff026..908089fb7 100644 --- a/e2e/sharedFlows/uploadObservation.js +++ b/e2e/sharedFlows/uploadObservation.js @@ -5,17 +5,19 @@ import { // This needs to be a relative path for the e2e-mock version to be used import { CHUCKS_PAD } from "../../src/appConstants/e2e"; +const TIMEOUT = 10_000; + // Upload or save an observation export default async function uploadObservation( options = { upload: false } ) { // Start this on ObsEdit // Check that the new observation screen is visible const newObservationText = element( by.id( "new-observation-text" ) ); - await waitFor( newObservationText ).toBeVisible().withTimeout( 10000 ); + await waitFor( newObservationText ).toBeVisible().withTimeout( TIMEOUT ); // Ensure the location from the e2e-mock is being used so we don't end up // with tests flaking out due to time zone issues const pattern = new RegExp( `.*${CHUCKS_PAD.latitude.toFixed( 4 )}.*` ); const locationText = element( by.text( pattern ) ); - await waitFor( locationText ).toBeVisible().withTimeout( 10000 ); + await waitFor( locationText ).toBeVisible().withTimeout( TIMEOUT ); if ( options.upload ) { // Press Upload now button const uploadNowButton = element( by.id( "ObsEdit.uploadButton" ) ); diff --git a/e2e/signedIn.e2e.js b/e2e/signedIn.e2e.js index a3b205608..91fa4a6bb 100644 --- a/e2e/signedIn.e2e.js +++ b/e2e/signedIn.e2e.js @@ -8,6 +8,8 @@ import deleteObservation from "./sharedFlows/deleteObservation"; import signIn from "./sharedFlows/signIn"; import uploadObservation from "./sharedFlows/uploadObservation"; +const TIMEOUT = 10_000; + function delay( ms ) { return new Promise( resolve => { setTimeout( resolve, ms ); } ); } @@ -19,7 +21,7 @@ describe( "Signed in user", () => { async function createAndUploadObservation( options = { upload: false } ) { const addObsButton = element( by.id( "add-obs-button" ) ); - await waitFor( addObsButton ).toBeVisible().withTimeout( 10000 ); + await waitFor( addObsButton ).toBeVisible().withTimeout( TIMEOUT ); await addObsButton.tap(); await expect( element( by.id( "identify-text" ) ) ).toBeVisible(); // Observe without evidence @@ -31,24 +33,14 @@ describe( "Signed in user", () => { await uploadObservation( options ); - // Check that the comments count component for the obs we just created is - // visible. Since it just saved and there's an animation the runs before - // this component becomes visible, and there may be other observations in - // the list, we need to wait for the right CommentsCount component to be - // visible const obsListItem = element( by.id( /MyObservations\.obsListItem\..*/ ) ).atIndex( 0 ); const obsListItemAttributes = await obsListItem.getAttributes( ); const uuid = obsListItemAttributes.elements ? obsListItemAttributes.elements[0].identifier.split( "." ).pop( ) : obsListItemAttributes.identifier.split( "." ).pop( ); - if ( options.upload ) { - const commentCount = element( - by.id( "ObsStatus.commentsCount" ) - .withAncestor( by.id( `MyObservations.obsListItem.${uuid}` ) ) - ); - await waitFor( commentCount ).toBeVisible().withTimeout( 10000 ); - } + const listItem = element( by.id( `MyObservations.obsListItem.${uuid}` ) ); + await waitFor( listItem ).toBeVisible().withTimeout( TIMEOUT ); return uuid; } @@ -58,7 +50,7 @@ describe( "Signed in user", () => { await obsListItem.tap(); await deleteObservation( options ); // Make sure we're back on MyObservations - await waitFor( username ).toBeVisible().withTimeout( 10000 ); + await waitFor( username ).toBeVisible().withTimeout( TIMEOUT ); } it( "should create an observation, add a comment, and delete the observation", async () => { @@ -70,7 +62,7 @@ describe( "Signed in user", () => { // Switch to list view as well const listToggle = element( by.id( "SegmentedButton.list" ) ); - await waitFor( listToggle ).toBeVisible( ).withTimeout( 10000 ); + await waitFor( listToggle ).toBeVisible( ).withTimeout( TIMEOUT ); await listToggle.tap(); /* @@ -88,11 +80,11 @@ describe( "Signed in user", () => { const obsListItem = element( by.id( `MyObservations.obsListItem.${uuid}` ) ); await obsListItem.tap(); const commentButton = element( by.id( "ObsDetail.commentButton" ) ); - await waitFor( commentButton ).toBeVisible().withTimeout( 10000 ); + await waitFor( commentButton ).toBeVisible().withTimeout( TIMEOUT ); await commentButton.tap(); // Check that the comment modal is visible const commentModalInput = element( by.id( "TextInputSheet.notes" ) ); - await waitFor( commentModalInput ).toBeVisible().withTimeout( 10000 ); + await waitFor( commentModalInput ).toBeVisible().withTimeout( TIMEOUT ); // Add a comment await commentModalInput.tap(); await commentModalInput.typeText( "This is a comment" ); @@ -105,9 +97,9 @@ describe( "Signed in user", () => { // Check that the comment is visible await element( by.id( `ObsDetails.${uuid}` ) ).scrollTo( "bottom" ); const comment = element( by.text( "This is a comment" ) ); - await waitFor( comment ).toBeVisible().withTimeout( 10000 ); + await waitFor( comment ).toBeVisible().withTimeout( TIMEOUT ); await element( by.id( "header-back-button" ) ).tap( ); - await waitFor( username ).toBeVisible( ).withTimeout( 10000 ); + await waitFor( username ).toBeVisible( ).withTimeout( TIMEOUT ); /* / 4. Delete the two observations without evidence @@ -124,7 +116,7 @@ describe( "Signed in user", () => { // the timing of syncing deletions seems to be different in the actual app versus these // e2e tests, so deleting an observation here still shows the observation // in the list unless this delay( ) is added - await delay( 3000 ); + await delay( 10000 ); await expect( obsListItem ).toBeNotVisible( ); } ); } ); diff --git a/ios/Podfile b/ios/Podfile index 0ac91a284..e12da29d0 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,8 +1,5 @@ # frozen_string_literal: true -# Disable New Architecture -ENV["RCT_NEW_ARCH_ENABLED"] = "0" - # setup instructions from https://www.npmjs.com/package/react-native-permissions def node_require( script ) # Resolve script with node to allow for hoisting diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4f15dd40c..dfbc5c65a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -13,11 +13,29 @@ PODS: - FasterImage (1.4.3): - FasterImage/Nuke (= 1.4.3) - FasterImage/NukeUI (= 1.4.3) + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-RCTFabric + - ReactCommon/turbomodule/core - FasterImage/Nuke (1.4.3): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-RCTFabric + - ReactCommon/turbomodule/core - FasterImage/NukeUI (1.4.3): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-RCTFabric + - ReactCommon/turbomodule/core - FBLazyVector (0.78.3) - fmt (11.0.2) - glog (0.3.5) @@ -32,9 +50,6 @@ PODS: - hermes-engine (0.78.3): - hermes-engine/Pre-built (= 0.78.3) - hermes-engine/Pre-built (0.78.3) - - MMKV (2.2.2): - - MMKVCore (~> 2.2.2) - - MMKVCore (2.2.2) - Mute (0.6.1) - RCT-Folly (2024.11.18.00): - boost @@ -75,6 +90,7 @@ PODS: - React-RCTText (= 0.78.3) - React-RCTVibration (= 0.78.3) - React-callinvoker (0.78.3) + - React-Codegen (0.1.0) - React-Core (0.78.3): - glog - hermes-engine @@ -1292,7 +1308,12 @@ PODS: - react-native-config/App (1.5.3): - React-Core - react-native-exif-reader (0.4.2): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - ReactCommon/turbomodule/core - react-native-geocoder-reborn (0.9.0): - React - react-native-geolocation (3.4.0): @@ -1319,20 +1340,51 @@ PODS: - react-native-get-random-values (1.11.0): - React-Core - react-native-image-picker (7.0.0): - - React-Core + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React + - React-Codegen + - React-RCTFabric + - ReactCommon/turbomodule/core - react-native-image-resizer (3.0.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-keep-awake (1.3.1): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-RCTFabric + - ReactCommon/turbomodule/core - react-native-mail (6.1.1): - React-Core - react-native-maps (1.20.1): - React-Core - - react-native-mmkv (2.12.2): + - react-native-mmkv (3.3.3): - DoubleConversion - glog - hermes-engine - - MMKV (>= 1.3.3) - RCT-Folly (= 2024.11.18.00) - RCTRequired - RCTTypeSafety @@ -1359,7 +1411,71 @@ PODS: - react-native-restart (0.0.27): - React-Core - react-native-safe-area-context (5.5.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - react-native-safe-area-context/common (= 5.5.1) + - react-native-safe-area-context/fabric (= 5.5.1) + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context/common (5.5.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context/fabric (5.5.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - react-native-safe-area-context/common + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-sensitive-info (6.0.0-alpha.9): - React-Core - react-native-slider (4.5.0): @@ -1724,11 +1840,68 @@ PODS: - RNAudioRecorderPlayer (3.6.7): - React-Core - RNCClipboard (1.16.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNCPicker (2.11.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNDateTimePicker (8.4.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNDeviceInfo (14.0.4): - React-Core - RNFlashList (1.8.3): @@ -1776,12 +1949,69 @@ PODS: - ReactCommon/turbomodule/core - Yoga - RNGoogleSignin (13.1.0): + - DoubleConversion + - glog - GoogleSignIn (~> 7.1) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNLocalize (3.5.2): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNPermissions (4.1.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNReanimated (3.19.1): - DoubleConversion - glog @@ -1902,6 +2132,29 @@ PODS: - ReactCommon/turbomodule/core - Yoga - RNScreens (4.13.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNScreens/common (= 4.13.1) + - Yoga + - RNScreens/common (4.13.1): - DoubleConversion - glog - hermes-engine @@ -1945,9 +2198,69 @@ PODS: - ReactCommon/turbomodule/core - Yoga - RNStoreReview (0.4.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNSVG (15.12.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNSVG/common (= 15.12.0) + - Yoga + - RNSVG/common (15.12.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - SocketRocket (0.7.1) - VisionCamera (4.7.2): - VisionCamera/Core (= 4.7.2) @@ -2106,9 +2419,8 @@ SPEC REPOS: - GoogleSignIn - GTMAppAuth - GTMSessionFetcher - - MMKV - - MMKVCore - Mute + - React-Codegen - SocketRocket EXTERNAL SOURCES: @@ -2342,7 +2654,7 @@ SPEC CHECKSUMS: BVLinearGradient: cb006ba232a1f3e4f341bb62c42d1098c284da70 DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6 - FasterImage: 5215480384883bb4a4a7f5655d4d1f8354e96987 + FasterImage: b93c7e32d4d8bf9323429351f1915be9c07c4533 FBLazyVector: e053802577a711add20e45bbbf5dd1180b6ca62e fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8 @@ -2350,8 +2662,6 @@ SPEC CHECKSUMS: GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 hermes-engine: b5c9cfbe6415f1b0b24759f2942c8f33e9af6347 - MMKV: b4802ebd5a7c68fc0c4a5ccb4926fbdfb62d68e0 - MMKVCore: a255341a3746955f50da2ad9121b18cb2b346e61 Mute: 20135a96076f140cc82bfc8b810e2d6150d8ec7e RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 RCTDeprecation: cf39863b43871c2031050605fb884019b6193910 @@ -2359,6 +2669,7 @@ SPEC CHECKSUMS: RCTTypeSafety: c9c9e64389bc545fc137030615b387ef1654dcee React: 14a80ea4f13387cfdaa4250b46fbfe19754c220c React-callinvoker: fed1dad5d6cf992c7b4b5fdbf1bf67fe2e8fb6c5 + React-Codegen: 4b8b4817cea7a54b83851d4c1f91f79aa73de30a React-Core: 3c803e7f3be6fa68e3dabcac283a5a5f87340a60 React-CoreModules: 94d556b4055defb79278c3afba95e521998b9b3a React-cxxreact: 21c826a567199cc2d5797bd4cfe3c0d94bb3a7de @@ -2383,37 +2694,37 @@ SPEC CHECKSUMS: React-logger: 8d00d3d794041a77bd890158353361e2709b04c1 React-Mapbuffer: b0debf83f1eecbb29ae07e0b22ca2483f1550685 React-microtasksnativemodule: b902bf1dc40aa577bb8e00e2ec897853fbc82ca4 - react-native-cameraroll: 4626e88dacb252ebbbba6e162bf7e92fe892c292 + react-native-cameraroll: 6d54614933a21bce260b342355816e1b5e3eee04 react-native-config: ea75335a7cca1d3326de1da384227e580a7c082e - react-native-exif-reader: d871d62023d532e33cc230ede6e2ba9cbfe220e2 + react-native-exif-reader: 0a3beb46ef9f33e4dda5f50795a01b6b510c1459 react-native-geocoder-reborn: a3c3d8460910309e750609c373b6887ec6f67a8f - react-native-geolocation: 697f7e4206386120bfdcf0c6a858e956360c734c + react-native-geolocation: 66ddfd59066bb9365d0899967adc0a2cf2d0e6b2 react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba - react-native-image-picker: b64848e41db57068721d5db3cea54e32ecb92791 - react-native-image-resizer: 24c5d06fae2176dc0caed4b6396e02befb44064a - react-native-keep-awake: 03b74eebe4f2bb5e8478fc8f420651a92463b6f8 + react-native-image-picker: 509b80d8073aca8558fecc6676155a3e4900b63e + react-native-image-resizer: 9e24efe3828c08a8d5553393f33695a086406340 + react-native-keep-awake: a351e6f67006b47f316ae2b17ee8ee69386167f4 react-native-mail: 6e83813066984b26403d3fdfe79ac7bb31857e3c react-native-maps: 9febd31278b35cd21e4fad2cf6fa708993be5dab - react-native-mmkv: a6e08ad1b51b84af075f91798f8a92c878472265 + react-native-mmkv: 2c554a003c78a27f92d6794f1658bbeea37a364a react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187 react-native-orientation-locker: dbd3f6ddbe9e62389cb0807dc2af63f6c36dec36 react-native-render-html: 5afc4751f1a98621b3009432ef84c47019dcb2bd react-native-restart: 0bc732f4461709022a742bb29bcccf6bbc5b4863 - react-native-safe-area-context: 827032edf27079702cbd006f11dc79451a2d744b + react-native-safe-area-context: 143faa2b60b6cc3e06e966d5fa23af6b31326814 react-native-sensitive-info: ee358bf2b901ac3d04f63ff637b31daee44ea87f - react-native-slider: 782148f71677e18db743131d85eecaf93948b478 + react-native-slider: 5d0ed01f7dfe994ec7221eb846b223ff67788fb6 react-native-volume-manager: d9d2863a2374420af89c89662333ea6adf506988 - react-native-webview: 3772c8537fd6d7869791820a7b154fb546bcef7b - react-native-worklets-core: b59cf88762c8fb6132d8796babd4cec15217d6f0 + react-native-webview: 80ef603d1df42e24fdde765686fbb9b8a6ecd554 + react-native-worklets-core: 70698b8dcaf742004d9fc4c483c2ffd82ebff25d React-NativeModulesApple: c8bb2bc56d39bd122c56ef58a55c3f34d53f1585 React-perflogger: d06f0fd0727356651a5535f6d717130187aeb667 React-performancetimeline: 7afc2307ffc4047cef95eb711ea39a12fd90d533 React-RCTActionSheet: a078d5008632fed31b0024c420ee02e612b317d5 React-RCTAnimation: b197cc109a896c6ce23981e02e317cfc055f6fda - React-RCTAppDelegate: 6e7e4fcec0d72cbe2ca43a028400ebc027264e8f + React-RCTAppDelegate: f7f1d7362256b7c142d9ab49f980df488101f869 React-RCTBlob: c12d15d40db01ac3fe57c24d3ef5233ff3333da6 - React-RCTFabric: 24b33edf434ab6856fd0b0af266f19fba335a465 - React-RCTFBReactNativeSpec: e1f4d2662a8a9fd6da4ae3b6b338c7476b4e992b + React-RCTFabric: 6bb325819bbfb8518070e6e3a31fbefd935be4da + React-RCTFBReactNativeSpec: c3a78cb9f2a98146443f1b732a4f21b2ce736abd React-RCTImage: 7a3d9d67161c714fa4d9b93820da39a266d0f1ff React-RCTLinking: f860b917500cd3974235a48d5b199a74a4ed6c26 React-RCTNetwork: 6a984ab1b5a81d17a2df6cc02c24b249fb055deb @@ -2437,26 +2748,26 @@ SPEC CHECKSUMS: RealmJS: 9fd51c849eb552ade9f7b11db42a319b4f6cab4c RNAppleAuthentication: 8d313d93fe2238d6b7ff0a39c67ebcf298d96653 RNAudioRecorderPlayer: fa079748b34d15cd3b7b6a5d47b286bae6d5d49b - RNCClipboard: f6679d470d0da2bce2a37b0af7b9e0bf369ecda5 - RNCPicker: da0f1c9411208c1ca52bc98383db54a06e0a3862 - RNDateTimePicker: 7d93eacf4bdf56350e4b7efd5cfc47639185e10c + RNCClipboard: ba9fda8e2c9f003a29f7f66793069c4d0dada955 + RNCPicker: 490a52d042dc1db36dc979947fced02fd1cf476e + RNDateTimePicker: db1c5f01cfc5681ef8d776cbaf070b415ba19c47 RNDeviceInfo: d863506092aef7e7af3a1c350c913d867d795047 - RNFlashList: e2981ad152fadf10f3b05e56cba9888317d85458 + RNFlashList: 3badc5badd3342f1e75515f911e34a34dd0fcb96 RNFS: 89de7d7f4c0f6bafa05343c578f61118c8282ed8 - RNGestureHandler: 6d231bf41166c01b8234f0b7b24d73d82e44ef4c - RNGoogleSignin: ba93c1137f8d5cebdd39b04f493fd212ddf5ecd6 - RNLocalize: 3c4d0abd777a546fa77bdb6caef85a87fb9ea349 - RNPermissions: f14c20f4eb7a20fff611ad9f467da7bb5872ac4f - RNReanimated: 3bc1666ae96a75a47688fe0ebc4e79340872a1c0 - RNScreens: 9f99e18ee2c72a203651a9bbe322825fe5525d2f - RNShareMenu: 1d285109182098f9f5f449c121080692f2300801 - RNStoreReview: 613c43e9132998ed41a65946e20c223c91b36464 - RNSVG: ae1766b2492f8915a1ee25095871f00a4f132093 + RNGestureHandler: 657b9ff1f40ee3ace3de2bcf467f86d9a6874197 + RNGoogleSignin: e499faa7c170e5466d6e69e43c2fffe036396d14 + RNLocalize: 662baf309d78d5893a767bbbf1b9d2abdb939e80 + RNPermissions: 5e666df09d0fbd11f4fedc8ea1b64686ed8fc26a + RNReanimated: 4f414b5e58e4249329d58839a2b613c480567805 + RNScreens: ef16970d0f91f1750ca82ba0db5d521fc0055fba + RNShareMenu: 3c02ec1c2687370e3a70656a8c95221f705edb67 + RNStoreReview: f1df4978ae22ec08d9c62d59437a1d5f056d0ccf + RNSVG: 4aaeac3fdc7c5bc88ca801e228f62fb469be37e9 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 VisionCamera: 4146fa2612c154f893a42a9b1feedf868faa6b23 - VisionCameraPluginInatVision: 6ddc291d90bbe7677c4a50d017d964aa1b67a61a + VisionCameraPluginInatVision: e1bf46bba641f33ba15125c9d6c1386c422db695 Yoga: eca8dd841b7cd47d82d66be58af8e3aeb819012f -PODFILE CHECKSUM: 5c7a85b8fc0a51e972a87e39194f661a51e0d872 +PODFILE CHECKSUM: ffe83f7f00b108b5b6df43c65170225a183f569b COCOAPODS: 1.15.2 diff --git a/package-lock.json b/package-lock.json index 266c69f39..02d7bf528 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@bam.tech/react-native-image-resizer": "^3.0.11", "@candlefinance/faster-image": "^1.4.3", "@formidable-webview/webshell": "^2.6.0", - "@gorhom/bottom-sheet": "^4.6.4", + "@gorhom/bottom-sheet": "^5.2.6", "@invertase/react-native-apple-authentication": "^2.4.0", "@likashefqet/react-native-image-zoom": "^4.2.0", "@react-native-camera-roll/camera-roll": "github:inaturalist/react-native-cameraroll", @@ -75,7 +75,7 @@ "react-native-logs": "^5.3.0", "react-native-mail": "github:chirag04/react-native-mail", "react-native-maps": "1.20.1", - "react-native-mmkv": "^2.12.2", + "react-native-mmkv": "^3.3.3", "react-native-modal": "^14.0.0-rc.1", "react-native-modal-datetime-picker": "^18.0.0", "react-native-open-maps": "^0.4.3", @@ -2616,9 +2616,9 @@ } }, "node_modules/@gorhom/bottom-sheet": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-4.6.4.tgz", - "integrity": "sha512-0itLMblLBvepE065w3a60S030c2rNUsGshPC7wbWDm31VyqoaU2xjzh/ojH62YIJOcobBr5QoC30IxBBKDGovQ==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-5.2.6.tgz", + "integrity": "sha512-vmruJxdiUGDg+ZYcDmS30XDhq/h/+QkINOI5LY/uGjx8cPGwgJW0H6AB902gNTKtccbiKe/rr94EwdmIEz+LAQ==", "license": "MIT", "dependencies": { "@gorhom/portal": "1.0.14", @@ -2629,8 +2629,8 @@ "@types/react-native": "*", "react": "*", "react-native": "*", - "react-native-gesture-handler": ">=1.10.1", - "react-native-reanimated": ">=2.2.0" + "react-native-gesture-handler": ">=2.16.1", + "react-native-reanimated": ">=3.16.0 || >=4.0.0-" }, "peerDependenciesMeta": { "@types/react": { @@ -18556,12 +18556,13 @@ } }, "node_modules/react-native-mmkv": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-2.12.2.tgz", - "integrity": "sha512-6058Aq0p57chPrUutLGe9fYoiDVDNMU2PKV+lLFUJ3GhoHvUrLdsS1PDSCLr00yqzL4WJQ7TTzH+V8cpyrNcfg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-3.3.3.tgz", + "integrity": "sha512-GMsfOmNzx0p5+CtrCFRVtpOOMYNJXuksBVARSQrCFaZwjUyHJdQzcN900GGaFFNTxw2fs8s5Xje//RDKj9+PZA==", + "license": "(MIT AND BSD-3-Clause)", "peerDependencies": { "react": "*", - "react-native": ">=0.71.0" + "react-native": "*" } }, "node_modules/react-native-modal": { diff --git a/package.json b/package.json index 569ae9cad..027f817b4 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@bam.tech/react-native-image-resizer": "^3.0.11", "@candlefinance/faster-image": "^1.4.3", "@formidable-webview/webshell": "^2.6.0", - "@gorhom/bottom-sheet": "^4.6.4", + "@gorhom/bottom-sheet": "^5.2.6", "@invertase/react-native-apple-authentication": "^2.4.0", "@likashefqet/react-native-image-zoom": "^4.2.0", "@react-native-camera-roll/camera-roll": "github:inaturalist/react-native-cameraroll", @@ -109,7 +109,7 @@ "react-native-logs": "^5.3.0", "react-native-mail": "github:chirag04/react-native-mail", "react-native-maps": "1.20.1", - "react-native-mmkv": "^2.12.2", + "react-native-mmkv": "^3.3.3", "react-native-modal": "^14.0.0-rc.1", "react-native-modal-datetime-picker": "^18.0.0", "react-native-open-maps": "^0.4.3", diff --git a/patches/react-native-mmkv+2.12.2.patch b/patches/react-native-mmkv+2.12.2.patch deleted file mode 100644 index 899b64ab5..000000000 --- a/patches/react-native-mmkv+2.12.2.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/node_modules/react-native-mmkv/android/CMakeLists.txt b/node_modules/react-native-mmkv/android/CMakeLists.txt -index 91a8a6a..7e2dea3 100644 ---- a/node_modules/react-native-mmkv/android/CMakeLists.txt -+++ b/node_modules/react-native-mmkv/android/CMakeLists.txt -@@ -5,6 +5,7 @@ set (PACKAGE_NAME "react-native-mmkv") - set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build) - set(CMAKE_VERBOSE_MAKEFILE ON) - set(CMAKE_CXX_STANDARD 17) -+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384") - - # Add headers search paths - include_directories( diff --git a/patches/react-native-sensitive-info+6.0.0-alpha.9.patch b/patches/react-native-sensitive-info+6.0.0-alpha.9.patch new file mode 100644 index 000000000..20df13eab --- /dev/null +++ b/patches/react-native-sensitive-info+6.0.0-alpha.9.patch @@ -0,0 +1,117 @@ +diff --git a/node_modules/react-native-sensitive-info/build/index.es.js b/node_modules/react-native-sensitive-info/build/index.es.js +index a3b8cf7..2e99837 100644 +--- a/node_modules/react-native-sensitive-info/build/index.es.js ++++ b/node_modules/react-native-sensitive-info/build/index.es.js +@@ -1,33 +1,23 @@ + import { NativeModules } from 'react-native'; + +-/*! ***************************************************************************** +-Copyright (c) Microsoft Corporation. ++const RNSensitiveInfo = NativeModules.RNSensitiveInfo; + +-Permission to use, copy, modify, and/or distribute this software for any +-purpose with or without fee is hereby granted. ++RNSensitiveInfo.setInvalidatedByBiometricEnrollment = ( ++ invalidatedByBiometricEnrollment, ++) => { ++ if (RNSensitiveInfo.setInvalidatedByBiometricEnrollment == null) { ++ return undefined; ++ } + +-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +-PERFORMANCE OF THIS SOFTWARE. +-***************************************************************************** */ +- +-var __assign = function() { +- __assign = Object.assign || function __assign(t) { +- for (var s, i = 1, n = arguments.length; i < n; i++) { +- s = arguments[i]; +- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; +- } +- return t; +- }; +- return __assign.apply(this, arguments); ++ return RNSensitiveInfo.setInvalidatedByBiometricEnrollment( ++ invalidatedByBiometricEnrollment, ++ ); + }; ++RNSensitiveInfo.cancelFingerprintAuth = () => { ++ if (RNSensitiveInfo.cancelFingerprintAuth == null) { ++ return undefined; ++ } + +-var RNSensitiveInfo = NativeModules.RNSensitiveInfo; +-var RNSensitiveInfo$1 = __assign({}, RNSensitiveInfo); +- +-export default RNSensitiveInfo$1; +-//# sourceMappingURL=index.es.js.map ++ return RNSensitiveInfo.cancelFingerprintAuth(); ++}; ++export default RNSensitiveInfo; +\ No newline at end of file +diff --git a/node_modules/react-native-sensitive-info/build/index.js b/node_modules/react-native-sensitive-info/build/index.js +index cd860cd..2e99837 100644 +--- a/node_modules/react-native-sensitive-info/build/index.js ++++ b/node_modules/react-native-sensitive-info/build/index.js +@@ -1,37 +1,23 @@ +-'use strict'; ++import { NativeModules } from 'react-native'; + +-Object.defineProperty(exports, '__esModule', { value: true }); ++const RNSensitiveInfo = NativeModules.RNSensitiveInfo; + +-var reactNative = require('react-native'); ++RNSensitiveInfo.setInvalidatedByBiometricEnrollment = ( ++ invalidatedByBiometricEnrollment, ++) => { ++ if (RNSensitiveInfo.setInvalidatedByBiometricEnrollment == null) { ++ return undefined; ++ } + +-/*! ***************************************************************************** +-Copyright (c) Microsoft Corporation. +- +-Permission to use, copy, modify, and/or distribute this software for any +-purpose with or without fee is hereby granted. +- +-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +-PERFORMANCE OF THIS SOFTWARE. +-***************************************************************************** */ +- +-var __assign = function() { +- __assign = Object.assign || function __assign(t) { +- for (var s, i = 1, n = arguments.length; i < n; i++) { +- s = arguments[i]; +- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; +- } +- return t; +- }; +- return __assign.apply(this, arguments); ++ return RNSensitiveInfo.setInvalidatedByBiometricEnrollment( ++ invalidatedByBiometricEnrollment, ++ ); + }; ++RNSensitiveInfo.cancelFingerprintAuth = () => { ++ if (RNSensitiveInfo.cancelFingerprintAuth == null) { ++ return undefined; ++ } + +-var RNSensitiveInfo = reactNative.NativeModules.RNSensitiveInfo; +-var RNSensitiveInfo$1 = __assign({}, RNSensitiveInfo); +- +-exports.default = RNSensitiveInfo$1; +-//# sourceMappingURL=index.js.map ++ return RNSensitiveInfo.cancelFingerprintAuth(); ++}; ++export default RNSensitiveInfo; +\ No newline at end of file diff --git a/tests/unit/sharedHooks/useObservationsUpdatesWhenFocused.test.js b/tests/unit/sharedHooks/useObservationsUpdatesWhenFocused.test.js deleted file mode 100644 index 145d09cc4..000000000 --- a/tests/unit/sharedHooks/useObservationsUpdatesWhenFocused.test.js +++ /dev/null @@ -1,32 +0,0 @@ -import { renderHook } from "@testing-library/react-native"; -import useObservationUpdatesWhenFocused from "sharedHooks/useObservationUpdatesWhenFocused"; - -const appStateListeners = { -}; - -jest.mock( "react-native/Libraries/AppState/AppState", ( ) => ( { - addEventListener: jest.fn( ( event, callback ) => { - appStateListeners[event] = callback; - return { - remove: jest.fn( () => { - if ( appStateListeners[event] === callback ) { - delete appStateListeners[event]; - } - } ) - }; - } ) -} ) ); - -describe( "useObservationUpdatesWhenFocused", ( ) => { - it( "should add a change listener on mount", ( ) => { - renderHook( ( ) => useObservationUpdatesWhenFocused( ) ); - expect( appStateListeners.change ).toBeDefined( ); - expect( appStateListeners.change ).toBeInstanceOf( Function ); - } ); - - it( "should remove the change listener on unmount", ( ) => { - const { unmount } = renderHook( ( ) => useObservationUpdatesWhenFocused( ) ); - unmount( ); - expect( appStateListeners.change ).toBeUndefined( ); - } ); -} );