summaryrefslogtreecommitdiffstats
path: root/remote/test/puppeteer/packages/puppeteer-core/src/injected/Poller.ts
diff options
context:
space:
mode:
Diffstat (limited to 'remote/test/puppeteer/packages/puppeteer-core/src/injected/Poller.ts')
-rw-r--r--remote/test/puppeteer/packages/puppeteer-core/src/injected/Poller.ts181
1 files changed, 181 insertions, 0 deletions
diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/injected/Poller.ts b/remote/test/puppeteer/packages/puppeteer-core/src/injected/Poller.ts
new file mode 100644
index 0000000000..d7f4eb398b
--- /dev/null
+++ b/remote/test/puppeteer/packages/puppeteer-core/src/injected/Poller.ts
@@ -0,0 +1,181 @@
+/**
+ * Copyright 2022 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {assert} from '../util/assert.js';
+import {
+ createDeferredPromise,
+ DeferredPromise,
+} from '../util/DeferredPromise.js';
+
+/**
+ * @internal
+ */
+export interface Poller<T> {
+ start(): Promise<void>;
+ stop(): Promise<void>;
+ result(): Promise<T>;
+}
+
+/**
+ * @internal
+ */
+export class MutationPoller<T> implements Poller<T> {
+ #fn: () => Promise<T>;
+
+ #root: Node;
+
+ #observer?: MutationObserver;
+ #promise?: DeferredPromise<T>;
+ constructor(fn: () => Promise<T>, root: Node) {
+ this.#fn = fn;
+ this.#root = root;
+ }
+
+ async start(): Promise<void> {
+ const promise = (this.#promise = createDeferredPromise<T>());
+ const result = await this.#fn();
+ if (result) {
+ promise.resolve(result);
+ return;
+ }
+
+ this.#observer = new MutationObserver(async () => {
+ const result = await this.#fn();
+ if (!result) {
+ return;
+ }
+ promise.resolve(result);
+ await this.stop();
+ });
+ this.#observer.observe(this.#root, {
+ childList: true,
+ subtree: true,
+ attributes: true,
+ });
+ }
+
+ async stop(): Promise<void> {
+ assert(this.#promise, 'Polling never started.');
+ if (!this.#promise.finished()) {
+ this.#promise.reject(new Error('Polling stopped'));
+ }
+ if (this.#observer) {
+ this.#observer.disconnect();
+ this.#observer = undefined;
+ }
+ }
+
+ result(): Promise<T> {
+ assert(this.#promise, 'Polling never started.');
+ return this.#promise;
+ }
+}
+
+/**
+ * @internal
+ */
+export class RAFPoller<T> implements Poller<T> {
+ #fn: () => Promise<T>;
+ #promise?: DeferredPromise<T>;
+ constructor(fn: () => Promise<T>) {
+ this.#fn = fn;
+ }
+
+ async start(): Promise<void> {
+ const promise = (this.#promise = createDeferredPromise<T>());
+ const result = await this.#fn();
+ if (result) {
+ promise.resolve(result);
+ return;
+ }
+
+ const poll = async () => {
+ if (promise.finished()) {
+ return;
+ }
+ const result = await this.#fn();
+ if (!result) {
+ window.requestAnimationFrame(poll);
+ return;
+ }
+ promise.resolve(result);
+ await this.stop();
+ };
+ window.requestAnimationFrame(poll);
+ }
+
+ async stop(): Promise<void> {
+ assert(this.#promise, 'Polling never started.');
+ if (!this.#promise.finished()) {
+ this.#promise.reject(new Error('Polling stopped'));
+ }
+ }
+
+ result(): Promise<T> {
+ assert(this.#promise, 'Polling never started.');
+ return this.#promise;
+ }
+}
+
+/**
+ * @internal
+ */
+
+export class IntervalPoller<T> implements Poller<T> {
+ #fn: () => Promise<T>;
+ #ms: number;
+
+ #interval?: NodeJS.Timer;
+ #promise?: DeferredPromise<T>;
+ constructor(fn: () => Promise<T>, ms: number) {
+ this.#fn = fn;
+ this.#ms = ms;
+ }
+
+ async start(): Promise<void> {
+ const promise = (this.#promise = createDeferredPromise<T>());
+ const result = await this.#fn();
+ if (result) {
+ promise.resolve(result);
+ return;
+ }
+
+ this.#interval = setInterval(async () => {
+ const result = await this.#fn();
+ if (!result) {
+ return;
+ }
+ promise.resolve(result);
+ await this.stop();
+ }, this.#ms);
+ }
+
+ async stop(): Promise<void> {
+ assert(this.#promise, 'Polling never started.');
+ if (!this.#promise.finished()) {
+ this.#promise.reject(new Error('Polling stopped'));
+ }
+ if (this.#interval) {
+ clearInterval(this.#interval);
+ this.#interval = undefined;
+ }
+ }
+
+ result(): Promise<T> {
+ assert(this.#promise, 'Polling never started.');
+ return this.#promise;
+ }
+}