fix(service-worker): Fix public api guard typing (#25860)

PR Close #25860
This commit is contained in:
Joost Zöllner 2018-09-28 10:28:53 +02:00 committed by Kara Erickson
parent 10618752e6
commit 4a01ada291
8 changed files with 29 additions and 29 deletions

View File

@ -52,8 +52,6 @@ interface StatusEvent {
error?: string; error?: string;
} }
export interface NotificationObject extends NotificationOptions { title: string; }
function errorObservable(message: string): Observable<any> { function errorObservable(message: string): Observable<any> {
return defer(() => throwError(new Error(message))); return defer(() => throwError(new Error(message)));

View File

@ -10,7 +10,7 @@ import {Injectable} from '@angular/core';
import {NEVER, Observable, Subject, merge} from 'rxjs'; import {NEVER, Observable, Subject, merge} from 'rxjs';
import {map, switchMap, take} from 'rxjs/operators'; import {map, switchMap, take} from 'rxjs/operators';
import {ERR_SW_NOT_SUPPORTED, NgswCommChannel, NotificationObject, PushEvent} from './low_level'; import {ERR_SW_NOT_SUPPORTED, NgswCommChannel, PushEvent} from './low_level';
/** /**
@ -30,14 +30,16 @@ export class SwPush {
* interacted with. * interacted with.
* If no action was used the action property will be an empty string `''`. * If no action was used the action property will be an empty string `''`.
* *
* Note that the `notification` property is __not__ a * Note that the `notification` property is **not** a
* [Notification](https://developer.mozilla.org/en-US/docs/Web/API/Notification) but rather a * [Notification](https://developer.mozilla.org/en-US/docs/Web/API/Notification) object but rather
* a
* [NotificationOptions](https://notifications.spec.whatwg.org/#dictdef-notificationoptions) * [NotificationOptions](https://notifications.spec.whatwg.org/#dictdef-notificationoptions)
* object that also includes the notification `title`. * object that also includes the `title` of the
* [Notification](https://developer.mozilla.org/en-US/docs/Web/API/Notification) object.
*/ */
readonly messagesClicked: Observable < { readonly notificationClicks: Observable < {
action: string; action: string;
notification: NotificationObject notification: NotificationOptions&{ title: string }
} }
> ; > ;
@ -61,14 +63,14 @@ export class SwPush {
constructor(private sw: NgswCommChannel) { constructor(private sw: NgswCommChannel) {
if (!sw.isEnabled) { if (!sw.isEnabled) {
this.messages = NEVER; this.messages = NEVER;
this.messagesClicked = NEVER; this.notificationClicks = NEVER;
this.subscription = NEVER; this.subscription = NEVER;
return; return;
} }
this.messages = this.sw.eventsOfType<PushEvent>('PUSH').pipe(map(message => message.data)); this.messages = this.sw.eventsOfType<PushEvent>('PUSH').pipe(map(message => message.data));
this.messagesClicked = this.notificationClicks =
this.sw.eventsOfType('NOTIFICATION_CLICK').pipe(map((message: any) => message.data)); this.sw.eventsOfType('NOTIFICATION_CLICK').pipe(map((message: any) => message.data));
this.pushManager = this.sw.registration.pipe(map(registration => registration.pushManager)); this.pushManager = this.sw.registration.pipe(map(registration => registration.pushManager));

View File

@ -304,13 +304,13 @@ import {async_fit, async_it} from './async';
}); });
}); });
describe('messagesClicked', () => { describe('notificationClicks', () => {
it('receives notification clicked messages', () => { it('receives notification clicked messages', () => {
const sendMessage = (type: string, action: string) => const sendMessage = (type: string, action: string) =>
mock.sendMessage({type, data: {action}}); mock.sendMessage({type, data: {action}});
const receivedMessages: string[] = []; const receivedMessages: string[] = [];
push.messagesClicked.subscribe( push.notificationClicks.subscribe(
(msg: {action: string}) => receivedMessages.push(msg.action)); (msg: {action: string}) => receivedMessages.push(msg.action));
sendMessage('NOTIFICATION_CLICK', 'this was a click'); sendMessage('NOTIFICATION_CLICK', 'this was a click');
@ -388,7 +388,7 @@ import {async_fit, async_it} from './async';
it('does not crash on subscription to observables', () => { it('does not crash on subscription to observables', () => {
push.messages.toPromise().catch(err => fail(err)); push.messages.toPromise().catch(err => fail(err));
push.messagesClicked.toPromise().catch(err => fail(err)); push.notificationClicks.toPromise().catch(err => fail(err));
push.subscription.toPromise().catch(err => fail(err)); push.subscription.toPromise().catch(err => fail(err));
}); });

View File

@ -88,7 +88,7 @@ const serverUpdate =
scope.clients.getMock('default') !.queue.subscribe(msg => { mock.sendMessage(msg); }); scope.clients.getMock('default') !.queue.subscribe(msg => { mock.sendMessage(msg); });
mock.messages.subscribe(msg => { scope.handleMessage(msg, 'default'); }); mock.messages.subscribe(msg => { scope.handleMessage(msg, 'default'); });
mock.messagesClicked.subscribe(msg => { scope.handleMessage(msg, 'default'); }); mock.notificationClicks.subscribe(msg => { scope.handleMessage(msg, 'default'); });
mock.setupSw(); mock.setupSw();
reg = mock.mockRegistration !; reg = mock.mockRegistration !;
@ -135,7 +135,7 @@ const serverUpdate =
scope.updateServerState(serverUpdate); scope.updateServerState(serverUpdate);
const gotNotificationClick = (async() => { const gotNotificationClick = (async() => {
const event: any = await obsToSinglePromise(push.messagesClicked); const event: any = await obsToSinglePromise(push.notificationClicks);
expect(event.action).toEqual('clicked'); expect(event.action).toEqual('clicked');
expect(event.notification.title).toEqual('This is a test'); expect(event.notification.title).toEqual('This is a test');
})(); })();

View File

@ -28,7 +28,7 @@ export class MockServiceWorkerContainer {
mockRegistration: MockServiceWorkerRegistration|null = null; mockRegistration: MockServiceWorkerRegistration|null = null;
controller: MockServiceWorker|null = null; controller: MockServiceWorker|null = null;
messages = new Subject(); messages = new Subject();
messagesClicked = new Subject(); notificationClicks = new Subject();
addEventListener(event: 'controllerchange'|'message', handler: Function) { addEventListener(event: 'controllerchange'|'message', handler: Function) {
if (event === 'controllerchange') { if (event === 'controllerchange') {

View File

@ -29,13 +29,9 @@ const IDLE_THRESHOLD = 5000;
const SUPPORTED_CONFIG_VERSION = 1; const SUPPORTED_CONFIG_VERSION = 1;
const NOTIFICATION_OPTION_NAMES = [ const NOTIFICATION_OPTION_NAMES: (keyof Notification)[] = [
'actions', 'badge', 'body', 'dir', 'icon', 'lang', 'renotify', 'requireInteraction', 'tag', 'actions', 'badge', 'body', 'data', 'dir', 'icon', 'image', 'lang', 'renotify',
'vibrate', 'data' 'requireInteraction', 'silent', 'tag', 'timestamp', 'title', 'vibrate'
];
const NOTIFICATION_CLICK_OPTION_NAMES = [
'actions', 'badge', 'title', 'body', 'dir', 'icon', 'image', 'lang', 'renotify',
'requireInteraction', 'tag', 'timestamp', 'vibrate', 'data'
]; ];
interface LatestEntry { interface LatestEntry {
@ -312,10 +308,9 @@ export class Driver implements Debuggable, UpdateSource {
private async handleClick(notification: Notification, action?: string): Promise<void> { private async handleClick(notification: Notification, action?: string): Promise<void> {
notification.close(); notification.close();
const desc = notification as any; const options: {-readonly[K in keyof Notification]?: Notification[K]} = {};
let options: {[key: string]: string | undefined} = {}; NOTIFICATION_OPTION_NAMES.filter(name => name in notification)
NOTIFICATION_CLICK_OPTION_NAMES.filter(name => desc.hasOwnProperty(name)) .forEach(name => options[name] = notification[name]);
.forEach(name => options[name] = desc[name]);
await this.broadcast({ await this.broadcast({
type: 'NOTIFICATION_CLICK', type: 'NOTIFICATION_CLICK',

View File

@ -576,7 +576,7 @@ const manifestUpdateHash = sha1(JSON.stringify(manifestUpdate));
}); });
expect(scope.notifications).toEqual([{ expect(scope.notifications).toEqual([{
title: 'This is a test', title: 'This is a test',
options: {body: 'Test body'}, options: {title: 'This is a test', body: 'Test body'},
}]); }]);
expect(scope.clients.getMock('default') !.messages).toEqual([{ expect(scope.clients.getMock('default') !.messages).toEqual([{
type: 'PUSH', type: 'PUSH',

View File

@ -8,7 +8,12 @@ export declare class ServiceWorkerModule {
export declare class SwPush { export declare class SwPush {
readonly isEnabled: boolean; readonly isEnabled: boolean;
readonly messages: Observable<object>; readonly messages: Observable<object>;
readonly messagesClicked: Observable<{ action: string; notification: NotificationObject }>; readonly notificationClicks: Observable<{
action: string;
notification: NotificationOptions & {
title: string;
};
}>;
readonly subscription: Observable<PushSubscription | null>; readonly subscription: Observable<PushSubscription | null>;
constructor(sw: NgswCommChannel); constructor(sw: NgswCommChannel);
requestSubscription(options: { requestSubscription(options: {