From 58e0d7367ca35ebab6ee9b710b268dccc993db0d Mon Sep 17 00:00:00 2001 From: sepeterson <10458078+sepeterson@users.noreply.github.com> Date: Fri, 8 May 2026 10:38:28 -0500 Subject: [PATCH] MOB-1321: unit tests --- .../useObservationLocation.test.js | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tests/unit/sharedHooks/useObservationLocation.test.js diff --git a/tests/unit/sharedHooks/useObservationLocation.test.js b/tests/unit/sharedHooks/useObservationLocation.test.js new file mode 100644 index 000000000..78b3f9df3 --- /dev/null +++ b/tests/unit/sharedHooks/useObservationLocation.test.js @@ -0,0 +1,134 @@ +import { renderHook, waitFor } from "@testing-library/react-native"; +import useObservationLocation from "sharedHooks/useObservationLocation"; + +const mockUseWatchPosition = jest.fn( ); +jest.mock( "sharedHooks/useWatchPosition", () => ( { + __esModule: true, + default: ( ...args ) => mockUseWatchPosition( ...args ), +} ) ); + +const mockHasOnlyCoarseLocation = jest.fn( ); +jest.mock( "components/SharedComponents/PermissionGateContainer", () => ( { + hasOnlyCoarseLocation: ( ...args ) => mockHasOnlyCoarseLocation( ...args ), +} ) ); + +const mockFetchCoarseUserLocation = jest.fn( ); +jest.mock( "sharedHelpers/fetchCoarseUserLocation", () => ( { + __esModule: true, + default: ( ...args ) => mockFetchCoarseUserLocation( ...args ), +} ) ); + +const mockCoarseLocation = { + latitude: 44.95, + longitude: -93.27, + positional_accuracy: 2000, + altitude: null, + altitudinal_accuracy: null, +}; + +const mockFineLocation = { + latitude: 44.9537, + longitude: -93.2690, + positional_accuracy: 8, + altitude: 250, + altitudinal_accuracy: 3, +}; + +const defaultWatchResult = { + isFetchingLocation: false, + stopWatch: jest.fn( ), + subscriptionId: null, + userLocation: null, +}; + +beforeEach( ( ) => { + jest.clearAllMocks( ); + mockUseWatchPosition.mockReturnValue( defaultWatchResult ); +} ); + +describe( "useObservationLocation", ( ) => { + describe( "when only coarse location permission is granted", ( ) => { + beforeEach( ( ) => { + mockHasOnlyCoarseLocation.mockResolvedValue( true ); + } ); + + it( "fetches coarse location and returns it as userLocation", async ( ) => { + mockFetchCoarseUserLocation.mockResolvedValue( mockCoarseLocation ); + + const { result } = renderHook( ( ) => useObservationLocation( { + shouldFetchLocation: true, + } ) ); + + await waitFor( ( ) => { + expect( result.current.userLocation ).toEqual( mockCoarseLocation ); + } ); + expect( result.current.isFetchingLocation ).toBe( false ); + expect( mockFetchCoarseUserLocation ).toHaveBeenCalledTimes( 1 ); + } ); + + it( "does not pass shouldFetchLocation to useWatchPosition", async ( ) => { + mockFetchCoarseUserLocation.mockResolvedValue( mockCoarseLocation ); + + renderHook( ( ) => useObservationLocation( { + shouldFetchLocation: true, + } ) ); + + await waitFor( ( ) => { + expect( mockHasOnlyCoarseLocation ).toHaveBeenCalled( ); + } ); + const allCalls = mockUseWatchPosition.mock.calls; + const lastCall = allCalls[allCalls.length - 1]; + expect( lastCall[0].shouldFetchLocation ).toBe( false ); + } ); + } ); + + describe( "when fine location permission is granted", ( ) => { + beforeEach( ( ) => { + mockHasOnlyCoarseLocation.mockResolvedValue( false ); + } ); + + it( "delegates to useWatchPosition and returns its location", async ( ) => { + mockUseWatchPosition.mockReturnValue( { + ...defaultWatchResult, + isFetchingLocation: false, + userLocation: mockFineLocation, + } ); + + const { result } = renderHook( ( ) => useObservationLocation( { + shouldFetchLocation: true, + } ) ); + + await waitFor( ( ) => { + expect( result.current.userLocation ).toEqual( mockFineLocation ); + } ); + expect( mockFetchCoarseUserLocation ).not.toHaveBeenCalled( ); + } ); + + it( "passes shouldFetchLocation: true to useWatchPosition", async ( ) => { + renderHook( ( ) => useObservationLocation( { + shouldFetchLocation: true, + } ) ); + + await waitFor( ( ) => { + const allCalls = mockUseWatchPosition.mock.calls; + const lastCall = allCalls[allCalls.length - 1]; + expect( lastCall[0].shouldFetchLocation ).toBe( true ); + } ); + } ); + + it( "reports isFetchingLocation from useWatchPosition", async ( ) => { + mockUseWatchPosition.mockReturnValue( { + ...defaultWatchResult, + isFetchingLocation: true, + } ); + + const { result } = renderHook( ( ) => useObservationLocation( { + shouldFetchLocation: true, + } ) ); + + await waitFor( ( ) => { + expect( result.current.isFetchingLocation ).toBe( true ); + } ); + } ); + } ); +} );