levia
levia

Reputation: 353

Unit Testing navigator.permissions.query({ name: 'geolocation' }) using Jest (React)

I Tried to mock this function

const location = window.navigator && window.navigator.geolocation;
if (location) {
  location.getCurrentPosition(
    (position) => {
      handleChangeLocation(position.coords.latitude, position.coords.longitude);
    },
    (error) => {
      console.log(error);
    },
  );
}
navigator.permissions
  .query({ name: 'geolocation' })
  .then((permission) => {
    permission.onchange = function () {
      if (permission.state === 'granted') {
        location.getCurrentPosition((position) => {
          handleChangeLocation(position.coords.latitude, position.coords.longitude);
        });
      } else if (permission.state === 'denied') {
        // Todo
      }
    };
  });

so far what i've tried is Create Global Navigator at setupTest.js

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

but ended up at error

enter image description here

I tried to solve this by addingjest.spyOn(window.navigator.permissions.query({ name: 'geolocation' }), 'onchange', 'get').mockReturnValueOnce('granted'); but i think there's some mistake cause it's says undefined.

Upvotes: 2

Views: 2871

Answers (3)

pataruco
pataruco

Reputation: 11

You can define the global object like this

const permissionQuerySpy = jest.fn();
const mediaDevicesGetUserMediaSpy = jest.fn();

Object.defineProperty(global.navigator, "permissions", {
  value: {
    query: permissionQuerySpy,
  },
  writable: true,
});

Object.defineProperty(global.navigator, "mediaDevices", {
  value: {
    getUserMedia: mediaDevicesGetUserMediaSpy,
  },
  writable: true,
});

Upvotes: 0

sm7
sm7

Reputation: 669

You need to mock navigator.permissions.query. Try the following:

global.navigator.permissions = {
  query: jest.fn().mockImplementationOnce(() => Promise.resolve({ state: 'granted' })),
};

Above state's value could be granted, denied or prompt.

Overall mock navigator.geolocation and navigator.permissions like the follwoing:

  global.navigator.geolocation = {
    getCurrentPosition: jest.fn().mockImplementationOnce((success) =>
      Promise.resolve(
        success({
          coords: {
            latitude: 43.21,
            longitude: -87.654321,
          },
        })
      )
    ),
  };
  global.navigator.permissions = {
    query: jest
      .fn()
      .mockImplementationOnce(() => Promise.resolve({ state: 'granted' })),
  };

Upvotes: 1

Estus Flask
Estus Flask

Reputation: 222760

The error means that navigator.permissions is undefined. Jest uses JSDOM to mimic real DOM in Node.js environment and doesn't have a lot of APIs that a browser would.

All missing globals need to be stubbed manually:

navigator.permissions = { query: jest.fn() };
navigator.geolocation = { getCurrentPosition: jest.fn() };

Upvotes: 2

Related Questions