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
This commit is contained in:
Alex Rickabaugh 2017-10-26 10:29:36 -07:00 committed by Matias Niemelä
parent 703fcda590
commit 5adb7c9669
4 changed files with 28 additions and 35 deletions

View File

@ -106,8 +106,7 @@ export class NgswCommChannel {
this.registration = <Observable<ServiceWorkerRegistration>>(
op_switchMap.call(this.worker, () => serviceWorker.getRegistration()));
const rawEvents = <Observable<MessageEvent>>(op_switchMap.call(
this.registration, (reg: ServiceWorkerRegistration) => obs_fromEvent(reg, 'message')));
const rawEvents = obs_fromEvent(serviceWorker, 'message');
const rawEventPayload =
<Observable<Object>>(op_map.call(rawEvents, (event: MessageEvent) => event.data));

View File

@ -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,

View File

@ -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'); });

View File

@ -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) {
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) {
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<void> { return; }
@ -36,6 +45,12 @@ export class MockServiceWorkerContainer {
get mockRegistration(): Promise<MockServiceWorkerRegistration> {
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,
}));
}
}
export class MockServiceWorkerRegistration {}