Skip to content

Commit

Permalink
chore: add waitForSelector for BiDi (#10383)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lightning00Blade committed Jun 16, 2023
1 parent 866addd commit d560299
Show file tree
Hide file tree
Showing 23 changed files with 779 additions and 375 deletions.
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/puppeteer-core/package.json
Expand Up @@ -132,7 +132,7 @@
"author": "The Chromium Authors",
"license": "Apache-2.0",
"dependencies": {
"chromium-bidi": "0.4.11",
"chromium-bidi": "0.4.12",
"cross-fetch": "3.1.6",
"debug": "4.3.4",
"devtools-protocol": "0.0.1135028",
Expand Down
35 changes: 28 additions & 7 deletions packages/puppeteer-core/src/api/ElementHandle.ts
Expand Up @@ -16,11 +16,13 @@

import {Protocol} from 'devtools-protocol';

import {Frame} from '../api/Frame.js';
import {CDPSession} from '../common/Connection.js';
import {ExecutionContext} from '../common/ExecutionContext.js';
import {getQueryHandlerAndSelector} from '../common/GetQueryHandler.js';
import {MouseClickOptions} from '../common/Input.js';
import {WaitForSelectorOptions} from '../common/IsolatedWorld.js';
import {LazyArg} from '../common/LazyArg.js';
import {
ElementFor,
EvaluateFuncWith,
Expand All @@ -33,7 +35,6 @@ import {isString, withSourcePuppeteerURLIfNone} from '../common/util.js';
import {assert} from '../util/assert.js';
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';

import {Frame} from './Frame.js';
import {JSHandle} from './JSHandle.js';
import {ScreenshotOptions} from './Page.js';

Expand Down Expand Up @@ -485,20 +486,38 @@ export class ElementHandle<
)) as ElementHandle<NodeFor<Selector>> | null;
}

async #checkVisibility(visibility: boolean): Promise<boolean> {
const element = await this.frame.isolatedRealm().adoptHandle(this);
try {
return await this.frame.isolatedRealm().evaluate(
async (PuppeteerUtil, element, visibility) => {
return Boolean(PuppeteerUtil.checkVisibility(element, visibility));
},
LazyArg.create(context => {
return context.puppeteerUtil;
}),
element,
visibility
);
} finally {
await element.dispose();
}
}

/**
* Checks if an element is visible using the same mechanism as
* {@link ElementHandle.waitForSelector}.
*/
async isVisible(): Promise<boolean> {
throw new Error('Not implemented.');
return this.#checkVisibility(true);
}

/**
* Checks if an element is hidden using the same mechanism as
* {@link ElementHandle.waitForSelector}.
*/
async isHidden(): Promise<boolean> {
throw new Error('Not implemented.');
return this.#checkVisibility(false);
}

/**
Expand Down Expand Up @@ -565,14 +584,16 @@ export class ElementHandle<
*/
async waitForXPath(
xpath: string,
options?: {
options: {
visible?: boolean;
hidden?: boolean;
timeout?: number;
} = {}
): Promise<ElementHandle<Node> | null> {
if (xpath.startsWith('//')) {
xpath = `.${xpath}`;
}
): Promise<ElementHandle<Node> | null>;
async waitForXPath(): Promise<ElementHandle<Node> | null> {
throw new Error('Not implemented');
return this.waitForSelector(`xpath/${xpath}`, options);
}

/**
Expand Down
96 changes: 78 additions & 18 deletions packages/puppeteer-core/src/api/Frame.ts
Expand Up @@ -20,6 +20,7 @@ import {Page, WaitTimeoutOptions} from '../api/Page.js';
import {CDPSession} from '../common/Connection.js';
import {DeviceRequestPrompt} from '../common/DeviceRequestPrompt.js';
import {ExecutionContext} from '../common/ExecutionContext.js';
import {getQueryHandlerAndSelector} from '../common/GetQueryHandler.js';
import {
IsolatedWorldChart,
WaitForSelectorOptions,
Expand All @@ -29,11 +30,52 @@ import {
EvaluateFunc,
EvaluateFuncWith,
HandleFor,
InnerLazyParams,
NodeFor,
} from '../common/types.js';
import {TaskManager} from '../common/WaitTask.js';

import {JSHandle} from './JSHandle.js';
import {Locator} from './Locator.js';

/**
* @internal
*/
export interface Realm {
taskManager: TaskManager;
waitForFunction<
Params extends unknown[],
Func extends EvaluateFunc<InnerLazyParams<Params>> = EvaluateFunc<
InnerLazyParams<Params>
>
>(
pageFunction: Func | string,
options: {
polling?: 'raf' | 'mutation' | number;
timeout?: number;
root?: ElementHandle<Node>;
signal?: AbortSignal;
},
...args: Params
): Promise<HandleFor<Awaited<ReturnType<Func>>>>;
adoptHandle<T extends JSHandle<Node>>(handle: T): Promise<T>;
transferHandle<T extends JSHandle<Node>>(handle: T): Promise<T>;
evaluateHandle<
Params extends unknown[],
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
>(
pageFunction: Func | string,
...args: Params
): Promise<HandleFor<Awaited<ReturnType<Func>>>>;
evaluate<
Params extends unknown[],
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
>(
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
}

/**
* @public
*/
Expand Down Expand Up @@ -307,6 +349,20 @@ export class Frame {
throw new Error('Not implemented');
}

/**
* @internal
*/
mainRealm(): Realm {
throw new Error('Not implemented');
}

/**
* @internal
*/
isolatedRealm(): Realm {
throw new Error('Not implemented');
}

/**
* Behaves identically to {@link Page.evaluateHandle} except it's run within
* the context of this frame.
Expand Down Expand Up @@ -529,12 +585,15 @@ export class Frame {
*/
async waitForSelector<Selector extends string>(
selector: Selector,
options?: WaitForSelectorOptions
): Promise<ElementHandle<NodeFor<Selector>> | null>;
async waitForSelector<Selector extends string>(): Promise<ElementHandle<
NodeFor<Selector>
> | null> {
throw new Error('Not implemented');
options: WaitForSelectorOptions = {}
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const {updatedSelector, QueryHandler} =
getQueryHandlerAndSelector(selector);
return (await QueryHandler.waitFor(
this,
updatedSelector,
options
)) as ElementHandle<NodeFor<Selector>> | null;
}

/**
Expand All @@ -561,10 +620,12 @@ export class Frame {
*/
async waitForXPath(
xpath: string,
options?: WaitForSelectorOptions
): Promise<ElementHandle<Node> | null>;
async waitForXPath(): Promise<ElementHandle<Node> | null> {
throw new Error('Not implemented');
options: WaitForSelectorOptions = {}
): Promise<ElementHandle<Node> | null> {
if (xpath.startsWith('//')) {
xpath = `.${xpath}`;
}
return this.waitForSelector(`xpath/${xpath}`, options);
}

/**
Expand Down Expand Up @@ -605,16 +666,15 @@ export class Frame {
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
>(
pageFunction: Func | string,
options?: FrameWaitForFunctionOptions,
options: FrameWaitForFunctionOptions = {},
...args: Params
): Promise<HandleFor<Awaited<ReturnType<Func>>>>;
waitForFunction<
Params extends unknown[],
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
>(): Promise<HandleFor<Awaited<ReturnType<Func>>>> {
throw new Error('Not implemented');
): Promise<HandleFor<Awaited<ReturnType<Func>>>> {
return this.mainRealm().waitForFunction(
pageFunction,
options,
...args
) as Promise<HandleFor<Awaited<ReturnType<Func>>>>;
}

/**
* The full HTML contents of the frame, including the DOCTYPE.
*/
Expand Down
42 changes: 0 additions & 42 deletions packages/puppeteer-core/src/common/ElementHandle.ts
Expand Up @@ -33,9 +33,7 @@ import {ExecutionContext} from './ExecutionContext.js';
import {Frame} from './Frame.js';
import {FrameManager} from './FrameManager.js';
import {WaitForSelectorOptions} from './IsolatedWorld.js';
import {PUPPETEER_WORLD} from './IsolatedWorlds.js';
import {CDPJSHandle} from './JSHandle.js';
import {LazyArg} from './LazyArg.js';
import {CDPPage} from './Page.js';
import {NodeFor} from './types.js';
import {KeyInput} from './USKeyboardLayout.js';
Expand Down Expand Up @@ -128,46 +126,6 @@ export class CDPElementHandle<
> | null;
}

override async waitForXPath(
xpath: string,
options: {
visible?: boolean;
hidden?: boolean;
timeout?: number;
} = {}
): Promise<CDPElementHandle<Node> | null> {
if (xpath.startsWith('//')) {
xpath = `.${xpath}`;
}
return this.waitForSelector(`xpath/${xpath}`, options);
}

async #checkVisibility(visibility: boolean): Promise<boolean> {
const element = await this.frame.worlds[PUPPETEER_WORLD].adoptHandle(this);
try {
return await this.frame.worlds[PUPPETEER_WORLD].evaluate(
async (PuppeteerUtil, element, visibility) => {
return Boolean(PuppeteerUtil.checkVisibility(element, visibility));
},
LazyArg.create(context => {
return context.puppeteerUtil;
}),
element,
visibility
);
} finally {
await element.dispose();
}
}

override async isVisible(): Promise<boolean> {
return this.#checkVisibility(true);
}

override async isHidden(): Promise<boolean> {
return this.#checkVisibility(false);
}

override async contentFrame(): Promise<Frame | null> {
const nodeInfo = await this.client.send('DOM.describeNode', {
objectId: this.id,
Expand Down

0 comments on commit d560299

Please sign in to comment.