web-dev-qa-db-de.com

Wie "navigieren" navigator.geolocation in einem React Jest-Test

Ich versuche, Tests für eine von mir erstellte Reakt-Komponente zu schreiben, die navigator.geolocation.getCurrentPosition() innerhalb einer Methode wie dieser verwendet (grobes Beispiel meiner Komponente):

class App extends Component {

  constructor() {
    ...
  }

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

  render() {
    return(...)
  }

}

Ich verwende create -rease-app , die einen Test beinhaltet:

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

Dieser Test schlägt fehl und druckt dies in der Konsole aus:

TypeError: Cannot read property 'getCurrentPosition' of undefined

Ich bin neu bei React, habe aber ziemlich viel Erfahrung mit Winkel 1.x. In Winkeln ist es üblich, Funktionen ("services") und globale Objektmethoden wie navigator.geolocation.etc (innerhalb der Tests in beforeEach) zu simulieren. Ich habe viel Zeit damit verbracht, dieses Problem zu untersuchen, und dieses bisschen Code ist das, was ich einem Mock am nächsten kommen könnte:

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

Ich habe dies in meine Testdatei für App eingefügt, aber es hatte keine Auswirkungen.

Wie kann ich diese Navigator-Methode "nachahmen" und den Test bestehen lassen?

EDIT: Ich habe mit einer Bibliothek namens geolocation nachgesehen, die navigator.getCurrentPosition für die Verwendung in einer Knotenumgebung einschließt. Wenn ich es richtig verstanden habe, führt Jest Tests in einer Knotenumgebung durch und verwendet JSDOM, um Dinge wie window zu simulieren. Ich habe nicht viele Informationen zu JSDOMs Unterstützung von navigator gefunden. Die oben erwähnte Bibliothek hat in meiner Reakt-App nicht funktioniert. Wenn Sie die spezifische Methode getCurrentPosition verwenden, wird nur undefined zurückgegeben, obwohl die Bibliothek selbst korrekt importiert wurde und im Kontext der App-Klasse verfügbar ist.

10
timothym

Es scheint, dass es bereits ein global.navigator-Objekt gibt, und wie Sie konnte ich es nicht erneut zuweisen.

Ich fand, dass das Spottmachen des Geolocation-Teils und das Hinzufügen zum vorhandenen global.navigator für mich funktioniert hat.

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

global.navigator.geolocation = mockGeolocation;

Ich habe dies wie hier beschrieben zu einer src/setupTests.js-Datei hinzugefügt - https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#initializing-test-environment

19
jarace87

Ich weiß, dass dieses Problem möglicherweise gelöst wurde, aber es scheint, dass alle oben genannten Lösungen alle falsch sind, zumindest für mich.

Wenn Sie diesen Mock ausführen, gibt getCurrentPosition: jest.fn()it undefined zurück. Wenn Sie etwas zurückgeben möchten, ist dies die korrekte Implementierung:

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

Ich verwende Create-React-App

5
Madeo

Verspottung mit setupFiles

// __mocks__/setup.js

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

und dann in deinem package.json

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

Aus irgendeinem Grund habe ich das global.navigator-Objekt nicht definiert, daher musste ich es in meiner setupTests.js-Datei angeben

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

Am Ende habe ich enzym verwendet. Mein Test sieht jetzt so aus:

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

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

Ich musste die Pakete enzyme und react-addons-test-utils hinzufügen. Keine config benötigt Im Moment weiß ich nicht, warum das Problem behoben wurde, da ich nicht weiß, wie das Enzym funktioniert. Ich kann mir vorstellen, dass es etwas mit dieser Zeile aus Enzyme's README zu tun hat:

Die API von Enzyme soll durch Nachahmen von Intuitiv und flexibel sein. jQuery's API für DOM-Manipulation und Traversierung.

0
timothym