test(service-worker): better align mock global scope implementation with actual implementation (#42736)
This commit better aligns the mock `ServiceWorkerGlobalScope` implementation used in ServiceWorker tests (and the associated typings) with the actual implementation (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:
parent
7c2f80067a
commit
a47aaabf70
|
@ -18,7 +18,7 @@ import {NamedCacheStorage} from './named-cache-storage';
|
|||
*/
|
||||
export class Adapter<T extends CacheStorage = CacheStorage> {
|
||||
readonly caches: NamedCacheStorage<T>;
|
||||
private readonly origin: string;
|
||||
readonly origin: string;
|
||||
|
||||
constructor(protected readonly scopeUrl: string, caches: T) {
|
||||
const parsedScopeUrl = this.parseUrl(this.scopeUrl);
|
||||
|
|
|
@ -106,23 +106,54 @@ interface ExtendableMessageEvent extends ExtendableEvent {
|
|||
readonly source: Client|ServiceWorker|MessagePort|null;
|
||||
}
|
||||
|
||||
// WorkerGlobalScope
|
||||
|
||||
// Explicitly omit the `caches` property to disallow accessing `CacheStorage` APIs directly. All
|
||||
// interactions with `CacheStorage` should go through a `NamedCacheStorage` instance (exposed by the
|
||||
// `Adapter`).
|
||||
interface WorkerGlobalScope extends EventTarget, Omit<WindowOrWorkerGlobalScope, 'caches'> {
|
||||
readonly location: WorkerLocation;
|
||||
readonly navigator: WorkerNavigator;
|
||||
readonly self: WorkerGlobalScope & typeof globalThis;
|
||||
|
||||
importScripts(...urls: string[]): void;
|
||||
addEventListener<K extends keyof WorkerGlobalScopeEventMap>(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof WorkerGlobalScopeEventMap>(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
interface WorkerGlobalScopeEventMap {
|
||||
error: ErrorEvent;
|
||||
languagechange: Event;
|
||||
offline: Event;
|
||||
online: Event;
|
||||
rejectionhandled: PromiseRejectionEvent;
|
||||
unhandledrejection: PromiseRejectionEvent;
|
||||
}
|
||||
|
||||
// ServiceWorkerGlobalScope
|
||||
|
||||
interface ServiceWorkerGlobalScope {
|
||||
// Intentionally does not include a `caches` property to disallow accessing `CacheStorage` APIs
|
||||
// directly. All interactions with `CacheStorage` should go through a `NamedCacheStorage` instance
|
||||
// (exposed by the `Adapter`).
|
||||
clients: Clients;
|
||||
registration: ServiceWorkerRegistration;
|
||||
interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
|
||||
readonly clients: Clients;
|
||||
readonly registration: ServiceWorkerRegistration;
|
||||
readonly serviceWorker: ServiceWorker;
|
||||
|
||||
addEventListener(event: 'activate', fn: (event?: ExtendableEvent) => any): void;
|
||||
addEventListener(event: 'message', fn: (event?: ExtendableMessageEvent) => any): void;
|
||||
addEventListener(event: 'fetch', fn: (event?: FetchEvent) => any): void;
|
||||
addEventListener(event: 'install', fn: (event?: ExtendableEvent) => any): void;
|
||||
addEventListener(event: 'push', fn: (event?: PushEvent) => any): void;
|
||||
addEventListener(event: 'notificationclick', fn: (event?: NotificationEvent) => any): void;
|
||||
addEventListener(event: 'sync', fn: (event?: SyncEvent) => any): void;
|
||||
|
||||
fetch(request: Request|string): Promise<Response>;
|
||||
skipWaiting(): Promise<void>;
|
||||
addEventListener<K extends keyof ServiceWorkerGlobalScopeEventMap>(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof ServiceWorkerGlobalScopeEventMap>(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
interface ServiceWorkerGlobalScopeEventMap extends WorkerGlobalScopeEventMap {
|
||||
activate: ExtendableEvent;
|
||||
fetch: FetchEvent;
|
||||
install: ExtendableEvent;
|
||||
message: ExtendableMessageEvent;
|
||||
messageerror: MessageEvent;
|
||||
notificationclick: NotificationEvent;
|
||||
notificationclose: NotificationEvent;
|
||||
push: PushEvent;
|
||||
sync: SyncEvent;
|
||||
}
|
||||
|
|
|
@ -37,13 +37,16 @@ export class SwTestHarnessBuilder {
|
|||
}
|
||||
|
||||
build(): SwTestHarness {
|
||||
return new SwTestHarness(this.server, this.caches, this.scopeUrl);
|
||||
return new SwTestHarnessImpl(this.server, this.caches, this.scopeUrl) as SwTestHarness;
|
||||
}
|
||||
}
|
||||
|
||||
export class SwTestHarness extends Adapter<MockCacheStorage> implements ServiceWorkerGlobalScope {
|
||||
export type SwTestHarness = SwTestHarnessImpl&ServiceWorkerGlobalScope;
|
||||
|
||||
export class SwTestHarnessImpl extends Adapter<MockCacheStorage> implements
|
||||
Partial<ServiceWorkerGlobalScope> {
|
||||
readonly clients = new MockClients();
|
||||
private eventHandlers = new Map<string, Function>();
|
||||
private eventHandlers = new Map<string, EventListener>();
|
||||
private skippedWaiting = false;
|
||||
|
||||
private selfMessageQueue: any[] = [];
|
||||
|
@ -131,12 +134,26 @@ export class SwTestHarness extends Adapter<MockCacheStorage> implements ServiceW
|
|||
}
|
||||
}
|
||||
|
||||
addEventListener(event: string, handler: Function): void {
|
||||
this.eventHandlers.set(event, handler);
|
||||
addEventListener(
|
||||
type: string, listener: EventListenerOrEventListenerObject,
|
||||
options?: boolean|AddEventListenerOptions): void {
|
||||
if (options !== undefined) {
|
||||
throw new Error('Mock `addEventListener()` does not support `options`.');
|
||||
}
|
||||
|
||||
const handler: EventListener =
|
||||
(typeof listener === 'function') ? listener : evt => listener.handleEvent(evt);
|
||||
this.eventHandlers.set(type, handler);
|
||||
}
|
||||
|
||||
removeEventListener(event: string, handler?: Function): void {
|
||||
this.eventHandlers.delete(event);
|
||||
removeEventListener(
|
||||
type: string, listener: EventListenerOrEventListenerObject,
|
||||
options?: boolean|AddEventListenerOptions): void {
|
||||
if (options !== undefined) {
|
||||
throw new Error('Mock `removeEventListener()` does not support `options`.');
|
||||
}
|
||||
|
||||
this.eventHandlers.delete(type);
|
||||
}
|
||||
|
||||
newRequest(url: string, init: Object = {}): Request {
|
||||
|
|
Loading…
Reference in New Issue