mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 15:51:00 +00:00
46f4cab1b7
- The location shim runs at high accuracy only while a watcher wants it and drops back once that watcher is gone, instead of keeping the 2 s GPS rate for the rest of the session. - The purchase client can hand over a Play subscription that was paid but never delivered (a pending payment that cleared later), and the plans screen redeems it at once, as a restore would, before Google Play refunds it after three days.
100 lines
4.0 KiB
TypeScript
100 lines
4.0 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { hasNativeFeature } from './capabilities';
|
|
import { _resetNativeGeolocation, installNativeGeolocation } from './geolocation';
|
|
import { isNativeApp } from './platform';
|
|
import { TrekShell, type NativeLocationPayload } from './trekShell';
|
|
|
|
vi.mock('./platform', () => ({ isNativeApp: vi.fn() }));
|
|
vi.mock('./capabilities', () => ({ hasNativeFeature: vi.fn() }));
|
|
vi.mock('./trekShell', () => ({
|
|
TrekShell: { startLocation: vi.fn(), stopLocation: vi.fn(), addListener: vi.fn() },
|
|
}));
|
|
|
|
let emit: (payload: NativeLocationPayload) => void = () => {};
|
|
const original = navigator.geolocation;
|
|
|
|
beforeEach(() => {
|
|
_resetNativeGeolocation();
|
|
Object.defineProperty(navigator, 'geolocation', { configurable: true, value: original });
|
|
vi.mocked(isNativeApp).mockReturnValue(true);
|
|
vi.mocked(hasNativeFeature).mockReturnValue(true);
|
|
vi.mocked(TrekShell.startLocation).mockReset().mockResolvedValue();
|
|
vi.mocked(TrekShell.stopLocation).mockReset().mockResolvedValue();
|
|
vi.mocked(TrekShell.addListener)
|
|
.mockReset()
|
|
.mockImplementation(async (_event, listener) => {
|
|
emit = listener as unknown as typeof emit;
|
|
return { remove: async () => {} };
|
|
});
|
|
});
|
|
|
|
const FIX: NativeLocationPayload = {
|
|
latitude: 35.68,
|
|
longitude: 139.76,
|
|
accuracy: 12,
|
|
altitude: null,
|
|
speed: null,
|
|
heading: 90,
|
|
timestamp: 1000,
|
|
};
|
|
|
|
describe('native geolocation', () => {
|
|
it('answers navigator.geolocation from the app, and stops the stream when nobody listens', async () => {
|
|
expect(installNativeGeolocation()).toBe(true);
|
|
const seen: number[] = [];
|
|
const id = navigator.geolocation.watchPosition((p) => seen.push(p.coords.latitude), undefined, {
|
|
enableHighAccuracy: true,
|
|
});
|
|
expect(TrekShell.startLocation).toHaveBeenCalledWith({ highAccuracy: true });
|
|
await Promise.resolve();
|
|
emit(FIX);
|
|
emit({ ...FIX, latitude: 35.7 });
|
|
expect(seen).toEqual([35.68, 35.7]);
|
|
|
|
navigator.geolocation.clearWatch(id);
|
|
expect(TrekShell.stopLocation).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('runs at high accuracy only while a watcher asks for it, and drops back after', () => {
|
|
installNativeGeolocation();
|
|
const passive = navigator.geolocation.watchPosition(vi.fn());
|
|
expect(TrekShell.startLocation).toHaveBeenLastCalledWith({ highAccuracy: false });
|
|
const tracking = navigator.geolocation.watchPosition(vi.fn(), undefined, { enableHighAccuracy: true });
|
|
expect(TrekShell.startLocation).toHaveBeenLastCalledWith({ highAccuracy: true });
|
|
navigator.geolocation.clearWatch(tracking);
|
|
expect(TrekShell.startLocation).toHaveBeenLastCalledWith({ highAccuracy: false });
|
|
expect(TrekShell.startLocation).toHaveBeenCalledTimes(3);
|
|
// A later passive watch does not inherit the high accuracy.
|
|
navigator.geolocation.watchPosition(vi.fn());
|
|
expect(TrekShell.startLocation).toHaveBeenCalledTimes(3);
|
|
navigator.geolocation.clearWatch(passive);
|
|
expect(TrekShell.stopLocation).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('settles a one-off request with the first fix, and passes a denial on as the Geolocation error', async () => {
|
|
installNativeGeolocation();
|
|
const once = vi.fn();
|
|
navigator.geolocation.getCurrentPosition(once);
|
|
await Promise.resolve();
|
|
emit(FIX);
|
|
emit(FIX);
|
|
expect(once).toHaveBeenCalledTimes(1);
|
|
expect(TrekShell.stopLocation).toHaveBeenCalledTimes(1);
|
|
|
|
const failed = vi.fn();
|
|
navigator.geolocation.getCurrentPosition(vi.fn(), failed);
|
|
emit({ error: { code: 1, message: 'denied' } });
|
|
expect(failed.mock.calls[0][0]).toMatchObject({ code: 1, PERMISSION_DENIED: 1 });
|
|
});
|
|
|
|
it('leaves the browser API alone outside an app binary with the feature', () => {
|
|
vi.mocked(hasNativeFeature).mockReturnValue(false);
|
|
expect(installNativeGeolocation()).toBe(false);
|
|
expect(navigator.geolocation).toBe(original);
|
|
vi.mocked(hasNativeFeature).mockReturnValue(true);
|
|
vi.mocked(isNativeApp).mockReturnValue(false);
|
|
expect(installNativeGeolocation()).toBe(false);
|
|
expect(navigator.geolocation).toBe(original);
|
|
});
|
|
});
|