| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  | import {PLATFORM_ID} from '@angular/core'; | 
					
						
							| 
									
										
										
										
											2017-10-16 18:08:41 +08:00
										 |  |  | import {TestBed} from '@angular/core/testing'; | 
					
						
							| 
									
										
										
										
											2018-11-27 17:18:21 -08:00
										 |  |  | import {NgswCommChannel} from '@angular/service-worker/src/low_level'; | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:08 +03:00
										 |  |  | import {SwRegistrationOptions, ngswCommChannelFactory} from '@angular/service-worker/src/module'; | 
					
						
							| 
									
										
										
										
											2018-11-27 17:18:21 -08:00
										 |  |  | import {SwPush} from '@angular/service-worker/src/push'; | 
					
						
							|  |  |  | import {SwUpdate} from '@angular/service-worker/src/update'; | 
					
						
							|  |  |  | import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockServiceWorkerRegistration, patchDecodeBase64} from '@angular/service-worker/testing/mock'; | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-16 14:42:55 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |   describe('ServiceWorker library', () => { | 
					
						
							|  |  |  |     let mock: MockServiceWorkerContainer; | 
					
						
							|  |  |  |     let comm: NgswCommChannel; | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     beforeEach(() => { | 
					
						
							|  |  |  |       mock = new MockServiceWorkerContainer(); | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |       comm = new NgswCommChannel(mock as any); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     describe('NgswCommsChannel', () => { | 
					
						
							| 
									
										
										
										
											2018-07-05 18:10:09 +03:00
										 |  |  |       it('can access the registration when it comes before subscription', done => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         const mock = new MockServiceWorkerContainer(); | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |         const comm = new NgswCommChannel(mock as any); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mock.setupSw(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |         (comm as any).registration.subscribe((reg: any) => { done(); }); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-07-05 18:10:09 +03:00
										 |  |  |       it('can access the registration when it comes after subscription', done => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         const mock = new MockServiceWorkerContainer(); | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |         const comm = new NgswCommChannel(mock as any); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-17 15:10:54 -08:00
										 |  |  |         (comm as any).registration.subscribe((reg: any) => { done(); }); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         mock.setupSw(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |     describe('ngswCommChannelFactory', () => { | 
					
						
							|  |  |  |       it('gives disabled NgswCommChannel for platform-server', () => { | 
					
						
							|  |  |  |         TestBed.configureTestingModule({ | 
					
						
							|  |  |  |           providers: [ | 
					
						
							|  |  |  |             {provide: PLATFORM_ID, useValue: 'server'}, | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:07 +03:00
										 |  |  |             {provide: SwRegistrationOptions, useValue: {enabled: true}}, { | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |               provide: NgswCommChannel, | 
					
						
							|  |  |  |               useFactory: ngswCommChannelFactory, | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:07 +03:00
										 |  |  |               deps: [SwRegistrationOptions, PLATFORM_ID] | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |             } | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 16:22:36 -07:00
										 |  |  |         expect(TestBed.inject(NgswCommChannel).isEnabled).toEqual(false); | 
					
						
							| 
									
										
										
										
											2017-11-12 12:39:27 +13:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |       it('gives disabled NgswCommChannel when \'enabled\' option is false', () => { | 
					
						
							|  |  |  |         TestBed.configureTestingModule({ | 
					
						
							|  |  |  |           providers: [ | 
					
						
							|  |  |  |             {provide: PLATFORM_ID, useValue: 'browser'}, | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:07 +03:00
										 |  |  |             {provide: SwRegistrationOptions, useValue: {enabled: false}}, { | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |               provide: NgswCommChannel, | 
					
						
							|  |  |  |               useFactory: ngswCommChannelFactory, | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:07 +03:00
										 |  |  |               deps: [SwRegistrationOptions, PLATFORM_ID] | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |             } | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 16:22:36 -07:00
										 |  |  |         expect(TestBed.inject(NgswCommChannel).isEnabled).toEqual(false); | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |       }); | 
					
						
							|  |  |  |       it('gives disabled NgswCommChannel when navigator.serviceWorker is undefined', () => { | 
					
						
							|  |  |  |         TestBed.configureTestingModule({ | 
					
						
							|  |  |  |           providers: [ | 
					
						
							|  |  |  |             {provide: PLATFORM_ID, useValue: 'browser'}, | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:07 +03:00
										 |  |  |             {provide: SwRegistrationOptions, useValue: {enabled: true}}, | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |             { | 
					
						
							|  |  |  |               provide: NgswCommChannel, | 
					
						
							|  |  |  |               useFactory: ngswCommChannelFactory, | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:07 +03:00
										 |  |  |               deps: [SwRegistrationOptions, PLATFORM_ID], | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |             }, | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const context: any = global || window; | 
					
						
							|  |  |  |         const originalDescriptor = Object.getOwnPropertyDescriptor(context, 'navigator'); | 
					
						
							|  |  |  |         const patchedDescriptor = {value: {serviceWorker: undefined}, configurable: true}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           // Set `navigator` to `{serviceWorker: undefined}`.
 | 
					
						
							|  |  |  |           Object.defineProperty(context, 'navigator', patchedDescriptor); | 
					
						
							| 
									
										
										
										
											2019-08-28 16:22:36 -07:00
										 |  |  |           expect(TestBed.inject(NgswCommChannel).isEnabled).toBe(false); | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |         } finally { | 
					
						
							|  |  |  |           if (originalDescriptor) { | 
					
						
							|  |  |  |             Object.defineProperty(context, 'navigator', originalDescriptor); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             delete context.navigator; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       it('gives enabled NgswCommChannel when browser supports SW and enabled option is true', | 
					
						
							|  |  |  |          () => { | 
					
						
							|  |  |  |            TestBed.configureTestingModule({ | 
					
						
							|  |  |  |              providers: [ | 
					
						
							|  |  |  |                {provide: PLATFORM_ID, useValue: 'browser'}, | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:07 +03:00
										 |  |  |                {provide: SwRegistrationOptions, useValue: {enabled: true}}, { | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |                  provide: NgswCommChannel, | 
					
						
							|  |  |  |                  useFactory: ngswCommChannelFactory, | 
					
						
							| 
									
										
										
										
											2019-04-25 16:51:07 +03:00
										 |  |  |                  deps: [SwRegistrationOptions, PLATFORM_ID] | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |                } | 
					
						
							|  |  |  |              ] | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            const context: any = global || window; | 
					
						
							|  |  |  |            const originalDescriptor = Object.getOwnPropertyDescriptor(context, 'navigator'); | 
					
						
							|  |  |  |            const patchedDescriptor = {value: {serviceWorker: mock}, configurable: true}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            try { | 
					
						
							|  |  |  |              // Set `navigator` to `{serviceWorker: mock}`.
 | 
					
						
							|  |  |  |              Object.defineProperty(context, 'navigator', patchedDescriptor); | 
					
						
							| 
									
										
										
										
											2019-08-28 16:22:36 -07:00
										 |  |  |              expect(TestBed.inject(NgswCommChannel).isEnabled).toBe(true); | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |            } finally { | 
					
						
							|  |  |  |              if (originalDescriptor) { | 
					
						
							|  |  |  |                Object.defineProperty(context, 'navigator', originalDescriptor); | 
					
						
							|  |  |  |              } else { | 
					
						
							|  |  |  |                delete context.navigator; | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  |            } | 
					
						
							|  |  |  |          }); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-16 18:08:41 +08:00
										 |  |  |     describe('SwPush', () => { | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |       let unpatchDecodeBase64: () => void; | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |       let push: SwPush; | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |       // Patch `SwPush.decodeBase64()` in Node.js (where `atob` is not available).
 | 
					
						
							|  |  |  |       beforeAll(() => unpatchDecodeBase64 = patchDecodeBase64(SwPush.prototype as any)); | 
					
						
							|  |  |  |       afterAll(() => unpatchDecodeBase64()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-26 10:29:36 -07:00
										 |  |  |       beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         push = new SwPush(comm); | 
					
						
							|  |  |  |         mock.setupSw(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-16 18:08:41 +08:00
										 |  |  |       it('is injectable', () => { | 
					
						
							|  |  |  |         TestBed.configureTestingModule({ | 
					
						
							|  |  |  |           providers: [ | 
					
						
							|  |  |  |             SwPush, | 
					
						
							|  |  |  |             {provide: NgswCommChannel, useValue: comm}, | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2019-08-28 16:22:36 -07:00
										 |  |  |         expect(() => TestBed.inject(SwPush)).not.toThrow(); | 
					
						
							| 
									
										
										
										
											2017-10-16 18:08:41 +08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |       describe('requestSubscription()', () => { | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('returns a promise that resolves to the subscription', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           const promise = push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							|  |  |  |           expect(promise).toEqual(jasmine.any(Promise)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           const sub = await promise; | 
					
						
							|  |  |  |           expect(sub).toEqual(jasmine.any(MockPushSubscription)); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('calls `PushManager.subscribe()` (with appropriate options)', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |           const decode = (charCodeArr: Uint8Array) => | 
					
						
							|  |  |  |               Array.from(charCodeArr).map(c => String.fromCharCode(c)).join(''); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           // atob('c3ViamVjdHM/') === 'subjects?'
 | 
					
						
							|  |  |  |           const serverPublicKey = 'c3ViamVjdHM_'; | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |           const appServerKeyStr = 'subjects?'; | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |           const pmSubscribeSpy = spyOn(MockPushManager.prototype, 'subscribe').and.callThrough(); | 
					
						
							|  |  |  |           await push.requestSubscription({serverPublicKey}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(pmSubscribeSpy).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |           expect(pmSubscribeSpy).toHaveBeenCalledWith({ | 
					
						
							|  |  |  |             applicationServerKey: jasmine.any(Uint8Array), | 
					
						
							|  |  |  |             userVisibleOnly: true, | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           const actualAppServerKey = pmSubscribeSpy.calls.first().args[0].applicationServerKey; | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |           const actualAppServerKeyStr = decode(actualAppServerKey); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           expect(actualAppServerKeyStr).toBe(appServerKeyStr); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('emits the new `PushSubscription` on `SwPush.subscription`', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           const subscriptionSpy = jasmine.createSpy('subscriptionSpy'); | 
					
						
							|  |  |  |           push.subscription.subscribe(subscriptionSpy); | 
					
						
							|  |  |  |           const sub = await push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledWith(sub); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe('unsubscribe()', () => { | 
					
						
							|  |  |  |         let psUnsubscribeSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         beforeEach(() => { | 
					
						
							|  |  |  |           psUnsubscribeSpy = spyOn(MockPushSubscription.prototype, 'unsubscribe').and.callThrough(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('rejects if currently not subscribed to push notifications', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           try { | 
					
						
							|  |  |  |             await push.unsubscribe(); | 
					
						
							|  |  |  |             throw new Error('`unsubscribe()` should fail'); | 
					
						
							|  |  |  |           } catch (err) { | 
					
						
							|  |  |  |             expect(err.message).toBe('Not subscribed to push notifications.'); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('calls `PushSubscription.unsubscribe()`', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           await push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							|  |  |  |           await push.unsubscribe(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(psUnsubscribeSpy).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('rejects if `PushSubscription.unsubscribe()` fails', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           psUnsubscribeSpy.and.callFake(() => { throw new Error('foo'); }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           try { | 
					
						
							|  |  |  |             await push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							|  |  |  |             await push.unsubscribe(); | 
					
						
							|  |  |  |             throw new Error('`unsubscribe()` should fail'); | 
					
						
							|  |  |  |           } catch (err) { | 
					
						
							|  |  |  |             expect(err.message).toBe('foo'); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('rejects if `PushSubscription.unsubscribe()` returns false', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           psUnsubscribeSpy.and.returnValue(Promise.resolve(false)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           try { | 
					
						
							|  |  |  |             await push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							|  |  |  |             await push.unsubscribe(); | 
					
						
							|  |  |  |             throw new Error('`unsubscribe()` should fail'); | 
					
						
							|  |  |  |           } catch (err) { | 
					
						
							|  |  |  |             expect(err.message).toBe('Unsubscribe failed!'); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('emits `null` on `SwPush.subscription`', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           const subscriptionSpy = jasmine.createSpy('subscriptionSpy'); | 
					
						
							|  |  |  |           push.subscription.subscribe(subscriptionSpy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           await push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							|  |  |  |           await push.unsubscribe(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledWith(null); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('does not emit on `SwPush.subscription` on failure', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           const subscriptionSpy = jasmine.createSpy('subscriptionSpy'); | 
					
						
							|  |  |  |           const initialSubEmit = new Promise(resolve => subscriptionSpy.and.callFake(resolve)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           push.subscription.subscribe(subscriptionSpy); | 
					
						
							|  |  |  |           await initialSubEmit; | 
					
						
							|  |  |  |           subscriptionSpy.calls.reset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Error due to no subscription.
 | 
					
						
							|  |  |  |           await push.unsubscribe().catch(() => undefined); | 
					
						
							|  |  |  |           expect(subscriptionSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Subscribe.
 | 
					
						
							|  |  |  |           await push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							|  |  |  |           subscriptionSpy.calls.reset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Error due to `PushSubscription.unsubscribe()` error.
 | 
					
						
							|  |  |  |           psUnsubscribeSpy.and.callFake(() => { throw new Error('foo'); }); | 
					
						
							|  |  |  |           await push.unsubscribe().catch(() => undefined); | 
					
						
							|  |  |  |           expect(subscriptionSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Error due to `PushSubscription.unsubscribe()` failure.
 | 
					
						
							|  |  |  |           psUnsubscribeSpy.and.returnValue(Promise.resolve(false)); | 
					
						
							|  |  |  |           await push.unsubscribe().catch(() => undefined); | 
					
						
							|  |  |  |           expect(subscriptionSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe('messages', () => { | 
					
						
							|  |  |  |         it('receives push messages', () => { | 
					
						
							|  |  |  |           const sendMessage = (type: string, message: string) => | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |               mock.sendMessage({type, data: {message}}); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |           const receivedMessages: string[] = []; | 
					
						
							| 
									
										
										
										
											2019-06-14 12:19:09 +02:00
										 |  |  |           push.messages.subscribe((msg: any) => receivedMessages.push(msg.message)); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |           sendMessage('PUSH', 'this was a push message'); | 
					
						
							|  |  |  |           sendMessage('NOTPUSH', 'this was not a push message'); | 
					
						
							|  |  |  |           sendMessage('PUSH', 'this was a push message too'); | 
					
						
							|  |  |  |           sendMessage('HSUP', 'this was a HSUP message'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(receivedMessages).toEqual([ | 
					
						
							|  |  |  |             'this was a push message', | 
					
						
							|  |  |  |             'this was a push message too', | 
					
						
							|  |  |  |           ]); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-09-28 09:43:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-28 10:28:53 +02:00
										 |  |  |       describe('notificationClicks', () => { | 
					
						
							| 
									
										
										
										
											2018-09-07 14:56:40 +02:00
										 |  |  |         it('receives notification clicked messages', () => { | 
					
						
							| 
									
										
										
										
											2018-09-28 09:43:24 +02:00
										 |  |  |           const sendMessage = (type: string, action: string) => | 
					
						
							|  |  |  |               mock.sendMessage({type, data: {action}}); | 
					
						
							| 
									
										
										
										
											2018-09-07 14:56:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           const receivedMessages: string[] = []; | 
					
						
							| 
									
										
										
										
											2018-09-28 10:28:53 +02:00
										 |  |  |           push.notificationClicks.subscribe( | 
					
						
							| 
									
										
										
										
											2018-09-28 09:43:24 +02:00
										 |  |  |               (msg: {action: string}) => receivedMessages.push(msg.action)); | 
					
						
							| 
									
										
										
										
											2018-09-07 14:56:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           sendMessage('NOTIFICATION_CLICK', 'this was a click'); | 
					
						
							| 
									
										
										
										
											2018-09-21 11:09:44 +02:00
										 |  |  |           sendMessage('NOT_IFICATION_CLICK', 'this was not a click'); | 
					
						
							| 
									
										
										
										
											2018-09-07 14:56:40 +02:00
										 |  |  |           sendMessage('NOTIFICATION_CLICK', 'this was a click too'); | 
					
						
							|  |  |  |           sendMessage('KCILC_NOITACIFITON', 'this was a KCILC_NOITACIFITON message'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(receivedMessages).toEqual([ | 
					
						
							|  |  |  |             'this was a click', | 
					
						
							|  |  |  |             'this was a click too', | 
					
						
							|  |  |  |           ]); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |       describe('subscription', () => { | 
					
						
							|  |  |  |         let nextSubEmitResolve: () => void; | 
					
						
							|  |  |  |         let nextSubEmitPromise: Promise<void>; | 
					
						
							|  |  |  |         let subscriptionSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         beforeEach(() => { | 
					
						
							|  |  |  |           nextSubEmitPromise = new Promise(resolve => nextSubEmitResolve = resolve); | 
					
						
							|  |  |  |           subscriptionSpy = jasmine.createSpy('subscriptionSpy').and.callFake(() => { | 
					
						
							|  |  |  |             nextSubEmitResolve(); | 
					
						
							|  |  |  |             nextSubEmitPromise = new Promise(resolve => nextSubEmitResolve = resolve); | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           push.subscription.subscribe(subscriptionSpy); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('emits on worker-driven changes (i.e. when the controller changes)', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           // Initial emit for the current `ServiceWorkerController`.
 | 
					
						
							|  |  |  |           await nextSubEmitPromise; | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledWith(null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           subscriptionSpy.calls.reset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Simulate a `ServiceWorkerController` change.
 | 
					
						
							|  |  |  |           mock.setupSw(); | 
					
						
							|  |  |  |           await nextSubEmitPromise; | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledWith(null); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 15:04:07 +03:00
										 |  |  |         it('emits on subscription changes (i.e. when subscribing/unsubscribing)', async() => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           await nextSubEmitPromise; | 
					
						
							|  |  |  |           subscriptionSpy.calls.reset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Subscribe.
 | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |           await push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           expect(subscriptionSpy).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledWith(jasmine.any(MockPushSubscription)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           subscriptionSpy.calls.reset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Subscribe again.
 | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |           await push.requestSubscription({serverPublicKey: 'test'}); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           expect(subscriptionSpy).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledWith(jasmine.any(MockPushSubscription)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           subscriptionSpy.calls.reset(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Unsubscribe.
 | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |           await push.unsubscribe(); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |           expect(subscriptionSpy).toHaveBeenCalledTimes(1); | 
					
						
							|  |  |  |           expect(subscriptionSpy).toHaveBeenCalledWith(null); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-30 08:22:41 -08:00
										 |  |  |       describe('with no SW', () => { | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |         beforeEach(() => { | 
					
						
							|  |  |  |           comm = new NgswCommChannel(undefined); | 
					
						
							| 
									
										
										
										
											2017-11-30 08:22:41 -08:00
										 |  |  |           push = new SwPush(comm); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         it('does not crash on subscription to observables', () => { | 
					
						
							| 
									
										
										
										
											2017-11-30 08:22:41 -08:00
										 |  |  |           push.messages.toPromise().catch(err => fail(err)); | 
					
						
							| 
									
										
										
										
											2018-09-28 10:28:53 +02:00
										 |  |  |           push.notificationClicks.toPromise().catch(err => fail(err)); | 
					
						
							| 
									
										
										
										
											2017-11-30 08:22:41 -08:00
										 |  |  |           push.subscription.toPromise().catch(err => fail(err)); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-30 08:22:41 -08:00
										 |  |  |         it('gives an error when registering', done => { | 
					
						
							|  |  |  |           push.requestSubscription({serverPublicKey: 'test'}).catch(err => { done(); }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 18:27:51 +03:00
										 |  |  |         it('gives an error when unsubscribing', | 
					
						
							|  |  |  |            done => { push.unsubscribe().catch(err => { done(); }); }); | 
					
						
							| 
									
										
										
										
											2017-11-30 08:22:41 -08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-05-28 16:28:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-16 18:08:41 +08:00
										 |  |  |     describe('SwUpdate', () => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |       let update: SwUpdate; | 
					
						
							| 
									
										
										
										
											2017-10-26 10:29:36 -07:00
										 |  |  |       beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         update = new SwUpdate(comm); | 
					
						
							|  |  |  |         mock.setupSw(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-07-05 18:10:09 +03:00
										 |  |  |       it('processes update availability notifications when sent', done => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         update.available.subscribe(event => { | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |           expect(event.current).toEqual({hash: 'A'}); | 
					
						
							|  |  |  |           expect(event.available).toEqual({hash: 'B'}); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |           expect(event.type).toEqual('UPDATE_AVAILABLE'); | 
					
						
							|  |  |  |           done(); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-10-26 10:29:36 -07:00
										 |  |  |         mock.sendMessage({ | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |           type: 'UPDATE_AVAILABLE', | 
					
						
							|  |  |  |           current: { | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |             hash: 'A', | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |           }, | 
					
						
							|  |  |  |           available: { | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |             hash: 'B', | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |           }, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-07-05 18:10:09 +03:00
										 |  |  |       it('processes update activation notifications when sent', done => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         update.activated.subscribe(event => { | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |           expect(event.previous).toEqual({hash: 'A'}); | 
					
						
							|  |  |  |           expect(event.current).toEqual({hash: 'B'}); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |           expect(event.type).toEqual('UPDATE_ACTIVATED'); | 
					
						
							|  |  |  |           done(); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-10-26 10:29:36 -07:00
										 |  |  |         mock.sendMessage({ | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |           type: 'UPDATE_ACTIVATED', | 
					
						
							|  |  |  |           previous: { | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |             hash: 'A', | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |           }, | 
					
						
							|  |  |  |           current: { | 
					
						
							| 
									
										
										
										
											2017-10-24 14:54:08 +03:00
										 |  |  |             hash: 'B', | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |           }, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-07-05 18:10:09 +03:00
										 |  |  |       it('activates updates when requested', done => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         mock.messages.subscribe((msg: {action: string, statusNonce: number}) => { | 
					
						
							|  |  |  |           expect(msg.action).toEqual('ACTIVATE_UPDATE'); | 
					
						
							| 
									
										
										
										
											2017-10-26 10:29:36 -07:00
										 |  |  |           mock.sendMessage({ | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |             type: 'STATUS', | 
					
						
							|  |  |  |             nonce: msg.statusNonce, | 
					
						
							|  |  |  |             status: true, | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         return update.activateUpdate().then(() => done()).catch(err => done.fail(err)); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-07-05 18:10:09 +03:00
										 |  |  |       it('reports activation failure when requested', done => { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |         mock.messages.subscribe((msg: {action: string, statusNonce: number}) => { | 
					
						
							|  |  |  |           expect(msg.action).toEqual('ACTIVATE_UPDATE'); | 
					
						
							| 
									
										
										
										
											2017-10-26 10:29:36 -07:00
										 |  |  |           mock.sendMessage({ | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |             type: 'STATUS', | 
					
						
							|  |  |  |             nonce: msg.statusNonce, | 
					
						
							|  |  |  |             status: false, | 
					
						
							|  |  |  |             error: 'Failed to activate', | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         return update.activateUpdate() | 
					
						
							|  |  |  |             .catch(err => { expect(err.message).toEqual('Failed to activate'); }) | 
					
						
							|  |  |  |             .then(() => done()) | 
					
						
							|  |  |  |             .catch(err => done.fail(err)); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-10-16 18:08:41 +08:00
										 |  |  |       it('is injectable', () => { | 
					
						
							|  |  |  |         TestBed.configureTestingModule({ | 
					
						
							|  |  |  |           providers: [ | 
					
						
							|  |  |  |             SwUpdate, | 
					
						
							|  |  |  |             {provide: NgswCommChannel, useValue: comm}, | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2019-08-28 16:22:36 -07:00
										 |  |  |         expect(() => TestBed.inject(SwUpdate)).not.toThrow(); | 
					
						
							| 
									
										
										
										
											2017-10-16 18:08:41 +08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-11-30 08:22:41 -08:00
										 |  |  |       describe('with no SW', () => { | 
					
						
							| 
									
										
										
										
											2018-05-10 00:11:43 +09:00
										 |  |  |         beforeEach(() => { comm = new NgswCommChannel(undefined); }); | 
					
						
							| 
									
										
										
										
											2017-11-30 08:22:41 -08:00
										 |  |  |         it('can be instantiated', () => { update = new SwUpdate(comm); }); | 
					
						
							|  |  |  |         it('does not crash on subscription to observables', () => { | 
					
						
							|  |  |  |           update = new SwUpdate(comm); | 
					
						
							|  |  |  |           update.available.toPromise().catch(err => fail(err)); | 
					
						
							|  |  |  |           update.activated.toPromise().catch(err => fail(err)); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         it('gives an error when checking for updates', done => { | 
					
						
							|  |  |  |           update = new SwUpdate(comm); | 
					
						
							|  |  |  |           update.checkForUpdate().catch(err => { done(); }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         it('gives an error when activating updates', done => { | 
					
						
							|  |  |  |           update = new SwUpdate(comm); | 
					
						
							|  |  |  |           update.activateUpdate().catch(err => { done(); }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } |