From 5adb7c9669f72bc6d9a2f802357cf7d1eca18dc8 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Thu, 26 Oct 2017 10:29:36 -0700 Subject: [PATCH] fix(service-worker): listen for messages on the right event source (#19954) Currently, the SwUpdate service doesn't receive messages from the SW. This is because it attempts to subscribe to the 'message' event on ServiceWorkerRegistration, when really messages are emitted by the ServiceWorkerContainer. This change moves to listening on ServiceWorkerContainer and changes the mocks to reflect the way the browser actually works. PR Close #19954 --- packages/service-worker/src/low_level.ts | 3 +- packages/service-worker/test/comm_spec.ts | 18 ++++----- .../service-worker/test/integration_spec.ts | 2 +- packages/service-worker/testing/mock.ts | 40 +++++++++---------- 4 files changed, 28 insertions(+), 35 deletions(-) diff --git a/packages/service-worker/src/low_level.ts b/packages/service-worker/src/low_level.ts index 48a6c45316..1632ca6bbd 100644 --- a/packages/service-worker/src/low_level.ts +++ b/packages/service-worker/src/low_level.ts @@ -106,8 +106,7 @@ export class NgswCommChannel { this.registration = >( op_switchMap.call(this.worker, () => serviceWorker.getRegistration())); - const rawEvents = >(op_switchMap.call( - this.registration, (reg: ServiceWorkerRegistration) => obs_fromEvent(reg, 'message'))); + const rawEvents = obs_fromEvent(serviceWorker, 'message'); const rawEventPayload = >(op_map.call(rawEvents, (event: MessageEvent) => event.data)); diff --git a/packages/service-worker/test/comm_spec.ts b/packages/service-worker/test/comm_spec.ts index 299af592c6..c1c0d75c80 100644 --- a/packages/service-worker/test/comm_spec.ts +++ b/packages/service-worker/test/comm_spec.ts @@ -44,11 +44,9 @@ export function main() { }); describe('SwPush', () => { let push: SwPush; - let reg: MockServiceWorkerRegistration; - beforeEach((done: DoneFn) => { + beforeEach(() => { push = new SwPush(comm); mock.setupSw(); - mock.mockRegistration.then(r => reg = r).then(() => done()); }); it('receives push messages', (done: DoneFn) => { push.messages.subscribe(msg => { @@ -57,7 +55,7 @@ export function main() { }); done(); }); - reg.sendMessage({ + mock.sendMessage({ type: 'PUSH', data: { message: 'this was a push message', @@ -76,11 +74,9 @@ export function main() { }); describe('SwUpdate', () => { let update: SwUpdate; - let reg: MockServiceWorkerRegistration; - beforeEach((done: DoneFn) => { + beforeEach(() => { update = new SwUpdate(comm); mock.setupSw(); - mock.mockRegistration.then(r => reg = r).then(() => done()); }); it('processes update availability notifications when sent', (done: DoneFn) => { update.available.subscribe(event => { @@ -89,7 +85,7 @@ export function main() { expect(event.type).toEqual('UPDATE_AVAILABLE'); done(); }); - reg.sendMessage({ + mock.sendMessage({ type: 'UPDATE_AVAILABLE', current: { version: 'A', @@ -106,7 +102,7 @@ export function main() { expect(event.type).toEqual('UPDATE_ACTIVATED'); done(); }); - reg.sendMessage({ + mock.sendMessage({ type: 'UPDATE_ACTIVATED', previous: { version: 'A', @@ -119,7 +115,7 @@ export function main() { it('activates updates when requested', (done: DoneFn) => { mock.messages.subscribe((msg: {action: string, statusNonce: number}) => { expect(msg.action).toEqual('ACTIVATE_UPDATE'); - reg.sendMessage({ + mock.sendMessage({ type: 'STATUS', nonce: msg.statusNonce, status: true, @@ -130,7 +126,7 @@ export function main() { it('reports activation failure when requested', (done: DoneFn) => { mock.messages.subscribe((msg: {action: string, statusNonce: number}) => { expect(msg.action).toEqual('ACTIVATE_UPDATE'); - reg.sendMessage({ + mock.sendMessage({ type: 'STATUS', nonce: msg.statusNonce, status: false, diff --git a/packages/service-worker/test/integration_spec.ts b/packages/service-worker/test/integration_spec.ts index 1b3686a32b..de069c3534 100644 --- a/packages/service-worker/test/integration_spec.ts +++ b/packages/service-worker/test/integration_spec.ts @@ -85,7 +85,7 @@ export function main() { driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); scope.clients.add('default'); - scope.clients.getMock('default') !.queue.subscribe(msg => { reg.sendMessage(msg); }); + scope.clients.getMock('default') !.queue.subscribe(msg => { mock.sendMessage(msg); }); mock.messages.subscribe(msg => { scope.handleMessage(msg, 'default'); }); diff --git a/packages/service-worker/testing/mock.ts b/packages/service-worker/testing/mock.ts index 42dccc2da4..0d28454990 100644 --- a/packages/service-worker/testing/mock.ts +++ b/packages/service-worker/testing/mock.ts @@ -10,17 +10,26 @@ import {Subject} from 'rxjs/Subject'; export class MockServiceWorkerContainer { private onControllerChange: Function[] = []; + private onMessage: Function[] = []; private registration: MockServiceWorkerRegistration|null = null; controller: MockServiceWorker|null = null; messages = new Subject(); - addEventListener(event: 'controllerchange', handler: Function) { - this.onControllerChange.push(handler); + addEventListener(event: 'controllerchange'|'message', handler: Function) { + if (event === 'controllerchange') { + this.onControllerChange.push(handler); + } else if (event === 'message') { + this.onMessage.push(handler); + } } removeEventListener(event: 'controllerchange', handler: Function) { - this.onControllerChange = this.onControllerChange.filter(h => h !== handler); + if (event === 'controllerchange') { + this.onControllerChange = this.onControllerChange.filter(h => h !== handler); + } else if (event === 'message') { + this.onMessage = this.onMessage.filter(h => h !== handler); + } } async register(url: string): Promise { return; } @@ -36,6 +45,12 @@ export class MockServiceWorkerContainer { get mockRegistration(): Promise { return Promise.resolve(this.registration !); } + + sendMessage(value: Object): void { + this.onMessage.forEach(onMessage => onMessage({ + data: value, + })); + } } export class MockServiceWorker { @@ -44,21 +59,4 @@ export class MockServiceWorker { postMessage(value: Object) { this.mock.messages.next(value); } } -export class MockServiceWorkerRegistration { - private onMessage: Function[] = []; - messages: Object[] = []; - - constructor() {} - - addEventListener(event: 'message', handler: Function) { this.onMessage.push(handler); } - - removeEventListener(event: 'message', handler: Function) { - this.onMessage = this.onMessage.filter(h => h !== handler); - } - - sendMessage(value: Object): void { - this.onMessage.forEach(onMessage => onMessage({ - data: value, - })); - } -} \ No newline at end of file +export class MockServiceWorkerRegistration {}