web-dev-qa-db-ja.com

React Jestテストでnavigator.geolocationを「モック」する方法

私が作成した反応コンポーネントのテストを、そのようなメソッド内でnavigator.geolocation.getCurrentPosition()を使用して記述しようとしています(コンポーネントの大まかな例):

class App extends Component {

  constructor() {
    ...
  }

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

  render() {
    return(...)
  }

}

テストを含む create-react-app を使用しています:

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

このテストは失敗し、これをコンソールに出力します。

TypeError: Cannot read property 'getCurrentPosition' of undefined

私はReactは初めてですが、angular 1.xでかなりの経験があります。angularで、モックアウトすることは一般的です(テスト内でbeforeEach)関数、「サービス」、およびnavigator.geolocation.etcなどのグローバルオブジェクトメソッドで、この問題の調査に時間を費やし、このコードのコードはモックに到達できる最も近いものです。

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

これをAppのテストファイルに入れましたが、効果がありませんでした。

このナビゲーターメソッドを「モック」してテストに合格させるにはどうすればよいですか?

編集:私は geolocation と呼ばれるライブラリの使用を検討しましたが、これはおそらくnavigator.getCurrentPositionをラップしてノード環境で使用するためのものです。私が正しく理解していれば、jestはノード環境でテストを実行し、JSDOMを使用してwindowなどのモックアウトを作成します。 JSDOMによるnavigatorのサポートについて、多くの情報を見つけることができませんでした。上記のライブラリは私の反応アプリで動作しませんでした。特定のメソッドgetCurrentPositionを使用すると、ライブラリ自体が正しくインポートされ、Appクラスのコンテキスト内で利用可能であっても、未定義のみが返されます。

17
timothym

global.navigatorオブジェクトはすでに存在しているようです。あなたと同じように、オブジェクトを再割り当てできませんでした。

ジオロケーションパーツをモックして既存のglobal.navigatorに追加するとうまくいくことがわかりました。

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

global.navigator.geolocation = mockGeolocation;

ここに記載されているように、これをsrc/setupTests.jsファイルに追加しました- https://create-react-app.dev/docs/running-tests#initializing-test-environment

29
jarace87

この問題は解決されたかもしれませんが、少なくとも私にとっては、上記のすべての解決策がすべて間違っているようです。

このモックを実行すると、getCurrentPosition: jest.fn()は未定義を返します。何かを返したい場合は、これが正しい実装です。

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

私はcreate-react-appを使用しています

14
Madeo

setupFilesによるモック

// __mocks__/setup.js

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

そしてあなたのpackage.json

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

何らかの理由で、global.navigatorオブジェクトを定義しなかったため、setupTests.jsファイルで指定する必要がありました

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

enzyme を使用してしまいました。私のテストは次のようになります:

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

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

enzymeパッケージとreact-addons-test-utilsパッケージの両方を追加する必要がありました。設定は必要ありません。現時点では、酵素がどのように機能するかよく知らないので、なぜこれが問題を解決したのか実際にはわかりません。私はそれがEnzymeのREADMEからのこの行と関係があると思います:

EnzymeのAPIは、jQueryのAPIを模倣してDOMの操作とトラバーサルを行うことにより、直感的で柔軟なものにすることを目的としています。

0
timothym