@ -28,14 +28,19 @@ export class MockCacheStorage implements CacheStorage {
|
||||
constructor(private origin: string, hydrateFrom?: string) {
|
||||
if (hydrateFrom !== undefined) {
|
||||
const hydrated = JSON.parse(hydrateFrom) as DehydratedCacheStorage;
|
||||
Object.keys(hydrated).forEach(
|
||||
name => { this.caches.set(name, new MockCache(this.origin, hydrated[name])); });
|
||||
Object.keys(hydrated).forEach(name => {
|
||||
this.caches.set(name, new MockCache(this.origin, hydrated[name]));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async has(name: string): Promise<boolean> { return this.caches.has(name); }
|
||||
async has(name: string): Promise<boolean> {
|
||||
return this.caches.has(name);
|
||||
}
|
||||
|
||||
async keys(): Promise<string[]> { return Array.from(this.caches.keys()); }
|
||||
async keys(): Promise<string[]> {
|
||||
return Array.from(this.caches.keys());
|
||||
}
|
||||
|
||||
async open(name: string): Promise<Cache> {
|
||||
if (!this.caches.has(name)) {
|
||||
@ -67,7 +72,7 @@ export class MockCacheStorage implements CacheStorage {
|
||||
dehydrate(): string {
|
||||
const dehydrated: DehydratedCacheStorage = {};
|
||||
Array.from(this.caches.keys()).forEach(name => {
|
||||
const cache = this.caches.get(name) !;
|
||||
const cache = this.caches.get(name)!;
|
||||
dehydrated[name] = cache.dehydrate();
|
||||
});
|
||||
return JSON.stringify(dehydrated);
|
||||
@ -82,16 +87,21 @@ export class MockCache {
|
||||
Object.keys(hydrated).forEach(url => {
|
||||
const resp = hydrated[url];
|
||||
this.cache.set(
|
||||
url, new MockResponse(
|
||||
resp.body,
|
||||
{status: resp.status, statusText: resp.statusText, headers: resp.headers}));
|
||||
url,
|
||||
new MockResponse(
|
||||
resp.body,
|
||||
{status: resp.status, statusText: resp.statusText, headers: resp.headers}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async add(request: RequestInfo): Promise<void> { throw 'Not implemented'; }
|
||||
async add(request: RequestInfo): Promise<void> {
|
||||
throw 'Not implemented';
|
||||
}
|
||||
|
||||
async addAll(requests: RequestInfo[]): Promise<void> { throw 'Not implemented'; }
|
||||
async addAll(requests: RequestInfo[]): Promise<void> {
|
||||
throw 'Not implemented';
|
||||
}
|
||||
|
||||
async 'delete'(request: RequestInfo): Promise<boolean> {
|
||||
const url = (typeof request === 'string' ? request : request.url);
|
||||
@ -119,7 +129,7 @@ export class MockCache {
|
||||
if (res !== undefined) {
|
||||
res = res.clone();
|
||||
}
|
||||
return res !;
|
||||
return res!;
|
||||
}
|
||||
|
||||
async matchAll(request?: Request|string, options?: CacheQueryOptions): Promise<Response[]> {
|
||||
@ -128,7 +138,7 @@ export class MockCache {
|
||||
}
|
||||
const url = (typeof request === 'string' ? request : request.url);
|
||||
if (this.cache.has(url)) {
|
||||
return [this.cache.get(url) !];
|
||||
return [this.cache.get(url)!];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
@ -156,8 +166,9 @@ export class MockCache {
|
||||
headers: {},
|
||||
} as DehydratedResponse;
|
||||
|
||||
resp.headers.forEach(
|
||||
(value: string, name: string) => { dehydratedResp.headers[name] = value; });
|
||||
resp.headers.forEach((value: string, name: string) => {
|
||||
dehydratedResp.headers[name] = value;
|
||||
});
|
||||
|
||||
dehydrated[url] = dehydratedResp;
|
||||
});
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
export class MockBody implements Body {
|
||||
readonly body !: ReadableStream;
|
||||
readonly body!: ReadableStream;
|
||||
bodyUsed: boolean = false;
|
||||
|
||||
constructor(public _body: string|null) {}
|
||||
@ -24,13 +24,21 @@ export class MockBody implements Body {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
async blob(): Promise<Blob> { throw 'Not implemented'; }
|
||||
async blob(): Promise<Blob> {
|
||||
throw 'Not implemented';
|
||||
}
|
||||
|
||||
async json(): Promise<any> { return JSON.parse(this.getBody()); }
|
||||
async json(): Promise<any> {
|
||||
return JSON.parse(this.getBody());
|
||||
}
|
||||
|
||||
async text(): Promise<string> { return this.getBody(); }
|
||||
async text(): Promise<string> {
|
||||
return this.getBody();
|
||||
}
|
||||
|
||||
async formData(): Promise<FormData> { throw 'Not implemented'; }
|
||||
async formData(): Promise<FormData> {
|
||||
throw 'Not implemented';
|
||||
}
|
||||
|
||||
private getBody(): string {
|
||||
if (this.bodyUsed === true) {
|
||||
@ -47,31 +55,51 @@ export class MockBody implements Body {
|
||||
export class MockHeaders implements Headers {
|
||||
map = new Map<string, string>();
|
||||
|
||||
[Symbol.iterator]() { return this.map[Symbol.iterator](); }
|
||||
[Symbol.iterator]() {
|
||||
return this.map[Symbol.iterator]();
|
||||
}
|
||||
|
||||
append(name: string, value: string): void { this.map.set(name.toLowerCase(), value); }
|
||||
append(name: string, value: string): void {
|
||||
this.map.set(name.toLowerCase(), value);
|
||||
}
|
||||
|
||||
delete (name: string): void { this.map.delete(name.toLowerCase()); }
|
||||
delete(name: string): void {
|
||||
this.map.delete(name.toLowerCase());
|
||||
}
|
||||
|
||||
entries() { return this.map.entries(); }
|
||||
entries() {
|
||||
return this.map.entries();
|
||||
}
|
||||
|
||||
forEach(callback: Function): void { this.map.forEach(callback as any); }
|
||||
forEach(callback: Function): void {
|
||||
this.map.forEach(callback as any);
|
||||
}
|
||||
|
||||
get(name: string): string|null { return this.map.get(name.toLowerCase()) || null; }
|
||||
get(name: string): string|null {
|
||||
return this.map.get(name.toLowerCase()) || null;
|
||||
}
|
||||
|
||||
has(name: string): boolean { return this.map.has(name.toLowerCase()); }
|
||||
has(name: string): boolean {
|
||||
return this.map.has(name.toLowerCase());
|
||||
}
|
||||
|
||||
keys() { return this.map.keys(); }
|
||||
keys() {
|
||||
return this.map.keys();
|
||||
}
|
||||
|
||||
set(name: string, value: string): void { this.map.set(name.toLowerCase(), value); }
|
||||
set(name: string, value: string): void {
|
||||
this.map.set(name.toLowerCase(), value);
|
||||
}
|
||||
|
||||
values() { return this.map.values(); }
|
||||
values() {
|
||||
return this.map.values();
|
||||
}
|
||||
}
|
||||
|
||||
export class MockRequest extends MockBody implements Request {
|
||||
readonly isHistoryNavigation: boolean = false;
|
||||
readonly isReloadNavigation: boolean = false;
|
||||
readonly body !: ReadableStream;
|
||||
readonly body!: ReadableStream;
|
||||
readonly cache: RequestCache = 'default';
|
||||
readonly credentials: RequestCredentials = 'omit';
|
||||
readonly destination: RequestDestination = 'document';
|
||||
@ -88,17 +116,19 @@ export class MockRequest extends MockBody implements Request {
|
||||
url: string;
|
||||
|
||||
constructor(input: string|Request, init: RequestInit = {}) {
|
||||
super(init !== undefined ? (init.body as(string | null)) || null : null);
|
||||
super(init !== undefined ? (init.body as (string | null)) || null : null);
|
||||
if (typeof input !== 'string') {
|
||||
throw 'Not implemented';
|
||||
}
|
||||
this.url = input;
|
||||
const headers = init.headers as{[key: string]: string};
|
||||
const headers = init.headers as {[key: string]: string};
|
||||
if (headers !== undefined) {
|
||||
if (headers instanceof MockHeaders) {
|
||||
this.headers = headers;
|
||||
} else {
|
||||
Object.keys(headers).forEach(header => { this.headers.set(header, headers[header]); });
|
||||
Object.keys(headers).forEach(header => {
|
||||
this.headers.set(header, headers[header]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (init.cache !== undefined) {
|
||||
@ -128,7 +158,9 @@ export class MockRequest extends MockBody implements Request {
|
||||
export class MockResponse extends MockBody implements Response {
|
||||
readonly trailer: Promise<Headers> = Promise.resolve(new MockHeaders());
|
||||
readonly headers: Headers = new MockHeaders();
|
||||
get ok(): boolean { return this.status >= 200 && this.status < 300; }
|
||||
get ok(): boolean {
|
||||
return this.status >= 200 && this.status < 300;
|
||||
}
|
||||
readonly status: number;
|
||||
readonly statusText: string;
|
||||
readonly type: ResponseType = 'basic';
|
||||
@ -141,12 +173,14 @@ export class MockResponse extends MockBody implements Response {
|
||||
super(typeof body === 'string' ? body : null);
|
||||
this.status = (init.status !== undefined) ? init.status : 200;
|
||||
this.statusText = init.statusText || 'OK';
|
||||
const headers = init.headers as{[key: string]: string};
|
||||
const headers = init.headers as {[key: string]: string};
|
||||
if (headers !== undefined) {
|
||||
if (headers instanceof MockHeaders) {
|
||||
this.headers = headers;
|
||||
} else {
|
||||
Object.keys(headers).forEach(header => { this.headers.set(header, headers[header]); });
|
||||
Object.keys(headers).forEach(header => {
|
||||
this.headers.set(header, headers[header]);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (init.type !== undefined) {
|
||||
|
@ -20,7 +20,9 @@ export class MockFile {
|
||||
readonly path: string, readonly contents: string, readonly headers = {},
|
||||
readonly hashThisFile: boolean) {}
|
||||
|
||||
get hash(): string { return sha1(this.contents); }
|
||||
get hash(): string {
|
||||
return sha1(this.contents);
|
||||
}
|
||||
}
|
||||
|
||||
export class MockFileSystemBuilder {
|
||||
@ -36,18 +38,22 @@ export class MockFileSystemBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): MockFileSystem { return new MockFileSystem(this.resources); }
|
||||
build(): MockFileSystem {
|
||||
return new MockFileSystem(this.resources);
|
||||
}
|
||||
}
|
||||
|
||||
export class MockFileSystem {
|
||||
constructor(private resources: Map<string, MockFile>) {}
|
||||
|
||||
lookup(path: string): MockFile|undefined { return this.resources.get(path); }
|
||||
lookup(path: string): MockFile|undefined {
|
||||
return this.resources.get(path);
|
||||
}
|
||||
|
||||
extend(): MockFileSystemBuilder {
|
||||
const builder = new MockFileSystemBuilder();
|
||||
Array.from(this.resources.keys()).forEach(path => {
|
||||
const res = this.resources.get(path) !;
|
||||
const res = this.resources.get(path)!;
|
||||
if (res.hashThisFile) {
|
||||
builder.addFile(path, res.contents, res.headers);
|
||||
} else {
|
||||
@ -57,7 +63,9 @@ export class MockFileSystem {
|
||||
return builder;
|
||||
}
|
||||
|
||||
list(): string[] { return Array.from(this.resources.keys()); }
|
||||
list(): string[] {
|
||||
return Array.from(this.resources.keys());
|
||||
}
|
||||
}
|
||||
|
||||
export class MockServerStateBuilder {
|
||||
@ -66,7 +74,7 @@ export class MockServerStateBuilder {
|
||||
|
||||
withStaticFiles(fs: MockFileSystem): MockServerStateBuilder {
|
||||
fs.list().forEach(path => {
|
||||
const file = fs.lookup(path) !;
|
||||
const file = fs.lookup(path)!;
|
||||
this.resources.set(path, new MockResponse(file.contents, {headers: file.headers}));
|
||||
});
|
||||
return this;
|
||||
@ -102,17 +110,21 @@ export class MockServerState {
|
||||
private gate: Promise<void> = Promise.resolve();
|
||||
private resolve: Function|null = null;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private resolveNextRequest !: Function;
|
||||
private resolveNextRequest!: Function;
|
||||
online = true;
|
||||
nextRequest: Promise<Request>;
|
||||
|
||||
constructor(private resources: Map<string, Response>, private errors: Set<string>) {
|
||||
this.nextRequest = new Promise(resolve => { this.resolveNextRequest = resolve; });
|
||||
this.nextRequest = new Promise(resolve => {
|
||||
this.resolveNextRequest = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
async fetch(req: Request): Promise<Response> {
|
||||
this.resolveNextRequest(req);
|
||||
this.nextRequest = new Promise(resolve => { this.resolveNextRequest = resolve; });
|
||||
this.nextRequest = new Promise(resolve => {
|
||||
this.resolveNextRequest = resolve;
|
||||
});
|
||||
|
||||
await this.gate;
|
||||
|
||||
@ -127,7 +139,7 @@ export class MockServerState {
|
||||
}
|
||||
const url = req.url.split('?')[0];
|
||||
if (this.resources.has(url)) {
|
||||
return this.resources.get(url) !.clone();
|
||||
return this.resources.get(url)!.clone();
|
||||
}
|
||||
if (this.errors.has(url)) {
|
||||
throw new Error('Intentional failure!');
|
||||
@ -136,7 +148,9 @@ export class MockServerState {
|
||||
}
|
||||
|
||||
pause(): void {
|
||||
this.gate = new Promise(resolve => { this.resolve = resolve; });
|
||||
this.gate = new Promise(resolve => {
|
||||
this.resolve = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
unpause(): void {
|
||||
@ -170,18 +184,24 @@ export class MockServerState {
|
||||
|
||||
assertNoOtherRequests(): void {
|
||||
if (!this.noOtherRequests()) {
|
||||
throw new Error(
|
||||
`Expected no other requests, got requests for ${this.requests.map(req => req.url.split('?')[0]).join(', ')}`);
|
||||
throw new Error(`Expected no other requests, got requests for ${
|
||||
this.requests.map(req => req.url.split('?')[0]).join(', ')}`);
|
||||
}
|
||||
}
|
||||
|
||||
noOtherRequests(): boolean { return this.requests.length === 0; }
|
||||
noOtherRequests(): boolean {
|
||||
return this.requests.length === 0;
|
||||
}
|
||||
|
||||
clearRequests(): void { this.requests = []; }
|
||||
clearRequests(): void {
|
||||
this.requests = [];
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.clearRequests();
|
||||
this.nextRequest = new Promise(resolve => { this.resolveNextRequest = resolve; });
|
||||
this.nextRequest = new Promise(resolve => {
|
||||
this.resolveNextRequest = resolve;
|
||||
});
|
||||
this.gate = Promise.resolve();
|
||||
this.resolve = null;
|
||||
this.online = true;
|
||||
@ -191,7 +211,9 @@ export class MockServerState {
|
||||
export function tmpManifestSingleAssetGroup(fs: MockFileSystem): Manifest {
|
||||
const files = fs.list();
|
||||
const hashTable: {[url: string]: string} = {};
|
||||
files.forEach(path => { hashTable[path] = fs.lookup(path) !.hash; });
|
||||
files.forEach(path => {
|
||||
hashTable[path] = fs.lookup(path)!.hash;
|
||||
});
|
||||
return {
|
||||
configVersion: 1,
|
||||
timestamp: 1234567890123,
|
||||
@ -205,7 +227,8 @@ export function tmpManifestSingleAssetGroup(fs: MockFileSystem): Manifest {
|
||||
patterns: [],
|
||||
},
|
||||
],
|
||||
navigationUrls: [], hashTable,
|
||||
navigationUrls: [],
|
||||
hashTable,
|
||||
};
|
||||
}
|
||||
|
||||
@ -213,7 +236,7 @@ export function tmpHashTableForFs(
|
||||
fs: MockFileSystem, breakHashes: {[url: string]: boolean} = {}): {[url: string]: string} {
|
||||
const table: {[url: string]: string} = {};
|
||||
fs.list().forEach(path => {
|
||||
const file = fs.lookup(path) !;
|
||||
const file = fs.lookup(path)!;
|
||||
if (file.hashThisFile) {
|
||||
table[path] = file.hash;
|
||||
if (breakHashes[path]) {
|
||||
|
@ -47,7 +47,9 @@ export class SwTestHarnessBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): SwTestHarness { return new SwTestHarness(this.server, this.caches, this.origin); }
|
||||
build(): SwTestHarness {
|
||||
return new SwTestHarness(this.server, this.caches, this.origin);
|
||||
}
|
||||
}
|
||||
|
||||
export class MockClients implements Clients {
|
||||
@ -60,11 +62,17 @@ export class MockClients implements Clients {
|
||||
this.clients.set(clientId, new MockClient(clientId));
|
||||
}
|
||||
|
||||
remove(clientId: string): void { this.clients.delete(clientId); }
|
||||
remove(clientId: string): void {
|
||||
this.clients.delete(clientId);
|
||||
}
|
||||
|
||||
async get(id: string): Promise<Client> { return this.clients.get(id) !as any as Client; }
|
||||
async get(id: string): Promise<Client> {
|
||||
return this.clients.get(id)! as any as Client;
|
||||
}
|
||||
|
||||
getMock(id: string): MockClient|undefined { return this.clients.get(id); }
|
||||
getMock(id: string): MockClient|undefined {
|
||||
return this.clients.get(id);
|
||||
}
|
||||
|
||||
async matchAll(): Promise<Client[]> {
|
||||
return Array.from(this.clients.values()) as any[] as Client[];
|
||||
@ -82,17 +90,23 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
private selfMessageQueue: any[] = [];
|
||||
autoAdvanceTime = false;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
unregistered !: boolean;
|
||||
unregistered!: boolean;
|
||||
readonly notifications: {title: string, options: Object}[] = [];
|
||||
readonly registration: ServiceWorkerRegistration = {
|
||||
active: {
|
||||
postMessage: (msg: any) => { this.selfMessageQueue.push(msg); },
|
||||
postMessage: (msg: any) => {
|
||||
this.selfMessageQueue.push(msg);
|
||||
},
|
||||
},
|
||||
scope: this.origin,
|
||||
showNotification: (title: string, options: Object) => {
|
||||
this.notifications.push({title, options});
|
||||
},
|
||||
unregister: () => { this.unregistered = true; },
|
||||
showNotification:
|
||||
(title: string, options: Object) => {
|
||||
this.notifications.push({title, options});
|
||||
},
|
||||
unregister:
|
||||
() => {
|
||||
this.unregistered = true;
|
||||
},
|
||||
} as any;
|
||||
|
||||
static envIsSupported(): boolean {
|
||||
@ -131,7 +145,7 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
while (this.selfMessageQueue.length > 0) {
|
||||
const queue = this.selfMessageQueue;
|
||||
this.selfMessageQueue = [];
|
||||
await queue.reduce(async(previous, msg) => {
|
||||
await queue.reduce(async (previous, msg) => {
|
||||
await previous;
|
||||
await this.handleMessage(msg, null);
|
||||
}, Promise.resolve());
|
||||
@ -145,18 +159,20 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
let skippedWaiting: boolean = false;
|
||||
if (this.eventHandlers.has('install')) {
|
||||
const installEvent = new MockInstallEvent();
|
||||
this.eventHandlers.get('install') !(installEvent);
|
||||
this.eventHandlers.get('install')!(installEvent);
|
||||
await installEvent.ready;
|
||||
skippedWaiting = this.skippedWaiting;
|
||||
}
|
||||
if (this.eventHandlers.has('activate')) {
|
||||
const activateEvent = new MockActivateEvent();
|
||||
this.eventHandlers.get('activate') !(activateEvent);
|
||||
this.eventHandlers.get('activate')!(activateEvent);
|
||||
await activateEvent.ready;
|
||||
}
|
||||
return skippedWaiting;
|
||||
}
|
||||
updateServerState(server?: MockServerState): void { this.server = server || EMPTY_SERVER_STATE; }
|
||||
updateServerState(server?: MockServerState): void {
|
||||
this.server = server || EMPTY_SERVER_STATE;
|
||||
}
|
||||
|
||||
fetch(req: string|Request): Promise<Response> {
|
||||
if (typeof req === 'string') {
|
||||
@ -177,11 +193,17 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
this.eventHandlers.set(event, handler);
|
||||
}
|
||||
|
||||
removeEventListener(event: string, handler?: Function): void { this.eventHandlers.delete(event); }
|
||||
removeEventListener(event: string, handler?: Function): void {
|
||||
this.eventHandlers.delete(event);
|
||||
}
|
||||
|
||||
newRequest(url: string, init: Object = {}): Request { return new MockRequest(url, init); }
|
||||
newRequest(url: string, init: Object = {}): Request {
|
||||
return new MockRequest(url, init);
|
||||
}
|
||||
|
||||
newResponse(body: string, init: Object = {}): Response { return new MockResponse(body, init); }
|
||||
newResponse(body: string, init: Object = {}): Response {
|
||||
return new MockResponse(body, init);
|
||||
}
|
||||
|
||||
newHeaders(headers: {[name: string]: string}): Headers {
|
||||
return Object.keys(headers).reduce((mock, name) => {
|
||||
@ -202,7 +224,9 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
};
|
||||
}
|
||||
|
||||
async skipWaiting(): Promise<void> { this.skippedWaiting = true; }
|
||||
async skipWaiting(): Promise<void> {
|
||||
this.skippedWaiting = true;
|
||||
}
|
||||
|
||||
waitUntil(promise: Promise<void>): void {}
|
||||
|
||||
@ -212,7 +236,7 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
throw new Error('No fetch handler registered');
|
||||
}
|
||||
const event = new MockFetchEvent(req, clientId);
|
||||
this.eventHandlers.get('fetch') !.call(this, event);
|
||||
this.eventHandlers.get('fetch')!.call(this, event);
|
||||
|
||||
if (clientId) {
|
||||
this.clients.add(clientId);
|
||||
@ -232,7 +256,7 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
this.clients.add(clientId);
|
||||
event = new MockMessageEvent(data, this.clients.getMock(clientId) || null);
|
||||
}
|
||||
this.eventHandlers.get('message') !.call(this, event);
|
||||
this.eventHandlers.get('message')!.call(this, event);
|
||||
return event.ready;
|
||||
}
|
||||
|
||||
@ -241,7 +265,7 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
throw new Error('No push handler registered');
|
||||
}
|
||||
const event = new MockPushEvent(data);
|
||||
this.eventHandlers.get('push') !.call(this, event);
|
||||
this.eventHandlers.get('push')!.call(this, event);
|
||||
return event.ready;
|
||||
}
|
||||
|
||||
@ -250,7 +274,7 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
throw new Error('No notificationclick handler registered');
|
||||
}
|
||||
const event = new MockNotificationEvent(notification, action);
|
||||
this.eventHandlers.get('notificationclick') !.call(this, event);
|
||||
this.eventHandlers.get('notificationclick')!.call(this, event);
|
||||
return event.ready;
|
||||
}
|
||||
|
||||
@ -281,7 +305,9 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||
});
|
||||
}
|
||||
|
||||
isClient(obj: any): obj is Client { return obj instanceof MockClient; }
|
||||
isClient(obj: any): obj is Client {
|
||||
return obj instanceof MockClient;
|
||||
}
|
||||
}
|
||||
|
||||
interface StaticFile {
|
||||
@ -304,9 +330,13 @@ export class AssetGroupBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
finish(): ConfigBuilder { return this.up; }
|
||||
finish(): ConfigBuilder {
|
||||
return this.up;
|
||||
}
|
||||
|
||||
toManifestGroup(): AssetGroupConfig { return null !; }
|
||||
toManifestGroup(): AssetGroupConfig {
|
||||
return null!;
|
||||
}
|
||||
}
|
||||
|
||||
export class ConfigBuilder {
|
||||
@ -324,8 +354,10 @@ export class ConfigBuilder {
|
||||
return {
|
||||
configVersion: 1,
|
||||
timestamp: 1234567890123,
|
||||
index: '/index.html', assetGroups,
|
||||
navigationUrls: [], hashTable,
|
||||
index: '/index.html',
|
||||
assetGroups,
|
||||
navigationUrls: [],
|
||||
hashTable,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -333,10 +365,12 @@ export class ConfigBuilder {
|
||||
class OneTimeContext implements Context {
|
||||
private queue: Promise<void>[] = [];
|
||||
|
||||
waitUntil(promise: Promise<void>): void { this.queue.push(promise); }
|
||||
waitUntil(promise: Promise<void>): void {
|
||||
this.queue.push(promise);
|
||||
}
|
||||
|
||||
get ready(): Promise<void> {
|
||||
return (async() => {
|
||||
return (async () => {
|
||||
while (this.queue.length > 0) {
|
||||
await this.queue.shift();
|
||||
}
|
||||
@ -349,7 +383,9 @@ class MockExtendableEvent extends OneTimeContext {}
|
||||
class MockFetchEvent extends MockExtendableEvent {
|
||||
response: Promise<Response|undefined> = Promise.resolve(undefined);
|
||||
|
||||
constructor(readonly request: Request, readonly clientId: string|null) { super(); }
|
||||
constructor(readonly request: Request, readonly clientId: string|null) {
|
||||
super();
|
||||
}
|
||||
|
||||
respondWith(promise: Promise<Response>): Promise<Response> {
|
||||
this.response = promise;
|
||||
@ -358,17 +394,23 @@ class MockFetchEvent extends MockExtendableEvent {
|
||||
}
|
||||
|
||||
class MockMessageEvent extends MockExtendableEvent {
|
||||
constructor(readonly data: Object, readonly source: MockClient|null) { super(); }
|
||||
constructor(readonly data: Object, readonly source: MockClient|null) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
class MockPushEvent extends MockExtendableEvent {
|
||||
constructor(private _data: Object) { super(); }
|
||||
constructor(private _data: Object) {
|
||||
super();
|
||||
}
|
||||
data = {
|
||||
json: () => this._data,
|
||||
};
|
||||
}
|
||||
class MockNotificationEvent extends MockExtendableEvent {
|
||||
constructor(private _notification: any, readonly action?: string) { super(); }
|
||||
constructor(private _notification: any, readonly action?: string) {
|
||||
super();
|
||||
}
|
||||
readonly notification = {...this._notification, close: () => undefined};
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user