summaryrefslogtreecommitdiffstats
path: root/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts
diff options
context:
space:
mode:
Diffstat (limited to 'remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts')
-rw-r--r--remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts305
1 files changed, 305 insertions, 0 deletions
diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts
new file mode 100644
index 0000000000..b3e9ea83ec
--- /dev/null
+++ b/remote/test/puppeteer/packages/puppeteer-core/src/cdp/Target.ts
@@ -0,0 +1,305 @@
+/**
+ * @license
+ * Copyright 2019 Google Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import type {Protocol} from 'devtools-protocol';
+
+import type {Browser} from '../api/Browser.js';
+import type {BrowserContext} from '../api/BrowserContext.js';
+import type {CDPSession} from '../api/CDPSession.js';
+import {PageEvent, type Page} from '../api/Page.js';
+import {Target, TargetType} from '../api/Target.js';
+import {debugError} from '../common/util.js';
+import type {Viewport} from '../common/Viewport.js';
+import {Deferred} from '../util/Deferred.js';
+
+import {CdpCDPSession} from './CDPSession.js';
+import {CdpPage} from './Page.js';
+import type {TargetManager} from './TargetManager.js';
+import {CdpWebWorker} from './WebWorker.js';
+
+/**
+ * @internal
+ */
+export enum InitializationStatus {
+ SUCCESS = 'success',
+ ABORTED = 'aborted',
+}
+
+/**
+ * @internal
+ */
+export class CdpTarget extends Target {
+ #browserContext?: BrowserContext;
+ #session?: CDPSession;
+ #targetInfo: Protocol.Target.TargetInfo;
+ #targetManager?: TargetManager;
+ #sessionFactory:
+ | ((isAutoAttachEmulated: boolean) => Promise<CDPSession>)
+ | undefined;
+
+ _initializedDeferred = Deferred.create<InitializationStatus>();
+ _isClosedDeferred = Deferred.create<void>();
+ _targetId: string;
+
+ /**
+ * To initialize the target for use, call initialize.
+ *
+ * @internal
+ */
+ constructor(
+ targetInfo: Protocol.Target.TargetInfo,
+ session: CDPSession | undefined,
+ browserContext: BrowserContext | undefined,
+ targetManager: TargetManager | undefined,
+ sessionFactory:
+ | ((isAutoAttachEmulated: boolean) => Promise<CDPSession>)
+ | undefined
+ ) {
+ super();
+ this.#session = session;
+ this.#targetManager = targetManager;
+ this.#targetInfo = targetInfo;
+ this.#browserContext = browserContext;
+ this._targetId = targetInfo.targetId;
+ this.#sessionFactory = sessionFactory;
+ if (this.#session && this.#session instanceof CdpCDPSession) {
+ this.#session._setTarget(this);
+ }
+ }
+
+ override async asPage(): Promise<Page> {
+ const session = this._session();
+ if (!session) {
+ return await this.createCDPSession().then(client => {
+ return CdpPage._create(client, this, false, null);
+ });
+ }
+ return await CdpPage._create(session, this, false, null);
+ }
+
+ _subtype(): string | undefined {
+ return this.#targetInfo.subtype;
+ }
+
+ _session(): CDPSession | undefined {
+ return this.#session;
+ }
+
+ protected _sessionFactory(): (
+ isAutoAttachEmulated: boolean
+ ) => Promise<CDPSession> {
+ if (!this.#sessionFactory) {
+ throw new Error('sessionFactory is not initialized');
+ }
+ return this.#sessionFactory;
+ }
+
+ override createCDPSession(): Promise<CDPSession> {
+ if (!this.#sessionFactory) {
+ throw new Error('sessionFactory is not initialized');
+ }
+ return this.#sessionFactory(false).then(session => {
+ (session as CdpCDPSession)._setTarget(this);
+ return session;
+ });
+ }
+
+ override url(): string {
+ return this.#targetInfo.url;
+ }
+
+ override type(): TargetType {
+ const type = this.#targetInfo.type;
+ switch (type) {
+ case 'page':
+ return TargetType.PAGE;
+ case 'background_page':
+ return TargetType.BACKGROUND_PAGE;
+ case 'service_worker':
+ return TargetType.SERVICE_WORKER;
+ case 'shared_worker':
+ return TargetType.SHARED_WORKER;
+ case 'browser':
+ return TargetType.BROWSER;
+ case 'webview':
+ return TargetType.WEBVIEW;
+ case 'tab':
+ return TargetType.TAB;
+ default:
+ return TargetType.OTHER;
+ }
+ }
+
+ _targetManager(): TargetManager {
+ if (!this.#targetManager) {
+ throw new Error('targetManager is not initialized');
+ }
+ return this.#targetManager;
+ }
+
+ _getTargetInfo(): Protocol.Target.TargetInfo {
+ return this.#targetInfo;
+ }
+
+ override browser(): Browser {
+ if (!this.#browserContext) {
+ throw new Error('browserContext is not initialized');
+ }
+ return this.#browserContext.browser();
+ }
+
+ override browserContext(): BrowserContext {
+ if (!this.#browserContext) {
+ throw new Error('browserContext is not initialized');
+ }
+ return this.#browserContext;
+ }
+
+ override opener(): Target | undefined {
+ const {openerId} = this.#targetInfo;
+ if (!openerId) {
+ return;
+ }
+ return this.browser()
+ .targets()
+ .find(target => {
+ return (target as CdpTarget)._targetId === openerId;
+ });
+ }
+
+ _targetInfoChanged(targetInfo: Protocol.Target.TargetInfo): void {
+ this.#targetInfo = targetInfo;
+ this._checkIfInitialized();
+ }
+
+ _initialize(): void {
+ this._initializedDeferred.resolve(InitializationStatus.SUCCESS);
+ }
+
+ _isTargetExposed(): boolean {
+ return this.type() !== TargetType.TAB && !this._subtype();
+ }
+
+ protected _checkIfInitialized(): void {
+ if (!this._initializedDeferred.resolved()) {
+ this._initializedDeferred.resolve(InitializationStatus.SUCCESS);
+ }
+ }
+}
+
+/**
+ * @internal
+ */
+export class PageTarget extends CdpTarget {
+ #defaultViewport?: Viewport;
+ protected pagePromise?: Promise<Page>;
+ #ignoreHTTPSErrors: boolean;
+
+ constructor(
+ targetInfo: Protocol.Target.TargetInfo,
+ session: CDPSession | undefined,
+ browserContext: BrowserContext,
+ targetManager: TargetManager,
+ sessionFactory: (isAutoAttachEmulated: boolean) => Promise<CDPSession>,
+ ignoreHTTPSErrors: boolean,
+ defaultViewport: Viewport | null
+ ) {
+ super(targetInfo, session, browserContext, targetManager, sessionFactory);
+ this.#ignoreHTTPSErrors = ignoreHTTPSErrors;
+ this.#defaultViewport = defaultViewport ?? undefined;
+ }
+
+ override _initialize(): void {
+ this._initializedDeferred
+ .valueOrThrow()
+ .then(async result => {
+ if (result === InitializationStatus.ABORTED) {
+ return;
+ }
+ const opener = this.opener();
+ if (!(opener instanceof PageTarget)) {
+ return;
+ }
+ if (!opener || !opener.pagePromise || this.type() !== 'page') {
+ return true;
+ }
+ const openerPage = await opener.pagePromise;
+ if (!openerPage.listenerCount(PageEvent.Popup)) {
+ return true;
+ }
+ const popupPage = await this.page();
+ openerPage.emit(PageEvent.Popup, popupPage);
+ return true;
+ })
+ .catch(debugError);
+ this._checkIfInitialized();
+ }
+
+ override async page(): Promise<Page | null> {
+ if (!this.pagePromise) {
+ const session = this._session();
+ this.pagePromise = (
+ session
+ ? Promise.resolve(session)
+ : this._sessionFactory()(/* isAutoAttachEmulated=*/ false)
+ ).then(client => {
+ return CdpPage._create(
+ client,
+ this,
+ this.#ignoreHTTPSErrors,
+ this.#defaultViewport ?? null
+ );
+ });
+ }
+ return (await this.pagePromise) ?? null;
+ }
+
+ override _checkIfInitialized(): void {
+ if (this._initializedDeferred.resolved()) {
+ return;
+ }
+ if (this._getTargetInfo().url !== '') {
+ this._initializedDeferred.resolve(InitializationStatus.SUCCESS);
+ }
+ }
+}
+
+/**
+ * @internal
+ */
+export class DevToolsTarget extends PageTarget {}
+
+/**
+ * @internal
+ */
+export class WorkerTarget extends CdpTarget {
+ #workerPromise?: Promise<CdpWebWorker>;
+
+ override async worker(): Promise<CdpWebWorker | null> {
+ if (!this.#workerPromise) {
+ const session = this._session();
+ // TODO(einbinder): Make workers send their console logs.
+ this.#workerPromise = (
+ session
+ ? Promise.resolve(session)
+ : this._sessionFactory()(/* isAutoAttachEmulated=*/ false)
+ ).then(client => {
+ return new CdpWebWorker(
+ client,
+ this._getTargetInfo().url,
+ () => {} /* consoleAPICalled */,
+ () => {} /* exceptionThrown */
+ );
+ });
+ }
+ return await this.#workerPromise;
+ }
+}
+
+/**
+ * @internal
+ */
+export class OtherTarget extends CdpTarget {}