Skip to content

Commit 027f5ed

Browse files
authored
Merge pull request #195 from zeroqs/test/useGeolocation
test: add test for useGeolocation
2 parents eaa32ad + 6fc7ea6 commit 027f5ed

File tree

2 files changed

+117
-23
lines changed

2 files changed

+117
-23
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { renderHook } from '@testing-library/react';
2+
3+
import { useGeolocation } from '@/hooks/useGeolocation/useGeolocation';
4+
5+
const geolocationPreset = {
6+
getCurrentPosition: vi.fn(),
7+
watchPosition: vi.fn(),
8+
clearWatch: vi.fn()
9+
};
10+
11+
beforeEach(() => {
12+
Object.defineProperty(global.navigator, 'geolocation', {
13+
value: geolocationPreset
14+
});
15+
});
16+
17+
it('should return default state initially', () => {
18+
const { result } = renderHook(useGeolocation);
19+
20+
expect(result.current).toEqual({
21+
loading: true,
22+
error: null,
23+
timestamp: expect.any(Number),
24+
accuracy: 0,
25+
latitude: Number.POSITIVE_INFINITY,
26+
longitude: Number.POSITIVE_INFINITY,
27+
altitude: null,
28+
altitudeAccuracy: null,
29+
heading: null,
30+
speed: null
31+
});
32+
});
33+
34+
it('should update state on successful geolocation retrieval', () => {
35+
const mockPosition = {
36+
coords: {
37+
latitude: 50,
38+
longitude: 14,
39+
altitude: 100,
40+
accuracy: 10,
41+
altitudeAccuracy: 5,
42+
heading: 90,
43+
speed: 10
44+
},
45+
timestamp: 123456789
46+
};
47+
48+
geolocationPreset.getCurrentPosition.mockImplementation((success) => success(mockPosition));
49+
geolocationPreset.watchPosition.mockImplementation((success) => success(mockPosition));
50+
51+
const { result } = renderHook(useGeolocation);
52+
53+
expect(result.current).toEqual({
54+
loading: false,
55+
error: null,
56+
timestamp: mockPosition.timestamp,
57+
accuracy: mockPosition.coords.accuracy,
58+
latitude: mockPosition.coords.latitude,
59+
longitude: mockPosition.coords.longitude,
60+
altitude: mockPosition.coords.altitude,
61+
altitudeAccuracy: mockPosition.coords.altitudeAccuracy,
62+
heading: mockPosition.coords.heading,
63+
speed: mockPosition.coords.speed
64+
});
65+
});
66+
67+
it('should update state on geolocation error', () => {
68+
const mockError = {
69+
code: 1,
70+
message: 'User denied Geolocation'
71+
};
72+
73+
geolocationPreset.getCurrentPosition.mockImplementation((_, error) => error(mockError));
74+
geolocationPreset.watchPosition.mockImplementation((_, error) => error(mockError));
75+
76+
const { result } = renderHook(useGeolocation);
77+
78+
expect(result.current).toEqual({
79+
loading: false,
80+
error: mockError,
81+
timestamp: expect.any(Number),
82+
accuracy: 0,
83+
latitude: Number.POSITIVE_INFINITY,
84+
longitude: Number.POSITIVE_INFINITY,
85+
altitude: null,
86+
altitudeAccuracy: null,
87+
heading: null,
88+
speed: null
89+
});
90+
});
91+
92+
it('should clear watch position on unmount', () => {
93+
const watchId = 1;
94+
geolocationPreset.watchPosition.mockReturnValue(watchId);
95+
96+
const { unmount } = renderHook(useGeolocation);
97+
98+
unmount();
99+
100+
expect(geolocationPreset.clearWatch).toHaveBeenCalledWith(watchId);
101+
});

src/hooks/useGeolocation/useGeolocation.ts

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,21 @@ export interface UseGeolocationReturn {
2626

2727
/** The use geolocation params type */
2828
export type UseGeolocationParams = PositionOptions;
29+
/** The use geolocation state type */
30+
type UseGeolocationState = UseGeolocationReturn;
31+
32+
const DEFAULT_STATE: UseGeolocationState = {
33+
loading: true,
34+
error: null,
35+
timestamp: Date.now(),
36+
accuracy: 0,
37+
latitude: Number.POSITIVE_INFINITY,
38+
longitude: Number.POSITIVE_INFINITY,
39+
altitude: null,
40+
altitudeAccuracy: null,
41+
heading: null,
42+
speed: null
43+
};
2944

3045
/**
3146
* @name useGeolocation
@@ -41,29 +56,7 @@ export type UseGeolocationParams = PositionOptions;
4156
* const { loading, error, timestamp, accuracy, latitude, longitude, altitude, altitudeAccuracy, heading, speed } = useGeolocation();
4257
*/
4358
export const useGeolocation = (params?: UseGeolocationParams): UseGeolocationReturn => {
44-
const [value, setValue] = useState<{
45-
loading: boolean;
46-
error: GeolocationPositionError | null;
47-
timestamp: number | null;
48-
accuracy: number | null;
49-
latitude: number | null;
50-
longitude: number | null;
51-
altitude: number | null;
52-
altitudeAccuracy: number | null;
53-
heading: number | null;
54-
speed: number | null;
55-
}>({
56-
loading: true,
57-
error: null,
58-
timestamp: Date.now(),
59-
accuracy: 0,
60-
latitude: Number.POSITIVE_INFINITY,
61-
longitude: Number.POSITIVE_INFINITY,
62-
altitude: null,
63-
altitudeAccuracy: null,
64-
heading: null,
65-
speed: null
66-
});
59+
const [value, setValue] = useState<UseGeolocationState>(DEFAULT_STATE);
6760

6861
useEffect(() => {
6962
const onEvent = ({ coords, timestamp }: GeolocationPosition) => {

0 commit comments

Comments
 (0)