2021-07-08 16:25:15 +03:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google LLC All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
|
|
|
import {Subject} from 'rxjs';
|
|
|
|
|
|
|
|
|
2021-07-08 16:25:16 +03:00
|
|
|
export class MockClient implements Client {
|
|
|
|
readonly messages: any[] = [];
|
|
|
|
readonly queue = new Subject<any>();
|
|
|
|
lastFocusedAt = 0;
|
2021-07-08 16:25:15 +03:00
|
|
|
|
2021-07-08 16:25:16 +03:00
|
|
|
constructor(
|
|
|
|
readonly id: string, readonly url: string, readonly type: ClientTypes = 'all',
|
|
|
|
readonly frameType: FrameType = 'top-level') {}
|
2021-07-08 16:25:15 +03:00
|
|
|
|
2021-07-08 16:25:16 +03:00
|
|
|
postMessage(message: any): void {
|
2021-07-08 16:25:15 +03:00
|
|
|
this.messages.push(message);
|
|
|
|
this.queue.next(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 16:25:16 +03:00
|
|
|
export class MockWindowClient extends MockClient implements WindowClient {
|
2021-07-08 16:25:15 +03:00
|
|
|
readonly focused: boolean = false;
|
2021-07-08 16:25:16 +03:00
|
|
|
readonly visibilityState: VisibilityState = 'visible';
|
2021-07-08 16:25:15 +03:00
|
|
|
|
2021-07-08 16:25:16 +03:00
|
|
|
constructor(id: string, url: string, frameType: FrameType = 'top-level') {
|
|
|
|
super(id, url, 'window', frameType);
|
2021-07-08 16:25:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async focus(): Promise<WindowClient> {
|
2021-07-08 16:25:16 +03:00
|
|
|
// This is only used for relatively ordering clients based on focus order, so we don't need to
|
|
|
|
// use `Adapter#time`.
|
|
|
|
this.lastFocusedAt = Date.now();
|
|
|
|
(this.focused as boolean) = true;
|
2021-07-08 16:25:15 +03:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
async navigate(url: string): Promise<WindowClient|null> {
|
2021-07-08 16:25:16 +03:00
|
|
|
(this.url as string) = url;
|
2021-07-08 16:25:15 +03:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class MockClients implements Clients {
|
|
|
|
private clients = new Map<string, MockClient>();
|
|
|
|
|
2021-07-08 16:25:16 +03:00
|
|
|
add(clientId: string, url: string, type: ClientTypes = 'window'): void {
|
2021-07-08 16:25:15 +03:00
|
|
|
if (this.clients.has(clientId)) {
|
2021-07-08 16:25:16 +03:00
|
|
|
const existingClient = this.clients.get(clientId)!;
|
|
|
|
if (existingClient.url === url) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw new Error(
|
|
|
|
`Trying to add mock client with same ID (${existingClient.id}) and different URL ` +
|
|
|
|
`(${existingClient.url} --> ${url})`);
|
2021-07-08 16:25:15 +03:00
|
|
|
}
|
2021-07-08 16:25:16 +03:00
|
|
|
|
|
|
|
const client = (type === 'window') ? new MockWindowClient(clientId, url) :
|
|
|
|
new MockClient(clientId, url, type);
|
|
|
|
this.clients.set(clientId, client);
|
2021-07-08 16:25:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
remove(clientId: string): void {
|
|
|
|
this.clients.delete(clientId);
|
|
|
|
}
|
|
|
|
|
|
|
|
async get(id: string): Promise<Client> {
|
2021-07-08 16:25:16 +03:00
|
|
|
return this.clients.get(id)!;
|
2021-07-08 16:25:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
getMock(id: string): MockClient|undefined {
|
|
|
|
return this.clients.get(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
async matchAll<T extends ClientQueryOptions>(options?: T):
|
|
|
|
Promise<ReadonlyArray<T['type'] extends 'window'? WindowClient : Client>> {
|
2021-07-08 16:25:16 +03:00
|
|
|
const type = options?.type ?? 'window';
|
|
|
|
const allClients = Array.from(this.clients.values());
|
|
|
|
const matchedClients =
|
|
|
|
(type === 'all') ? allClients : allClients.filter(client => client.type === type);
|
|
|
|
|
|
|
|
// Order clients according to the [spec](https://w3c.github.io/ServiceWorker/#clients-matchall):
|
|
|
|
// In most recently focused then most recently created order, with windows clients before other
|
|
|
|
// clients.
|
|
|
|
return matchedClients
|
|
|
|
// Sort in most recently created order.
|
|
|
|
.reverse()
|
|
|
|
// Sort in most recently focused order.
|
|
|
|
.sort((a, b) => b.lastFocusedAt - a.lastFocusedAt)
|
|
|
|
// Sort windows clients before other clients (otherwise leave existing order).
|
|
|
|
.sort((a, b) => {
|
|
|
|
const aScore = (a.type === 'window') ? 1 : 0;
|
|
|
|
const bScore = (b.type === 'window') ? 1 : 0;
|
|
|
|
return bScore - aScore;
|
|
|
|
}) as any;
|
2021-07-08 16:25:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async openWindow(url: string): Promise<WindowClient|null> {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
async claim(): Promise<any> {}
|
|
|
|
}
|