How to "mock" navigator.geolocation in a React Jest Test

Mocking with setupFiles

// __mocks__/setup.js

jest.mock('Geolocation', () => {
  return {
    getCurrentPosition: jest.fn(),
    watchPosition: jest.fn(),
  }
});

and then in your package.json

"jest": {
  "preset": "react-native",
  "setupFiles": [
    "./__mocks__/setup.js"
  ]
}

A TypeScript version for anyone that was getting Cannot assign to 'geolocation' because it is a read-only property.

In the mockNavigatorGeolocation.ts file (this can live in a test-utils folder or similar)

export const mockNavigatorGeolocation = () => {
  const clearWatchMock = jest.fn();
  const getCurrentPositionMock = jest.fn();
  const watchPositionMock = jest.fn();

  const geolocation = {
    clearWatch: clearWatchMock,
    getCurrentPosition: getCurrentPositionMock,
    watchPosition: watchPositionMock,
  };

  Object.defineProperty(global.navigator, 'geolocation', {
    value: geolocation,
  });

  return { clearWatchMock, getCurrentPositionMock, watchPositionMock };
};

I then import this in my test at the top of the file:

import { mockNavigatorGeolocation } from '../../test-utils';

And then use the function like so:

const { getCurrentPositionMock } = mockNavigatorGeolocation();
getCurrentPositionMock.mockImplementation((success, rejected) =>
  rejected({
    code: '',
    message: '',
    PERMISSION_DENIED: '',
    POSITION_UNAVAILABLE: '',
    TIMEOUT: '',
  })
);

I know this issue might have been solved, but seems that all the solutions above are all wrong, at least for me.

When you do this mock: getCurrentPosition: jest.fn() it returns undefined, if you want to return something, this is the correct implementation:

const mockGeolocation = {
  getCurrentPosition: jest.fn()
    .mockImplementationOnce((success) => Promise.resolve(success({
      coords: {
        latitude: 51.1,
        longitude: 45.3
      }
    })))
};
global.navigator.geolocation = mockGeolocation;

I am using create-react-app


It appears that there is already a global.navigator object and, like you, I wasn't able to reassign it.

I found that mocking the geolocation part and adding it to the existing global.navigator worked for me.

const mockGeolocation = {
  getCurrentPosition: jest.fn(),
  watchPosition: jest.fn()
};

global.navigator.geolocation = mockGeolocation;

I added this to a src/setupTests.js file as described here - https://create-react-app.dev/docs/running-tests#initializing-test-environment