mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: use bindIsolatedHandle
(#10810)
This commit is contained in:
parent
f3c7499e67
commit
690b1c2218
@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
sidebar_label: ElementHandle.asElement
|
|
||||||
---
|
|
||||||
|
|
||||||
# ElementHandle.asElement() method
|
|
||||||
|
|
||||||
#### Signature:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
class ElementHandle {
|
|
||||||
asElement(): ElementHandle<ElementType>;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Returns:**
|
|
||||||
|
|
||||||
[ElementHandle](./puppeteer.elementhandle.md)<ElementType>
|
|
@ -54,7 +54,6 @@ The constructor for this class is marked as internal. Third-party code should no
|
|||||||
| [$$eval(selector, pageFunction, args)](./puppeteer.elementhandle.__eval.md) | | <p>Runs the given function on an array of elements matching the given selector in the current element.</p><p>If the given function returns a promise, then this method will wait till the promise resolves.</p> |
|
| [$$eval(selector, pageFunction, args)](./puppeteer.elementhandle.__eval.md) | | <p>Runs the given function on an array of elements matching the given selector in the current element.</p><p>If the given function returns a promise, then this method will wait till the promise resolves.</p> |
|
||||||
| [$eval(selector, pageFunction, args)](./puppeteer.elementhandle._eval.md) | | <p>Runs the given function on the first element matching the given selector in the current element.</p><p>If the given function returns a promise, then this method will wait till the promise resolves.</p> |
|
| [$eval(selector, pageFunction, args)](./puppeteer.elementhandle._eval.md) | | <p>Runs the given function on the first element matching the given selector in the current element.</p><p>If the given function returns a promise, then this method will wait till the promise resolves.</p> |
|
||||||
| [$x(expression)](./puppeteer.elementhandle._x.md) | | |
|
| [$x(expression)](./puppeteer.elementhandle._x.md) | | |
|
||||||
| [asElement()](./puppeteer.elementhandle.aselement.md) | | |
|
|
||||||
| [autofill(data)](./puppeteer.elementhandle.autofill.md) | | If the element is a form input, you can use [ElementHandle.autofill()](./puppeteer.elementhandle.autofill.md) to test if the form is compatible with the browser's autofill implementation. Throws an error if the form cannot be autofilled. |
|
| [autofill(data)](./puppeteer.elementhandle.autofill.md) | | If the element is a form input, you can use [ElementHandle.autofill()](./puppeteer.elementhandle.autofill.md) to test if the form is compatible with the browser's autofill implementation. Throws an error if the form cannot be autofilled. |
|
||||||
| [boundingBox()](./puppeteer.elementhandle.boundingbox.md) | | This method returns the bounding box of the element (relative to the main frame), or <code>null</code> if the element is not visible. |
|
| [boundingBox()](./puppeteer.elementhandle.boundingbox.md) | | This method returns the bounding box of the element (relative to the main frame), or <code>null</code> if the element is not visible. |
|
||||||
| [boxModel()](./puppeteer.elementhandle.boxmodel.md) | | This method returns boxes of the element, or <code>null</code> if the element is not visible. |
|
| [boxModel()](./puppeteer.elementhandle.boxmodel.md) | | This method returns boxes of the element, or <code>null</code> if the element is not visible. |
|
||||||
|
@ -139,6 +139,58 @@ export interface Point {
|
|||||||
export abstract class ElementHandle<
|
export abstract class ElementHandle<
|
||||||
ElementType extends Node = Element,
|
ElementType extends Node = Element,
|
||||||
> extends JSHandle<ElementType> {
|
> extends JSHandle<ElementType> {
|
||||||
|
/**
|
||||||
|
* A given method will have it's `this` replaced with an isolated version of
|
||||||
|
* `this` when decorated with this decorator.
|
||||||
|
*
|
||||||
|
* All changes of isolated `this` are reflected on the actual `this`.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
static bindIsolatedHandle<This extends ElementHandle<Node>>(
|
||||||
|
target: (this: This, ...args: any[]) => Promise<any>,
|
||||||
|
_: unknown
|
||||||
|
): typeof target {
|
||||||
|
return async function (...args) {
|
||||||
|
// If the handle is already isolated, then we don't need to adopt it
|
||||||
|
// again.
|
||||||
|
if (this.realm === this.frame.isolatedRealm()) {
|
||||||
|
return await target.call(this, ...args);
|
||||||
|
}
|
||||||
|
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
|
||||||
|
const result = await target.call(adoptedThis, ...args);
|
||||||
|
// If the function returns `adoptedThis`, then we return `this`.
|
||||||
|
if (result === adoptedThis) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// If the function returns a handle, transfer it into the current realm.
|
||||||
|
if (result instanceof JSHandle) {
|
||||||
|
return await this.realm.transferHandle(result);
|
||||||
|
}
|
||||||
|
// If the function returns an array of handlers, transfer them into the
|
||||||
|
// current realm.
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
await Promise.all(
|
||||||
|
result.map(async (item, index, result) => {
|
||||||
|
if (item instanceof JSHandle) {
|
||||||
|
result[index] = await this.realm.transferHandle(item);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (result instanceof Map) {
|
||||||
|
await Promise.all(
|
||||||
|
[...result.entries()].map(async ([key, value]) => {
|
||||||
|
if (value instanceof JSHandle) {
|
||||||
|
result.set(key, await this.realm.transferHandle(value));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -176,6 +228,10 @@ export abstract class ElementHandle<
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
override async getProperty(propertyName: string): Promise<JSHandle<unknown>>;
|
override async getProperty(propertyName: string): Promise<JSHandle<unknown>>;
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async getProperty<K extends keyof ElementType>(
|
override async getProperty<K extends keyof ElementType>(
|
||||||
propertyName: HandleOr<K>
|
propertyName: HandleOr<K>
|
||||||
): Promise<HandleFor<ElementType[K]>> {
|
): Promise<HandleFor<ElementType[K]>> {
|
||||||
@ -185,6 +241,7 @@ export abstract class ElementHandle<
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async getProperties(): Promise<Map<string, JSHandle>> {
|
override async getProperties(): Promise<Map<string, JSHandle>> {
|
||||||
return await this.handle.getProperties();
|
return await this.handle.getProperties();
|
||||||
}
|
}
|
||||||
@ -224,6 +281,7 @@ export abstract class ElementHandle<
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async jsonValue(): Promise<ElementType> {
|
override async jsonValue(): Promise<ElementType> {
|
||||||
return await this.handle.jsonValue();
|
return await this.handle.jsonValue();
|
||||||
}
|
}
|
||||||
@ -249,6 +307,9 @@ export abstract class ElementHandle<
|
|||||||
return this.handle.dispose();
|
return this.handle.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
override asElement(): ElementHandle<ElementType> {
|
override asElement(): ElementHandle<ElementType> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -265,6 +326,7 @@ export abstract class ElementHandle<
|
|||||||
* @returns A {@link ElementHandle | element handle} to the first element
|
* @returns A {@link ElementHandle | element handle} to the first element
|
||||||
* matching the given selector. Otherwise, `null`.
|
* matching the given selector. Otherwise, `null`.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async $<Selector extends string>(
|
async $<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
@ -283,6 +345,7 @@ export abstract class ElementHandle<
|
|||||||
* @returns An array of {@link ElementHandle | element handles} that point to
|
* @returns An array of {@link ElementHandle | element handles} that point to
|
||||||
* elements matching the given selector.
|
* elements matching the given selector.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async $$<Selector extends string>(
|
async $$<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
|
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
|
||||||
@ -415,6 +478,7 @@ export abstract class ElementHandle<
|
|||||||
* If there are no such elements, the method will resolve to an empty array.
|
* If there are no such elements, the method will resolve to an empty array.
|
||||||
* @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate}
|
* @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate}
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
||||||
if (expression.startsWith('//')) {
|
if (expression.startsWith('//')) {
|
||||||
expression = `.${expression}`;
|
expression = `.${expression}`;
|
||||||
@ -459,6 +523,7 @@ export abstract class ElementHandle<
|
|||||||
* @returns An element matching the given selector.
|
* @returns An element matching the given selector.
|
||||||
* @throws Throws if an element matching the given selector doesn't appear.
|
* @throws Throws if an element matching the given selector doesn't appear.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async waitForSelector<Selector extends string>(
|
async waitForSelector<Selector extends string>(
|
||||||
selector: Selector,
|
selector: Selector,
|
||||||
options: WaitForSelectorOptions = {}
|
options: WaitForSelectorOptions = {}
|
||||||
@ -473,15 +538,13 @@ export abstract class ElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
async #checkVisibility(visibility: boolean): Promise<boolean> {
|
async #checkVisibility(visibility: boolean): Promise<boolean> {
|
||||||
using element = await this.frame.isolatedRealm().adoptHandle(this);
|
return await this.evaluate(
|
||||||
return await this.frame.isolatedRealm().evaluate(
|
async (element, PuppeteerUtil, visibility) => {
|
||||||
async (PuppeteerUtil, element, visibility) => {
|
|
||||||
return Boolean(PuppeteerUtil.checkVisibility(element, visibility));
|
return Boolean(PuppeteerUtil.checkVisibility(element, visibility));
|
||||||
},
|
},
|
||||||
LazyArg.create(context => {
|
LazyArg.create(context => {
|
||||||
return context.puppeteerUtil;
|
return context.puppeteerUtil;
|
||||||
}),
|
}),
|
||||||
element,
|
|
||||||
visibility
|
visibility
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -490,6 +553,7 @@ export abstract class ElementHandle<
|
|||||||
* Checks if an element is visible using the same mechanism as
|
* Checks if an element is visible using the same mechanism as
|
||||||
* {@link ElementHandle.waitForSelector}.
|
* {@link ElementHandle.waitForSelector}.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async isVisible(): Promise<boolean> {
|
async isVisible(): Promise<boolean> {
|
||||||
return await this.#checkVisibility(true);
|
return await this.#checkVisibility(true);
|
||||||
}
|
}
|
||||||
@ -498,6 +562,7 @@ export abstract class ElementHandle<
|
|||||||
* Checks if an element is hidden using the same mechanism as
|
* Checks if an element is hidden using the same mechanism as
|
||||||
* {@link ElementHandle.waitForSelector}.
|
* {@link ElementHandle.waitForSelector}.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async isHidden(): Promise<boolean> {
|
async isHidden(): Promise<boolean> {
|
||||||
return await this.#checkVisibility(false);
|
return await this.#checkVisibility(false);
|
||||||
}
|
}
|
||||||
@ -564,6 +629,7 @@ export abstract class ElementHandle<
|
|||||||
* default value can be changed by using the {@link Page.setDefaultTimeout}
|
* default value can be changed by using the {@link Page.setDefaultTimeout}
|
||||||
* method.
|
* method.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async waitForXPath(
|
async waitForXPath(
|
||||||
xpath: string,
|
xpath: string,
|
||||||
options: {
|
options: {
|
||||||
@ -596,6 +662,7 @@ export abstract class ElementHandle<
|
|||||||
* @throws An error if the handle does not match. **The handle will not be
|
* @throws An error if the handle does not match. **The handle will not be
|
||||||
* automatically disposed.**
|
* automatically disposed.**
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async toElement<
|
async toElement<
|
||||||
K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap,
|
K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap,
|
||||||
>(tagName: K): Promise<HandleFor<ElementFor<K>>> {
|
>(tagName: K): Promise<HandleFor<ElementFor<K>>> {
|
||||||
@ -618,9 +685,9 @@ export abstract class ElementHandle<
|
|||||||
/**
|
/**
|
||||||
* Returns the middle point within an element unless a specific offset is provided.
|
* Returns the middle point within an element unless a specific offset is provided.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async clickablePoint(offset?: Offset): Promise<Point> {
|
async clickablePoint(offset?: Offset): Promise<Point> {
|
||||||
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
|
const box = await this.#clickableBox();
|
||||||
const box = await adoptedThis.#clickableBox();
|
|
||||||
if (!box) {
|
if (!box) {
|
||||||
throw new Error('Node is either not clickable or not an Element');
|
throw new Error('Node is either not clickable or not an Element');
|
||||||
}
|
}
|
||||||
@ -641,6 +708,7 @@ export abstract class ElementHandle<
|
|||||||
* uses {@link Page} to hover over the center of the element.
|
* uses {@link Page} to hover over the center of the element.
|
||||||
* If the element is detached from DOM, the method throws an error.
|
* If the element is detached from DOM, the method throws an error.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async hover(this: ElementHandle<Element>): Promise<void> {
|
async hover(this: ElementHandle<Element>): Promise<void> {
|
||||||
await this.scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint();
|
const {x, y} = await this.clickablePoint();
|
||||||
@ -652,6 +720,7 @@ export abstract class ElementHandle<
|
|||||||
* uses {@link Page | Page.mouse} to click in the center of the element.
|
* uses {@link Page | Page.mouse} to click in the center of the element.
|
||||||
* If the element is detached from DOM, the method throws an error.
|
* If the element is detached from DOM, the method throws an error.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async click(
|
async click(
|
||||||
this: ElementHandle<Element>,
|
this: ElementHandle<Element>,
|
||||||
options: Readonly<ClickOptions> = {}
|
options: Readonly<ClickOptions> = {}
|
||||||
@ -733,6 +802,7 @@ export abstract class ElementHandle<
|
|||||||
* `multiple` attribute, all values are considered, otherwise only the first
|
* `multiple` attribute, all values are considered, otherwise only the first
|
||||||
* one is taken into account.
|
* one is taken into account.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async select(...values: string[]): Promise<string[]> {
|
async select(...values: string[]): Promise<string[]> {
|
||||||
for (const value of values) {
|
for (const value of values) {
|
||||||
assert(
|
assert(
|
||||||
@ -801,6 +871,7 @@ export abstract class ElementHandle<
|
|||||||
* {@link Touchscreen.tap} to tap in the center of the element.
|
* {@link Touchscreen.tap} to tap in the center of the element.
|
||||||
* If the element is detached from DOM, the method throws an error.
|
* If the element is detached from DOM, the method throws an error.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async tap(this: ElementHandle<Element>): Promise<void> {
|
async tap(this: ElementHandle<Element>): Promise<void> {
|
||||||
await this.scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint();
|
const {x, y} = await this.clickablePoint();
|
||||||
@ -808,18 +879,21 @@ export abstract class ElementHandle<
|
|||||||
await this.frame.page().touchscreen.touchEnd();
|
await this.frame.page().touchscreen.touchEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async touchStart(this: ElementHandle<Element>): Promise<void> {
|
async touchStart(this: ElementHandle<Element>): Promise<void> {
|
||||||
await this.scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint();
|
const {x, y} = await this.clickablePoint();
|
||||||
await this.frame.page().touchscreen.touchStart(x, y);
|
await this.frame.page().touchscreen.touchStart(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async touchMove(this: ElementHandle<Element>): Promise<void> {
|
async touchMove(this: ElementHandle<Element>): Promise<void> {
|
||||||
await this.scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint();
|
const {x, y} = await this.clickablePoint();
|
||||||
await this.frame.page().touchscreen.touchMove(x, y);
|
await this.frame.page().touchscreen.touchMove(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async touchEnd(this: ElementHandle<Element>): Promise<void> {
|
async touchEnd(this: ElementHandle<Element>): Promise<void> {
|
||||||
await this.scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
await this.frame.page().touchscreen.touchEnd();
|
await this.frame.page().touchscreen.touchEnd();
|
||||||
@ -828,6 +902,7 @@ export abstract class ElementHandle<
|
|||||||
/**
|
/**
|
||||||
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | focus} on the element.
|
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | focus} on the element.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async focus(): Promise<void> {
|
async focus(): Promise<void> {
|
||||||
await this.evaluate(element => {
|
await this.evaluate(element => {
|
||||||
if (!(element instanceof HTMLElement)) {
|
if (!(element instanceof HTMLElement)) {
|
||||||
@ -862,6 +937,7 @@ export abstract class ElementHandle<
|
|||||||
*
|
*
|
||||||
* @param options - Delay in milliseconds. Defaults to 0.
|
* @param options - Delay in milliseconds. Defaults to 0.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async type(
|
async type(
|
||||||
text: string,
|
text: string,
|
||||||
options?: Readonly<KeyboardTypeOptions>
|
options?: Readonly<KeyboardTypeOptions>
|
||||||
@ -884,6 +960,7 @@ export abstract class ElementHandle<
|
|||||||
* @param key - Name of key to press, such as `ArrowLeft`.
|
* @param key - Name of key to press, such as `ArrowLeft`.
|
||||||
* See {@link KeyInput} for a list of all key names.
|
* See {@link KeyInput} for a list of all key names.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async press(
|
async press(
|
||||||
key: KeyInput,
|
key: KeyInput,
|
||||||
options?: Readonly<KeyPressOptions>
|
options?: Readonly<KeyPressOptions>
|
||||||
@ -972,9 +1049,9 @@ export abstract class ElementHandle<
|
|||||||
* This method returns the bounding box of the element (relative to the main frame),
|
* This method returns the bounding box of the element (relative to the main frame),
|
||||||
* or `null` if the element is not visible.
|
* or `null` if the element is not visible.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async boundingBox(): Promise<BoundingBox | null> {
|
async boundingBox(): Promise<BoundingBox | null> {
|
||||||
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
|
const box = await this.evaluate(element => {
|
||||||
const box = await adoptedThis.evaluate(element => {
|
|
||||||
if (!(element instanceof Element)) {
|
if (!(element instanceof Element)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -988,7 +1065,7 @@ export abstract class ElementHandle<
|
|||||||
if (!box) {
|
if (!box) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const offset = await adoptedThis.#getTopLeftCornerOfFrame();
|
const offset = await this.#getTopLeftCornerOfFrame();
|
||||||
if (!offset) {
|
if (!offset) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1008,82 +1085,80 @@ export abstract class ElementHandle<
|
|||||||
* Boxes are represented as an array of points;
|
* Boxes are represented as an array of points;
|
||||||
* Each Point is an object `{x, y}`. Box points are sorted clock-wise.
|
* Each Point is an object `{x, y}`. Box points are sorted clock-wise.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async boxModel(): Promise<BoxModel | null> {
|
async boxModel(): Promise<BoxModel | null> {
|
||||||
const model = await (async () => {
|
const model = await this.evaluate(element => {
|
||||||
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
|
if (!(element instanceof Element)) {
|
||||||
return await adoptedThis.evaluate(element => {
|
return null;
|
||||||
if (!(element instanceof Element)) {
|
}
|
||||||
return null;
|
// Element is not visible.
|
||||||
}
|
if (element.getClientRects().length === 0) {
|
||||||
// Element is not visible.
|
return null;
|
||||||
if (element.getClientRects().length === 0) {
|
}
|
||||||
return null;
|
const rect = element.getBoundingClientRect();
|
||||||
}
|
const style = window.getComputedStyle(element);
|
||||||
const rect = element.getBoundingClientRect();
|
const offsets = {
|
||||||
const style = window.getComputedStyle(element);
|
padding: {
|
||||||
const offsets = {
|
left: parseInt(style.paddingLeft, 10),
|
||||||
padding: {
|
top: parseInt(style.paddingTop, 10),
|
||||||
left: parseInt(style.paddingLeft, 10),
|
right: parseInt(style.paddingRight, 10),
|
||||||
top: parseInt(style.paddingTop, 10),
|
bottom: parseInt(style.paddingBottom, 10),
|
||||||
right: parseInt(style.paddingRight, 10),
|
},
|
||||||
bottom: parseInt(style.paddingBottom, 10),
|
margin: {
|
||||||
},
|
left: -parseInt(style.marginLeft, 10),
|
||||||
margin: {
|
top: -parseInt(style.marginTop, 10),
|
||||||
left: -parseInt(style.marginLeft, 10),
|
right: -parseInt(style.marginRight, 10),
|
||||||
top: -parseInt(style.marginTop, 10),
|
bottom: -parseInt(style.marginBottom, 10),
|
||||||
right: -parseInt(style.marginRight, 10),
|
},
|
||||||
bottom: -parseInt(style.marginBottom, 10),
|
border: {
|
||||||
},
|
left: parseInt(style.borderLeft, 10),
|
||||||
border: {
|
top: parseInt(style.borderTop, 10),
|
||||||
left: parseInt(style.borderLeft, 10),
|
right: parseInt(style.borderRight, 10),
|
||||||
top: parseInt(style.borderTop, 10),
|
bottom: parseInt(style.borderBottom, 10),
|
||||||
right: parseInt(style.borderRight, 10),
|
},
|
||||||
bottom: parseInt(style.borderBottom, 10),
|
};
|
||||||
},
|
const border: Quad = [
|
||||||
};
|
{x: rect.left, y: rect.top},
|
||||||
const border: Quad = [
|
{x: rect.left + rect.width, y: rect.top},
|
||||||
{x: rect.left, y: rect.top},
|
{x: rect.left + rect.width, y: rect.top + rect.bottom},
|
||||||
{x: rect.left + rect.width, y: rect.top},
|
{x: rect.left, y: rect.top + rect.bottom},
|
||||||
{x: rect.left + rect.width, y: rect.top + rect.bottom},
|
];
|
||||||
{x: rect.left, y: rect.top + rect.bottom},
|
const padding = transformQuadWithOffsets(border, offsets.border);
|
||||||
];
|
const content = transformQuadWithOffsets(padding, offsets.padding);
|
||||||
const padding = transformQuadWithOffsets(border, offsets.border);
|
const margin = transformQuadWithOffsets(border, offsets.margin);
|
||||||
const content = transformQuadWithOffsets(padding, offsets.padding);
|
return {
|
||||||
const margin = transformQuadWithOffsets(border, offsets.margin);
|
content,
|
||||||
return {
|
padding,
|
||||||
content,
|
border,
|
||||||
padding,
|
margin,
|
||||||
border,
|
width: rect.width,
|
||||||
margin,
|
height: rect.height,
|
||||||
width: rect.width,
|
};
|
||||||
height: rect.height,
|
|
||||||
};
|
|
||||||
|
|
||||||
function transformQuadWithOffsets(
|
function transformQuadWithOffsets(
|
||||||
quad: Quad,
|
quad: Quad,
|
||||||
offsets: {top: number; left: number; right: number; bottom: number}
|
offsets: {top: number; left: number; right: number; bottom: number}
|
||||||
): Quad {
|
): Quad {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
x: quad[0].x + offsets.left,
|
x: quad[0].x + offsets.left,
|
||||||
y: quad[0].y + offsets.top,
|
y: quad[0].y + offsets.top,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: quad[1].x - offsets.right,
|
x: quad[1].x - offsets.right,
|
||||||
y: quad[1].y + offsets.top,
|
y: quad[1].y + offsets.top,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: quad[2].x - offsets.right,
|
x: quad[2].x - offsets.right,
|
||||||
y: quad[2].y - offsets.bottom,
|
y: quad[2].y - offsets.bottom,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: quad[3].x + offsets.left,
|
x: quad[3].x + offsets.left,
|
||||||
y: quad[3].y - offsets.bottom,
|
y: quad[3].y - offsets.bottom,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1198,6 +1273,7 @@ export abstract class ElementHandle<
|
|||||||
* @param options - Threshold for the intersection between 0 (no intersection) and 1
|
* @param options - Threshold for the intersection between 0 (no intersection) and 1
|
||||||
* (full intersection). Defaults to 1.
|
* (full intersection). Defaults to 1.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async isIntersectingViewport(
|
async isIntersectingViewport(
|
||||||
this: ElementHandle<Element>,
|
this: ElementHandle<Element>,
|
||||||
options: {
|
options: {
|
||||||
@ -1227,10 +1303,10 @@ export abstract class ElementHandle<
|
|||||||
* Scrolls the element into view using either the automation protocol client
|
* Scrolls the element into view using either the automation protocol client
|
||||||
* or by calling element.scrollIntoView.
|
* or by calling element.scrollIntoView.
|
||||||
*/
|
*/
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
async scrollIntoView(this: ElementHandle<Element>): Promise<void> {
|
async scrollIntoView(this: ElementHandle<Element>): Promise<void> {
|
||||||
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
|
await this.assertConnectedElement();
|
||||||
await adoptedThis.assertConnectedElement();
|
await this.evaluate(async (element): Promise<void> => {
|
||||||
await adoptedThis.evaluate(async (element): Promise<void> => {
|
|
||||||
element.scrollIntoView({
|
element.scrollIntoView({
|
||||||
block: 'center',
|
block: 'center',
|
||||||
inline: 'center',
|
inline: 'center',
|
||||||
|
@ -87,6 +87,7 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@throwIfDisposed()
|
@throwIfDisposed()
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async scrollIntoView(
|
override async scrollIntoView(
|
||||||
this: CDPElementHandle<Element>
|
this: CDPElementHandle<Element>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@ -106,6 +107,7 @@ export class CDPElementHandle<
|
|||||||
* This method creates and captures a dragevent from the element.
|
* This method creates and captures a dragevent from the element.
|
||||||
*/
|
*/
|
||||||
@throwIfDisposed()
|
@throwIfDisposed()
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async drag(
|
override async drag(
|
||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
target: Point
|
target: Point
|
||||||
@ -120,6 +122,7 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@throwIfDisposed()
|
@throwIfDisposed()
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async dragEnter(
|
override async dragEnter(
|
||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
||||||
@ -130,6 +133,7 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@throwIfDisposed()
|
@throwIfDisposed()
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async dragOver(
|
override async dragOver(
|
||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
||||||
@ -140,6 +144,7 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@throwIfDisposed()
|
@throwIfDisposed()
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async drop(
|
override async drop(
|
||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
||||||
@ -150,6 +155,7 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@throwIfDisposed()
|
@throwIfDisposed()
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async dragAndDrop(
|
override async dragAndDrop(
|
||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
target: CDPElementHandle<Node>,
|
target: CDPElementHandle<Node>,
|
||||||
@ -166,6 +172,7 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@throwIfDisposed()
|
@throwIfDisposed()
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async uploadFile(
|
override async uploadFile(
|
||||||
this: CDPElementHandle<HTMLInputElement>,
|
this: CDPElementHandle<HTMLInputElement>,
|
||||||
...filePaths: string[]
|
...filePaths: string[]
|
||||||
@ -224,6 +231,7 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
@throwIfDisposed()
|
@throwIfDisposed()
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async screenshot(
|
override async screenshot(
|
||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
options: ScreenshotOptions = {}
|
options: ScreenshotOptions = {}
|
||||||
|
@ -328,6 +328,10 @@ export class IsolatedWorld extends Realm {
|
|||||||
if (handle.realm === this) {
|
if (handle.realm === this) {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
// Implies it's a primitive value, probably.
|
||||||
|
if (handle.remoteObject().objectId === undefined) {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
const info = await this.client.send('DOM.describeNode', {
|
const info = await this.client.send('DOM.describeNode', {
|
||||||
objectId: handle.remoteObject().objectId,
|
objectId: handle.remoteObject().objectId,
|
||||||
});
|
});
|
||||||
|
@ -55,11 +55,6 @@ export class BidiElementHandle<
|
|||||||
return this.handle.remoteValue();
|
return this.handle.remoteValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
assertElementHasWorld(): asserts this {
|
|
||||||
// TODO: Should assert element has a Sandbox
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
override async autofill(data: AutofillData): Promise<void> {
|
override async autofill(data: AutofillData): Promise<void> {
|
||||||
const client = this.frame.client;
|
const client = this.frame.client;
|
||||||
const nodeInfo = await client.send('DOM.describeNode', {
|
const nodeInfo = await client.send('DOM.describeNode', {
|
||||||
@ -77,9 +72,9 @@ export class BidiElementHandle<
|
|||||||
override async contentFrame(
|
override async contentFrame(
|
||||||
this: BidiElementHandle<HTMLIFrameElement>
|
this: BidiElementHandle<HTMLIFrameElement>
|
||||||
): Promise<BidiFrame>;
|
): Promise<BidiFrame>;
|
||||||
|
@ElementHandle.bindIsolatedHandle
|
||||||
override async contentFrame(): Promise<BidiFrame | null> {
|
override async contentFrame(): Promise<BidiFrame | null> {
|
||||||
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
|
using handle = (await this.evaluateHandle(element => {
|
||||||
using handle = (await adoptedThis.evaluateHandle(element => {
|
|
||||||
if (element instanceof HTMLIFrameElement) {
|
if (element instanceof HTMLIFrameElement) {
|
||||||
return element.contentWindow;
|
return element.contentWindow;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,6 @@ export class Sandbox extends Realm {
|
|||||||
const transferredHandle = await this.evaluateHandle(node => {
|
const transferredHandle = await this.evaluateHandle(node => {
|
||||||
return node;
|
return node;
|
||||||
}, handle);
|
}, handle);
|
||||||
|
|
||||||
await handle.dispose();
|
await handle.dispose();
|
||||||
return transferredHandle as unknown as T;
|
return transferredHandle as unknown as T;
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,8 @@ export class BidiSerializer {
|
|||||||
: null;
|
: null;
|
||||||
if (objectHandle) {
|
if (objectHandle) {
|
||||||
if (
|
if (
|
||||||
objectHandle.realm !== sandbox &&
|
objectHandle.realm.environment.context() !==
|
||||||
|
sandbox.environment.context() &&
|
||||||
!('sharedId' in objectHandle.remoteValue())
|
!('sharedId' in objectHandle.remoteValue())
|
||||||
) {
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -2111,6 +2111,18 @@
|
|||||||
"parameters": ["firefox", "webDriverBiDi"],
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["cdp", "firefox"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport should work with svg elements",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["cdp", "firefox"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[emulation.spec] Emulation Page.emulate should support clicking",
|
"testIdPattern": "[emulation.spec] Emulation Page.emulate should support clicking",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
@ -208,7 +208,7 @@ describe('AriaQueryHandler', () => {
|
|||||||
});
|
});
|
||||||
describe('queryAllArray', () => {
|
describe('queryAllArray', () => {
|
||||||
it('$$eval should handle many elements', async function () {
|
it('$$eval should handle many elements', async function () {
|
||||||
this.timeout(25_000);
|
this.timeout(40_000);
|
||||||
|
|
||||||
const {page} = await getTestState();
|
const {page} = await getTestState();
|
||||||
await page.setContent('');
|
await page.setContent('');
|
||||||
|
Loading…
Reference in New Issue
Block a user