diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js index 7cb2e9d032b3ae..9158d62d1c7f52 100644 --- a/Libraries/Geolocation/Geolocation.js +++ b/Libraries/Geolocation/Geolocation.js @@ -57,7 +57,7 @@ const Geolocation = { }, /* - * Request suitable Location permission based on the key configured on pList. + * Requests Location permissions based on the key configured on pList. * * See https://facebook.github.io/react-native/docs/geolocation.html#requestauthorization */ @@ -126,6 +126,11 @@ const Geolocation = { return watchID; }, + /* + * Unsubscribes the watcher with the given watchID. + * + * See https://facebook.github.io/react-native/docs/geolocation.html#clearwatch + */ clearWatch: function(watchID: number) { const sub = subscriptions[watchID]; if (!sub) { @@ -150,6 +155,11 @@ const Geolocation = { } }, + /* + * Stops observing for device location changes and removes all registered listeners. + * + * See https://facebook.github.io/react-native/docs/geolocation.html#stopobserving + */ stopObserving: function() { if (updatesEnabled) { RCTLocationObserver.stopObserving(); diff --git a/Libraries/Geolocation/__tests__/Geolocation-test.js b/Libraries/Geolocation/__tests__/Geolocation-test.js new file mode 100644 index 00000000000000..ebf0daf08b7fd5 --- /dev/null +++ b/Libraries/Geolocation/__tests__/Geolocation-test.js @@ -0,0 +1,102 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @emails oncall+react_native + */ + +'use strict'; + +describe('Geolocation', () => { + let Geolocation; + const NativeModules = require('NativeModules'); + + beforeEach(() => { + jest.resetModules(); + Geolocation = jest.requireActual('Geolocation'); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should set the location observer configuration', () => { + Geolocation.setRNConfiguration({skipPermissionRequests: true}); + expect( + NativeModules.LocationObserver.setConfiguration.mock.calls.length, + ).toEqual(1); + }); + + it('should request authorization for location requests', () => { + Geolocation.requestAuthorization(); + expect( + NativeModules.LocationObserver.requestAuthorization.mock.calls.length, + ).toEqual(1); + }); + + it('should get the current position and pass it to the given callback', () => { + const callback = () => {}; + Geolocation.getCurrentPosition(callback); + expect( + NativeModules.LocationObserver.getCurrentPosition.mock.calls.length, + ).toEqual(1); + expect( + NativeModules.LocationObserver.getCurrentPosition.mock.calls[0][1], + ).toBe(callback); + }); + + it('should add a success listener to the geolocation', () => { + const watchID = Geolocation.watchPosition(() => {}); + expect(watchID).toEqual(0); + expect(NativeModules.LocationObserver.addListener.mock.calls[0][0]).toBe( + 'geolocationDidChange', + ); + }); + + it('should add an error listener to the geolocation', () => { + const watchID = Geolocation.watchPosition(() => {}, () => {}); + expect(watchID).toEqual(0); + expect(NativeModules.LocationObserver.addListener.mock.calls[1][0]).toBe( + 'geolocationError', + ); + }); + + it('should clear the listeners associated with a watchID', () => { + const watchID = Geolocation.watchPosition(() => {}, () => {}); + Geolocation.clearWatch(watchID); + expect(NativeModules.LocationObserver.stopObserving.mock.calls.length).toBe( + 1, + ); + }); + + it('should correctly assess if all listeners have been cleared', () => { + const watchID = Geolocation.watchPosition(() => {}, () => {}); + Geolocation.watchPosition(() => {}, () => {}); + Geolocation.clearWatch(watchID); + expect(NativeModules.LocationObserver.stopObserving.mock.calls.length).toBe( + 0, + ); + }); + + it('should not fail if the watchID one wants to clear does not exist', () => { + Geolocation.watchPosition(() => {}, () => {}); + Geolocation.clearWatch(42); + expect(NativeModules.LocationObserver.stopObserving.mock.calls.length).toBe( + 0, + ); + }); + + it('should stop observing and warn about removing existing subscriptions', () => { + const warningCallback = jest.fn(); + jest.mock('fbjs/lib/warning', () => warningCallback); + Geolocation.watchPosition(() => {}, () => {}); + Geolocation.stopObserving(); + expect(NativeModules.LocationObserver.stopObserving.mock.calls.length).toBe( + 1, + ); + expect(warningCallback.mock.calls.length).toBeGreaterThanOrEqual(1); + }); +}); diff --git a/jest/setup.js b/jest/setup.js index 32499d2992dbab..67b41d7bbc9069 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -171,7 +171,11 @@ const mockNativeModules = { sendIntent: jest.fn(), }, LocationObserver: { + addListener: jest.fn(), getCurrentPosition: jest.fn(), + removeListeners: jest.fn(), + requestAuthorization: jest.fn(), + setConfiguration: jest.fn(), startObserving: jest.fn(), stopObserving: jest.fn(), },