Как "макет" навигатора .geolocation в React Jest Test
Я пытаюсь написать тесты для созданного мной реактивного компонента, который использует navigator.geolocation.getCurrentPosition()
в методе, подобном этому (грубый пример моего компонента):
class App extends Component {
constructor() {
...
}
method() {
navigator.geolocation.getCurrentPosition((position) => {
...code...
}
}
render() {
return(...)
}
}
Я использую приложение create-реагировать, которое включает в себя тест:
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()
}
}
Я поместил это в свой тестовый файл для приложения, но это не имело никакого эффекта.
Как я могу "смоделировать" этот метод навигатора и пройти тест?
РЕДАКТИРОВАТЬ: я рассмотрел использование библиотеки под названием геолокации, которая якобы оборачивает navigator.getCurrentPosition
для использования в среде узла. Если я правильно понимаю, jest запускает тесты в среде узлов и использует JSDOM для имитации таких вещей, как window
. Я не смог найти много информации о поддержке JSDOM navigator
. Вышеупомянутая библиотека не работала в моем приложении реакции. Использование специального метода getCurrentPosition вернет только неопределенное значение, даже если сама библиотека была импортирована правильно и доступна в контексте класса App.
Ответы
Ответ 1
Похоже, что объект 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
Ответ 2
Я знаю, что эта проблема, возможно, была решена, но кажется, что все вышеупомянутые решения являются неправильными, по крайней мере, для меня.
Когда вы делаете это mock: getCurrentPosition: jest.fn()
он возвращает undefined, если вы хотите что-то вернуть, это правильная реализация:
const mockGeolocation = {
getCurrentPosition: jest.fn()
.mockImplementationOnce((success) => Promise.resolve(success({
coords: {
latitude: 51.1,
longitude: 45.3
}
})))
};
global.navigator.geolocation = mockGeolocation;
Я использую приложение create-реагировать
Ответ 3
Издевается над setupFiles
// __mocks__/setup.js
jest.mock('Geolocation', () => {
return {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
}
});
а затем в package.json
"jest": {
"preset": "react-native",
"setupFiles": [
"./__mocks__/setup.js"
]
}
Ответ 4
В итоге я использовал 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:
Ферментный API должен быть интуитивно понятным и гибким путем подражания jQuery API для манипуляции и обхода DOM.
Ответ 5
По какой-то причине у меня не был определен объект global.navigator, поэтому мне пришлось указать его в моем файле setupTests.js.
const mockGeolocation = {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
}
global.navigator = { geolocation: mockGeolocation }