如何在 React Jest 测试中 "mock" navigator.geolocation
How to "mock" navigator.geolocation in a React Jest Test
我正在尝试为我构建的 React 组件编写测试,该组件使用 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 的测试中)函数、"services" 和全局对象方法如 navigator.geolocation.etc 是很常见的。我花时间研究了这个问题,这段代码是我能得到的最接近模拟的代码:
global.navigator = {
geolocation: {
getCurrentPosition: jest.fn()
}
}
我把它放在我的应用程序测试文件中,但是没有效果。
如何 "mock" 退出这个导航器方法并让测试通过?
编辑:我研究了使用一个名为 geolocation 的库,它应该包装 navigator.getCurrentPosition
以便在节点环境中使用。如果我理解正确的话,jest 在节点环境中运行测试并使用 JSDOM 来模拟 window
之类的东西。我没能找到很多关于 JSDOM 对 navigator
的支持的信息。上面提到的库在我的 React 应用程序中不起作用。使用特定方法 getCurrentPosition 只会 return 未定义,即使库本身已正确导入并在应用程序的上下文中可用 class.
似乎已经有一个 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
用setupFiles
模拟
// __mocks__/setup.js
jest.mock('Geolocation', () => {
return {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
}
});
然后在你的 package.json
"jest": {
"preset": "react-native",
"setupFiles": [
"./__mocks__/setup.js"
]
}
我知道这个问题可能已经解决了,但是上面的所有解决方案似乎都是错误的,至少对我来说是这样。
当你做这个模拟时:getCurrentPosition: jest.fn()
它 return 未定义,如果你想 return 一些东西,这是正确的实现:
const mockGeolocation = {
getCurrentPosition: jest.fn()
.mockImplementationOnce((success) => Promise.resolve(success({
coords: {
latitude: 51.1,
longitude: 45.3
}
})))
};
global.navigator.geolocation = mockGeolocation;
我正在使用 create-react-app
出于某种原因,我没有定义 global.navigator 对象,所以我必须在我的 setupTests.js 文件中指定它
const mockGeolocation = {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
}
global.navigator = { geolocation: mockGeolocation }
我按照@madeo 上面的评论来模拟global.navigator.geolocation
。成功了!
此外,我做了以下模拟 global.navigator.permissions
:
global.navigator.permissions = {
query: jest
.fn()
.mockImplementationOnce(() => Promise.resolve({ state: 'granted' })),
};
根据需要将state
设置为granted
、denied
、prompt
中的任意一个。
为正在获取的任何人准备的 TypeScript 版本
Cannot assign to 'geolocation' because it is a read-only property.
在 mockNavigatorGeolocation.ts
文件中(这可以存在于 test-utils
文件夹或类似文件夹中)
export const mockNavigatorGeolocation = () => {
const clearWatchMock = jest.fn();
const getCurrentPositionMock = jest.fn();
const watchPositionMock = jest.fn();
const geolocation = {
clearWatch: clearWatchMock,
getCurrentPosition: getCurrentPositionMock,
watchPosition: watchPositionMock,
};
Object.defineProperty(global.navigator, 'geolocation', {
value: geolocation,
});
return { clearWatchMock, getCurrentPositionMock, watchPositionMock };
};
然后我在文件顶部的测试中导入它:
import { mockNavigatorGeolocation } from '../../test-utils';
然后像这样使用函数:
const { getCurrentPositionMock } = mockNavigatorGeolocation();
getCurrentPositionMock.mockImplementation((success, rejected) =>
rejected({
code: '',
message: '',
PERMISSION_DENIED: '',
POSITION_UNAVAILABLE: '',
TIMEOUT: '',
})
);
我正在尝试为我构建的 React 组件编写测试,该组件使用 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 的测试中)函数、"services" 和全局对象方法如 navigator.geolocation.etc 是很常见的。我花时间研究了这个问题,这段代码是我能得到的最接近模拟的代码:
global.navigator = {
geolocation: {
getCurrentPosition: jest.fn()
}
}
我把它放在我的应用程序测试文件中,但是没有效果。
如何 "mock" 退出这个导航器方法并让测试通过?
编辑:我研究了使用一个名为 geolocation 的库,它应该包装 navigator.getCurrentPosition
以便在节点环境中使用。如果我理解正确的话,jest 在节点环境中运行测试并使用 JSDOM 来模拟 window
之类的东西。我没能找到很多关于 JSDOM 对 navigator
的支持的信息。上面提到的库在我的 React 应用程序中不起作用。使用特定方法 getCurrentPosition 只会 return 未定义,即使库本身已正确导入并在应用程序的上下文中可用 class.
似乎已经有一个 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
用setupFiles
// __mocks__/setup.js
jest.mock('Geolocation', () => {
return {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
}
});
然后在你的 package.json
"jest": {
"preset": "react-native",
"setupFiles": [
"./__mocks__/setup.js"
]
}
我知道这个问题可能已经解决了,但是上面的所有解决方案似乎都是错误的,至少对我来说是这样。
当你做这个模拟时:getCurrentPosition: jest.fn()
它 return 未定义,如果你想 return 一些东西,这是正确的实现:
const mockGeolocation = {
getCurrentPosition: jest.fn()
.mockImplementationOnce((success) => Promise.resolve(success({
coords: {
latitude: 51.1,
longitude: 45.3
}
})))
};
global.navigator.geolocation = mockGeolocation;
我正在使用 create-react-app
出于某种原因,我没有定义 global.navigator 对象,所以我必须在我的 setupTests.js 文件中指定它
const mockGeolocation = {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
}
global.navigator = { geolocation: mockGeolocation }
我按照@madeo 上面的评论来模拟global.navigator.geolocation
。成功了!
此外,我做了以下模拟 global.navigator.permissions
:
global.navigator.permissions = {
query: jest
.fn()
.mockImplementationOnce(() => Promise.resolve({ state: 'granted' })),
};
根据需要将state
设置为granted
、denied
、prompt
中的任意一个。
为正在获取的任何人准备的 TypeScript 版本
Cannot assign to 'geolocation' because it is a read-only property.
在 mockNavigatorGeolocation.ts
文件中(这可以存在于 test-utils
文件夹或类似文件夹中)
export const mockNavigatorGeolocation = () => {
const clearWatchMock = jest.fn();
const getCurrentPositionMock = jest.fn();
const watchPositionMock = jest.fn();
const geolocation = {
clearWatch: clearWatchMock,
getCurrentPosition: getCurrentPositionMock,
watchPosition: watchPositionMock,
};
Object.defineProperty(global.navigator, 'geolocation', {
value: geolocation,
});
return { clearWatchMock, getCurrentPositionMock, watchPositionMock };
};
然后我在文件顶部的测试中导入它:
import { mockNavigatorGeolocation } from '../../test-utils';
然后像这样使用函数:
const { getCurrentPositionMock } = mockNavigatorGeolocation();
getCurrentPositionMock.mockImplementation((success, rejected) =>
rejected({
code: '',
message: '',
PERMISSION_DENIED: '',
POSITION_UNAVAILABLE: '',
TIMEOUT: '',
})
);