From 81c2a94310cda1bc8dde0b30b18c003837a5a25a Mon Sep 17 00:00:00 2001 From: Hoel IRIS Date: Tue, 4 Jun 2019 16:54:24 +0200 Subject: [PATCH] fix(service-worker): avoid uncaught rejection warning when registration fails (#30876) Service worker API `navigator.serviceWorker.register` can fail in multiple ways. For example, in Chrome, with an unstable network connection you can have the following error: `An unknown error occurred when fetching the script.` In the current state, it creates an `Uncaught (in promise) TypeError:` style of error, which cannot be caught by the user on his own. I think it's better to log the error over raising an error that cannot be caught. PR Close #30876 --- packages/service-worker/src/module.ts | 7 ++++--- packages/service-worker/test/module_spec.ts | 13 ++++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/service-worker/src/module.ts b/packages/service-worker/src/module.ts index 39e8f62e65..307f4d3355 100644 --- a/packages/service-worker/src/module.ts +++ b/packages/service-worker/src/module.ts @@ -115,10 +115,11 @@ export function ngswAppInitializer( } } - // Don't return anything to avoid blocking the application until the SW is registered or - // causing a crash if the SW registration fails. + // Don't return anything to avoid blocking the application until the SW is registered. + // Catch and log the error if SW registration fails to avoid uncaught rejection warning. readyToRegister$.pipe(take(1)).subscribe( - () => navigator.serviceWorker.register(script, {scope: options.scope})); + () => navigator.serviceWorker.register(script, {scope: options.scope}) + .catch(err => console.error('Service worker registration failed with:', err))); }; return initializer; } diff --git a/packages/service-worker/test/module_spec.ts b/packages/service-worker/test/module_spec.ts index aec5fe1784..85fbc7e5ae 100644 --- a/packages/service-worker/test/module_spec.ts +++ b/packages/service-worker/test/module_spec.ts @@ -28,7 +28,9 @@ describe('ServiceWorkerModule', () => { return appRef.isStable.pipe(filter(Boolean), take(1)).toPromise(); }; - beforeEach(() => swRegisterSpy = spyOn(navigator.serviceWorker, 'register')); + beforeEach( + () => swRegisterSpy = + spyOn(navigator.serviceWorker, 'register').and.returnValue(Promise.resolve())); describe('register()', () => { const configTestBed = async(opts: SwRegistrationOptions) => { @@ -67,6 +69,15 @@ describe('ServiceWorkerModule', () => { expect(TestBed.get(SwUpdate).isEnabled).toBe(true); expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); }); + + it('catches and a logs registration errors', async() => { + const consoleErrorSpy = spyOn(console, 'error'); + swRegisterSpy.and.returnValue(Promise.reject('no reason')); + + await configTestBed({enabled: true, scope: 'foo'}); + expect(consoleErrorSpy) + .toHaveBeenCalledWith('Service worker registration failed with:', 'no reason'); + }); }); describe('SwRegistrationOptions', () => {