test(service-worker): better align mock event implementations with actual implementations (#42736)

This commit better aligns the mock event implementations used in
ServiceWorker tests (and the associated typings) with the actual
implementations (and the official TypeScript typings). This allows
verifying the ServiceWorker behavior in a slightly more realistic
environment.

This is in preparation of switching from our custom typings to the
official TypeScript typings (`lib.webworker.d.ts`).

PR Close #42736
This commit is contained in:
George Kalpakas 2021-07-08 16:25:15 +03:00 committed by atscott
parent a86c404f14
commit 22a81231f2
4 changed files with 41 additions and 36 deletions

View File

@ -64,29 +64,24 @@ type WindowClientState = 'hidden'|'visible'|'prerender'|'unloaded';
// Fetch API
interface FetchEvent extends ExtendableEvent {
request: Request;
clientId?: string;
resultingClientId?: string;
respondWith(response: Promise<Response>|Response): Promise<Response>;
readonly clientId: string;
readonly preloadResponse: Promise<any>;
readonly request: Request;
readonly resultingClientId: string;
respondWith(r: Response|Promise<Response>): void;
}
interface InstallEvent extends ExtendableEvent {
activeWorker: ServiceWorker;
}
interface ActivateEvent extends ExtendableEvent {}
// Notification API
interface NotificationEvent extends ExtendableEvent {
action: string;
notification: Notification;
readonly action: string;
readonly notification: Notification;
}
// Push API
interface PushEvent extends ExtendableEvent {
data: PushMessageData;
readonly data: PushMessageData|null;
}
interface PushMessageData {
@ -99,13 +94,16 @@ interface PushMessageData {
// Sync API
interface SyncEvent extends ExtendableEvent {
lastChance: boolean;
tag: string;
readonly lastChance: boolean;
readonly tag: string;
}
interface ExtendableMessageEvent extends ExtendableEvent {
data: any;
source: Client|Object;
readonly data: any;
readonly lastEventId: string;
readonly origin: string;
readonly ports: ReadonlyArray<MessagePort>;
readonly source: Client|ServiceWorker|MessagePort|null;
}
// ServiceWorkerGlobalScope

View File

@ -783,7 +783,7 @@ describe('Driver', () => {
const message: any = scope.clients.getMock('default')!.messages[0];
expect(message.type).toEqual('NOTIFICATION_CLICK');
expect(message.data.action).toBeUndefined();
expect(message.data.action).toBe('');
expect(message.data.notification.title).toEqual('This is a test without action');
expect(message.data.notification.body).toEqual('Test body without action');
});

View File

@ -49,7 +49,7 @@ export class MockEvent implements Event {
}
export class MockExtendableEvent extends MockEvent implements ExtendableEvent {
private queue: Promise<void>[] = [];
private queue: Promise<unknown>[] = [];
get ready(): Promise<void> {
return (async () => {
@ -59,7 +59,7 @@ export class MockExtendableEvent extends MockEvent implements ExtendableEvent {
})();
}
waitUntil(promise: Promise<void>): void {
waitUntil(promise: Promise<unknown>): void {
this.queue.push(promise);
}
}
@ -70,7 +70,8 @@ export class MockActivateEvent extends MockExtendableEvent {
}
}
export class MockFetchEvent extends MockExtendableEvent {
export class MockFetchEvent extends MockExtendableEvent implements FetchEvent {
readonly preloadResponse = Promise.resolve();
response: Promise<Response|undefined> = Promise.resolve(undefined);
constructor(
@ -78,9 +79,8 @@ export class MockFetchEvent extends MockExtendableEvent {
super('fetch');
}
respondWith(promise: Promise<Response>): Promise<Response> {
this.response = promise;
return promise;
respondWith(r: Response|Promise<Response>): void {
this.response = Promise.resolve(r);
}
}
@ -90,27 +90,33 @@ export class MockInstallEvent extends MockExtendableEvent {
}
}
export class MockMessageEvent extends MockExtendableEvent {
constructor(readonly data: Object, readonly source: MockClient|null) {
export class MockExtendableMessageEvent extends MockExtendableEvent implements
ExtendableMessageEvent {
readonly lastEventId = '';
readonly origin = '';
readonly ports: ReadonlyArray<MessagePort> = [];
constructor(readonly data: any, readonly source: Client|MessagePort|ServiceWorker|null) {
super('message');
}
}
export class MockNotificationEvent extends MockExtendableEvent {
export class MockNotificationEvent extends MockExtendableEvent implements NotificationEvent {
readonly notification = {
...this._notification,
close: () => undefined,
};
} as Notification;
constructor(private _notification: any, readonly action?: string) {
constructor(private _notification: Partial<Notification>, readonly action = '') {
super('notification');
}
}
export class MockPushEvent extends MockExtendableEvent {
data = {
export class MockPushEvent extends MockExtendableEvent implements PushEvent {
readonly data = {
json: () => this._data,
};
text: () => JSON.stringify(this._data),
} as PushMessageData;
constructor(private _data: object) {
super('push');

View File

@ -13,7 +13,7 @@ import {AssetGroupConfig, Manifest} from '../src/manifest';
import {sha1} from '../src/sha1';
import {MockCacheStorage} from './cache';
import {MockActivateEvent, MockFetchEvent, MockInstallEvent, MockMessageEvent, MockNotificationEvent, MockPushEvent} from './events';
import {MockActivateEvent, MockExtendableMessageEvent, MockFetchEvent, MockInstallEvent, MockNotificationEvent, MockPushEvent} from './events';
import {MockHeaders, MockRequest, MockResponse} from './fetch';
import {MockServerState, MockServerStateBuilder} from './mock';
import {normalizeUrl, parseUrl} from './utils';
@ -244,12 +244,13 @@ export class SwTestHarness extends Adapter<MockCacheStorage> implements ServiceW
if (!this.eventHandlers.has('message')) {
throw new Error('No message handler registered');
}
let event: MockMessageEvent;
let event: MockExtendableMessageEvent;
if (clientId === null) {
event = new MockMessageEvent(data, null);
event = new MockExtendableMessageEvent(data, null);
} else {
this.clients.add(clientId);
event = new MockMessageEvent(data, this.clients.getMock(clientId) || null);
event = new MockExtendableMessageEvent(
data, this.clients.getMock(clientId) as unknown as Client || null);
}
this.eventHandlers.get('message')!.call(this, event);
return event.ready;