From fce73a454f07c6b73813147257eaaa8f52c280b6 Mon Sep 17 00:00:00 2001 From: Igor Kamyshev Date: Thu, 1 Aug 2024 18:19:58 +0700 Subject: [PATCH] Add correct safe calls --- packages/web-api/src/geolocation.test.ts | 96 ++++++++++++++++++++++++ packages/web-api/src/geolocation.ts | 57 ++++++++------ 2 files changed, 131 insertions(+), 22 deletions(-) diff --git a/packages/web-api/src/geolocation.test.ts b/packages/web-api/src/geolocation.test.ts index a652c86..7bc5ac4 100644 --- a/packages/web-api/src/geolocation.test.ts +++ b/packages/web-api/src/geolocation.test.ts @@ -197,3 +197,99 @@ describe('trackGeolocation, providers as a Store', () => { `); }); }); + +describe('trackGeolocation, failure of provider', () => { + const brokenProvider = () => ({ + async getCurrentPosition() { + throw new Error('Wow, government do not want you to use this provider!'); + }, + watchPosition(success: any, error: any) { + throw new Error('Wow, government do not want you to use this provider!'); + }, + }); + + const slightlyBrokenProvider = () => ({ + async getCurrentPosition() { + throw new Error('Not this time, buddy!'); + }, + watchPosition(success: any, error: any) { + error(new Error('Not this time, buddy!')); + + return () => {}; + }, + }); + + const okProvider = () => ({ + async getCurrentPosition() { + return { + coords: { latitude: 2, longitude: 2 }, + timestamp: Date.now(), + }; + }, + watchPosition(success: any, error: any) { + success({ + coords: { latitude: 2, longitude: 2 }, + timestamp: Date.now(), + }); + return () => {}; + }, + }); + + const geo = trackGeolocation({ + providers: [brokenProvider, slightlyBrokenProvider, okProvider], + }); + + test('request', async () => { + const scope = fork(); + + const failedWatcher = vi.fn(); + createWatch({ unit: geo.reporting.failed, fn: failedWatcher, scope }); + + await allSettled(geo.request, { scope }); + + expect(scope.getState(geo.$location)).toMatchInlineSnapshot(` + { + "latitude": 2, + "longitude": 2, + } + `); + + expect(failedWatcher.mock.calls).toMatchInlineSnapshot(` + [ + [ + [Error: Wow, government do not want you to use this provider!], + ], + [ + [Error: Not this time, buddy!], + ], + ] + `); + }); + + test('watching', async () => { + const scope = fork(); + + const failedWatcher = vi.fn(); + createWatch({ unit: geo.reporting.failed, fn: failedWatcher, scope }); + + await allSettled(geo.watching.start, { scope }); + + expect(scope.getState(geo.$location)).toMatchInlineSnapshot(` + { + "latitude": 2, + "longitude": 2, + } + `); + + expect(failedWatcher.mock.calls).toMatchInlineSnapshot(` + [ + [ + [Error: Wow, government do not want you to use this provider!], + ], + [ + [Error: Not this time, buddy!], + ], + ] + `); + }); +}); diff --git a/packages/web-api/src/geolocation.ts b/packages/web-api/src/geolocation.ts index aded3fd..72400b8 100644 --- a/packages/web-api/src/geolocation.ts +++ b/packages/web-api/src/geolocation.ts @@ -174,14 +174,20 @@ export function trackGeolocation( | CustomGeolocationPosition | null = null; + const boundFailed = scopeBind(failed, { safe: true }); + for (const provider of providers ?? []) { - if (isDefaultProvider(provider)) { - geolocation = await new Promise( - (resolve, reject) => - provider.getCurrentPosition(resolve, reject, params) - ); - } else { - geolocation = await provider.getCurrentPosition(); + try { + if (isDefaultProvider(provider)) { + geolocation = await new Promise( + (resolve, reject) => + provider.getCurrentPosition(resolve, reject, params) + ); + } else { + geolocation = await provider.getCurrentPosition(); + } + } catch (e: any) { + boundFailed(e); } } @@ -217,21 +223,28 @@ export function trackGeolocation( const customUnwatchSet = new Set(); for (const provider of providers ?? []) { - if (isDefaultProvider(provider)) { - const watchId = provider.watchPosition( - boundNewPosition, - boundFailed, - params - ); - - defaultUnwatchMap.set( - (id: number) => provider.clearWatch(id), - watchId - ); - } else { - const unwatch = provider.watchPosition(boundNewPosition, boundFailed); - - customUnwatchSet.add(unwatch); + try { + if (isDefaultProvider(provider)) { + const watchId = provider.watchPosition( + boundNewPosition, + boundFailed, + params + ); + + defaultUnwatchMap.set( + (id: number) => provider.clearWatch(id), + watchId + ); + } else { + const unwatch = provider.watchPosition( + boundNewPosition, + boundFailed + ); + + customUnwatchSet.add(unwatch); + } + } catch (e: any) { + boundFailed(e); } }