chore: use throwIfDisposed in ElementHandle and JSHandle (#10904)

This commit is contained in:
jrandolf 2023-09-14 11:57:06 +02:00 committed by GitHub
parent 9342bac263
commit 1c66c547b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 11 deletions

View File

@ -222,16 +222,7 @@ export abstract class ElementHandle<
/** /**
* @internal * @internal
*/ */
override async getProperty<K extends keyof ElementType>( @throwIfDisposed()
propertyName: HandleOr<K>
): Promise<HandleFor<ElementType[K]>>;
/**
* @internal
*/
override async getProperty(propertyName: string): Promise<JSHandle<unknown>>;
/**
* @internal
*/
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
override async getProperty<K extends keyof ElementType>( override async getProperty<K extends keyof ElementType>(
propertyName: HandleOr<K> propertyName: HandleOr<K>
@ -242,6 +233,7 @@ export abstract class ElementHandle<
/** /**
* @internal * @internal
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @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();
@ -260,6 +252,10 @@ export abstract class ElementHandle<
pageFunction: Func | string, pageFunction: Func | string,
...args: Params ...args: Params
): Promise<Awaited<ReturnType<Func>>> { ): Promise<Awaited<ReturnType<Func>>> {
pageFunction = withSourcePuppeteerURLIfNone(
this.evaluate.name,
pageFunction
);
return await this.handle.evaluate(pageFunction, ...args); return await this.handle.evaluate(pageFunction, ...args);
} }
@ -276,12 +272,17 @@ export abstract class ElementHandle<
pageFunction: Func | string, pageFunction: Func | string,
...args: Params ...args: Params
): Promise<HandleFor<Awaited<ReturnType<Func>>>> { ): Promise<HandleFor<Awaited<ReturnType<Func>>>> {
pageFunction = withSourcePuppeteerURLIfNone(
this.evaluateHandle.name,
pageFunction
);
return await this.handle.evaluateHandle(pageFunction, ...args); return await this.handle.evaluateHandle(pageFunction, ...args);
} }
/** /**
* @internal * @internal
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
override async jsonValue(): Promise<ElementType> { override async jsonValue(): Promise<ElementType> {
return await this.handle.jsonValue(); return await this.handle.jsonValue();
@ -327,6 +328,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`.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async $<Selector extends string>( async $<Selector extends string>(
selector: Selector selector: Selector
@ -346,6 +348,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async $$<Selector extends string>( async $$<Selector extends string>(
selector: Selector selector: Selector
@ -479,6 +482,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}
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async $x(expression: string): Promise<Array<ElementHandle<Node>>> { async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
if (expression.startsWith('//')) { if (expression.startsWith('//')) {
@ -524,6 +528,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async waitForSelector<Selector extends string>( async waitForSelector<Selector extends string>(
selector: Selector, selector: Selector,
@ -554,6 +559,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}.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async isVisible(): Promise<boolean> { async isVisible(): Promise<boolean> {
return await this.#checkVisibility(true); return await this.#checkVisibility(true);
@ -563,6 +569,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}.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async isHidden(): Promise<boolean> { async isHidden(): Promise<boolean> {
return await this.#checkVisibility(false); return await this.#checkVisibility(false);
@ -630,6 +637,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async waitForXPath( async waitForXPath(
xpath: string, xpath: string,
@ -663,6 +671,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.**
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async toElement< async toElement<
K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap, K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap,
@ -686,6 +695,7 @@ 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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async clickablePoint(offset?: Offset): Promise<Point> { async clickablePoint(offset?: Offset): Promise<Point> {
const box = await this.#clickableBox(); const box = await this.#clickableBox();
@ -709,6 +719,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async hover(this: ElementHandle<Element>): Promise<void> { async hover(this: ElementHandle<Element>): Promise<void> {
await this.scrollIntoViewIfNeeded(); await this.scrollIntoViewIfNeeded();
@ -721,6 +732,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async click( async click(
this: ElementHandle<Element>, this: ElementHandle<Element>,
@ -878,6 +890,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async select(...values: string[]): Promise<string[]> { async select(...values: string[]): Promise<string[]> {
for (const value of values) { for (const value of values) {
@ -947,6 +960,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async tap(this: ElementHandle<Element>): Promise<void> { async tap(this: ElementHandle<Element>): Promise<void> {
await this.scrollIntoViewIfNeeded(); await this.scrollIntoViewIfNeeded();
@ -955,6 +969,7 @@ export abstract class ElementHandle<
await this.frame.page().touchscreen.touchEnd(); await this.frame.page().touchscreen.touchEnd();
} }
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async touchStart(this: ElementHandle<Element>): Promise<void> { async touchStart(this: ElementHandle<Element>): Promise<void> {
await this.scrollIntoViewIfNeeded(); await this.scrollIntoViewIfNeeded();
@ -962,6 +977,7 @@ export abstract class ElementHandle<
await this.frame.page().touchscreen.touchStart(x, y); await this.frame.page().touchscreen.touchStart(x, y);
} }
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async touchMove(this: ElementHandle<Element>): Promise<void> { async touchMove(this: ElementHandle<Element>): Promise<void> {
await this.scrollIntoViewIfNeeded(); await this.scrollIntoViewIfNeeded();
@ -969,6 +985,7 @@ export abstract class ElementHandle<
await this.frame.page().touchscreen.touchMove(x, y); await this.frame.page().touchscreen.touchMove(x, y);
} }
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async touchEnd(this: ElementHandle<Element>): Promise<void> { async touchEnd(this: ElementHandle<Element>): Promise<void> {
await this.scrollIntoViewIfNeeded(); await this.scrollIntoViewIfNeeded();
@ -978,6 +995,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async focus(): Promise<void> { async focus(): Promise<void> {
await this.evaluate(element => { await this.evaluate(element => {
@ -1013,6 +1031,7 @@ export abstract class ElementHandle<
* *
* @param options - Delay in milliseconds. Defaults to 0. * @param options - Delay in milliseconds. Defaults to 0.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async type( async type(
text: string, text: string,
@ -1036,6 +1055,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async press( async press(
key: KeyInput, key: KeyInput,
@ -1125,6 +1145,7 @@ 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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async boundingBox(): Promise<BoundingBox | null> { async boundingBox(): Promise<BoundingBox | null> {
const box = await this.evaluate(element => { const box = await this.evaluate(element => {
@ -1161,6 +1182,7 @@ 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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async boxModel(): Promise<BoxModel | null> { async boxModel(): Promise<BoxModel | null> {
const model = await this.evaluate(element => { const model = await this.evaluate(element => {
@ -1349,6 +1371,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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async isIntersectingViewport( async isIntersectingViewport(
this: ElementHandle<Element>, this: ElementHandle<Element>,
@ -1379,6 +1402,7 @@ 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.
*/ */
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
async scrollIntoView(this: ElementHandle<Element>): Promise<void> { async scrollIntoView(this: ElementHandle<Element>): Promise<void> {
await this.assertConnectedElement(); await this.assertConnectedElement();

View File

@ -24,7 +24,7 @@ import {
Moveable, Moveable,
} from '../common/types.js'; } from '../common/types.js';
import {debugError, withSourcePuppeteerURLIfNone} from '../common/util.js'; import {debugError, withSourcePuppeteerURLIfNone} from '../common/util.js';
import {moveable} from '../util/decorators.js'; import {moveable, throwIfDisposed} from '../util/decorators.js';
import {ElementHandle} from './ElementHandle.js'; import {ElementHandle} from './ElementHandle.js';
import {Realm} from './Realm.js'; import {Realm} from './Realm.js';
@ -124,6 +124,7 @@ export abstract class JSHandle<T = unknown>
/** /**
* @internal * @internal
*/ */
@throwIfDisposed()
async getProperty<K extends keyof T>( async getProperty<K extends keyof T>(
propertyName: HandleOr<K> propertyName: HandleOr<K>
): Promise<HandleFor<T[K]>> { ): Promise<HandleFor<T[K]>> {
@ -150,6 +151,7 @@ export abstract class JSHandle<T = unknown>
* children; // holds elementHandles to all children of document.body * children; // holds elementHandles to all children of document.body
* ``` * ```
*/ */
@throwIfDisposed()
async getProperties(): Promise<Map<string, JSHandle>> { async getProperties(): Promise<Map<string, JSHandle>> {
const propertyNames = await this.evaluate(object => { const propertyNames = await this.evaluate(object => {
const enumerableProperties = []; const enumerableProperties = [];

View File

@ -17,6 +17,7 @@
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js'; import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import {AutofillData, ElementHandle} from '../../api/ElementHandle.js'; import {AutofillData, ElementHandle} from '../../api/ElementHandle.js';
import {throwIfDisposed} from '../../util/decorators.js';
import {BidiFrame} from './Frame.js'; import {BidiFrame} from './Frame.js';
import {BidiJSHandle} from './JSHandle.js'; import {BidiJSHandle} from './JSHandle.js';
@ -55,6 +56,7 @@ export class BidiElementHandle<
return this.handle.remoteValue(); return this.handle.remoteValue();
} }
@throwIfDisposed()
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', {
@ -72,6 +74,7 @@ export class BidiElementHandle<
override async contentFrame( override async contentFrame(
this: BidiElementHandle<HTMLIFrameElement> this: BidiElementHandle<HTMLIFrameElement>
): Promise<BidiFrame>; ): Promise<BidiFrame>;
@throwIfDisposed()
@ElementHandle.bindIsolatedHandle @ElementHandle.bindIsolatedHandle
override async contentFrame(): Promise<BidiFrame | null> { override async contentFrame(): Promise<BidiFrame | null> {
using handle = (await this.evaluateHandle(element => { using handle = (await this.evaluateHandle(element => {