react-haiku
Version:
React Hook & Utility Library
124 lines (123 loc) • 4.54 kB
JavaScript
import { renderHook, act, waitFor } from '@testing-library/react';
import { useGeolocation } from '../../hooks/useGeolocation';
// Mock the geolocation API
const mockGeolocation = {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
clearWatch: jest.fn(),
};
// Mock navigator.geolocation
Object.defineProperty(window.navigator, 'geolocation', {
value: mockGeolocation,
writable: true,
});
describe('useGeolocation Hook', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('returns initial state correctly', () => {
const { result } = renderHook(() => useGeolocation());
expect(result.current.latitude).toBe(null);
expect(result.current.longitude).toBe(null);
expect(result.current.error).toBe(null);
expect(result.current.loading).toBe(true);
});
test('handles successful geolocation', async () => {
const mockPosition = {
coords: {
latitude: 40.7128,
longitude: -74.0060,
},
};
mockGeolocation.getCurrentPosition.mockImplementation((success) => {
success(mockPosition);
});
const { result } = renderHook(() => useGeolocation());
await waitFor(() => {
expect(result.current.loading).toBe(false);
});
expect(result.current.latitude).toBe(40.7128);
expect(result.current.longitude).toBe(-74.0060);
expect(result.current.error).toBe(null);
expect(mockGeolocation.getCurrentPosition).toHaveBeenCalledTimes(1);
});
test('handles geolocation errors', async () => {
const mockError = {
code: 1,
PERMISSION_DENIED: 1,
POSITION_UNAVAILABLE: 2,
TIMEOUT: 3,
};
mockGeolocation.getCurrentPosition.mockImplementation((_success, error) => {
error(mockError);
});
const { result } = renderHook(() => useGeolocation());
await waitFor(() => {
expect(result.current.loading).toBe(false);
});
expect(result.current.latitude).toBe(null);
expect(result.current.longitude).toBe(null);
expect(result.current.error).toEqual({
code: 1,
message: 'User denied the request for Geolocation.',
});
});
test('handles unsupported geolocation', () => {
// Temporarily remove geolocation support
const originalGeolocation = window.navigator.geolocation;
Object.defineProperty(window.navigator, 'geolocation', {
value: undefined,
writable: true,
});
const { result } = renderHook(() => useGeolocation());
expect(result.current.loading).toBe(false);
expect(result.current.error).toEqual({
code: 0,
message: 'Geolocation is not supported by this browser.',
});
// Restore geolocation
Object.defineProperty(window.navigator, 'geolocation', {
value: originalGeolocation,
writable: true,
});
});
test('handles watch mode', async () => {
const mockPosition = {
coords: {
latitude: 40.7128,
longitude: -74.0060,
},
};
let watchCallback = null;
const watchId = 123;
mockGeolocation.watchPosition.mockImplementation((success) => {
watchCallback = success;
return watchId;
});
const { result, unmount } = renderHook(() => useGeolocation({ watch: true }));
expect(mockGeolocation.watchPosition).toHaveBeenCalledTimes(1);
// Simulate position update
act(() => {
if (watchCallback) {
watchCallback(mockPosition);
}
});
await waitFor(() => {
expect(result.current.loading).toBe(false);
});
expect(result.current.latitude).toBe(40.7128);
expect(result.current.longitude).toBe(-74.0060);
// Test cleanup
unmount();
expect(mockGeolocation.clearWatch).toHaveBeenCalledWith(watchId);
});
test('passes correct options to getCurrentPosition', () => {
const options = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000,
};
renderHook(() => useGeolocation(options));
expect(mockGeolocation.getCurrentPosition).toHaveBeenCalledWith(expect.any(Function), expect.any(Function), options);
});
});