web-dev-qa-db-fra.com

Comment "simuler" navigator.geolocation dans un test React Jest

J'essaie d'écrire des tests pour un composant de réaction que j'ai construit et qui utilise navigator.geolocation.getCurrentPosition() dans une méthode telle que so (exemple approximatif de mon composant):

class App extends Component {

  constructor() {
    ...
  }

  method() {
    navigator.geolocation.getCurrentPosition((position) => {
       ...code...
    }
  }

  render() {
    return(...)
  }

}

J'utilise create-react-app , qui inclut un test:

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
});

Ce test échoue en imprimant ceci dans la console:

TypeError: Cannot read property 'getCurrentPosition' of undefined

Je suis nouveau sur React, mais j'ai pas mal d’expérience avec angular 1.x. De manière angulaire, il est courant de simuler (dans les tests de beforeEach) des fonctions, des "services" et des méthodes d'objet globales telles que navigator.geolocation.etc. J'ai passé du temps à rechercher ce problème et ce morceau de code est le plus proche que je puisse obtenir d'une maquette:

global.navigator = {
  geolocation: {
    getCurrentPosition: jest.fn()
  }
}

Je l'ai mis dans mon fichier de test pour App, mais cela n'a eu aucun effet.

Comment puis-je "simuler" cette méthode de navigateur et réussir le test?

EDIT: J'ai envisagé d'utiliser une bibliothèque appelée geolocation qui, supposément, enveloppe navigator.getCurrentPosition pour l'utiliser dans un environnement de nœud. Si je comprends bien, Jest exécute des tests dans un environnement de nœud et utilise JSDOM pour simuler des choses comme window. Je n'ai pas pu trouver beaucoup d'informations sur le support de navigator par JSDOM. La bibliothèque mentionnée ci-dessus ne fonctionnait pas dans mon application de réaction. L'utilisation de la méthode spécifique getCurrentPosition ne renvoie qu'un indéfini même si la bibliothèque elle-même a été importée correctement et disponible dans le contexte de la classe App.

10
timothym

Il semble qu’il existe déjà un objet global.navigator et, comme vous, je n’ai pas pu le réaffecter.

J'ai trouvé que se moquer de la partie géolocalisation et l'ajouter au global.navigator existant fonctionnait pour moi.

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

global.navigator.geolocation = mockGeolocation;

J'ai ajouté ceci à un fichier src/setupTests.js comme décrit ici - https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#initializing-test-environment

19
jarace87

Je sais que ce problème a peut-être été résolu, mais il semble que toutes les solutions ci-dessus sont toutes fausses, du moins pour moi.

Lorsque vous effectuez cette simulation: getCurrentPosition: jest.fn()it renvoie undefined, si vous souhaitez retourner quelque chose, voici la bonne implémentation:

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

J'utilise create-react-app

5
Madeo

Se moquer de setupFiles

// __mocks__/setup.js

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

puis dans votre package.json

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

Pour une raison quelconque, l’objet global.navigator n’était pas défini. Je devais donc le spécifier dans mon fichier setupTests.js.

const mockGeolocation = {
  getCurrentPosition: jest.fn(),
  watchPosition: jest.fn(),
}
global.navigator = { geolocation: mockGeolocation }
0
IonicBurger

J'ai fini par utiliser enzyme . Mon test ressemble maintenant à:

import React from 'react'
import App from './App'
import {shallow} from 'enzyme'

it('renders without crashing', () => {
  const app = shallow(<App />)
  expect(app).toBeDefined()
});

Je devais ajouter les packages enzyme et react-addons-test-utils. Aucune configuration nécessaire. Pour l'instant, je ne sais pas vraiment pourquoi cela a résolu le problème, car je ne connais pas bien le fonctionnement de l'enzyme. J'imagine que cela a quelque chose à voir avec cette ligne du fichier README d'Enzyme:

L'API d'Enzyme se veut intuitive et flexible en imitant API jQuery pour la manipulation et la traversée du DOM.

0
timothym