mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: implement simple BiDi ElementHandle (#9753)
This commit is contained in:
parent
232873ae76
commit
004a99aaef
@ -8,10 +8,10 @@ sidebar_label: ElementHandle.asElement
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
asElement(): ElementHandle<ElementType> | null;
|
asElement(): ElementHandle<ElementType>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
[ElementHandle](./puppeteer.elementhandle.md)<ElementType> \| null
|
[ElementHandle](./puppeteer.elementhandle.md)<ElementType>
|
||||||
|
@ -25,6 +25,7 @@ import {
|
|||||||
ElementFor,
|
ElementFor,
|
||||||
EvaluateFuncWith,
|
EvaluateFuncWith,
|
||||||
HandleFor,
|
HandleFor,
|
||||||
|
HandleOr,
|
||||||
NodeFor,
|
NodeFor,
|
||||||
} from '../common/types.js';
|
} from '../common/types.js';
|
||||||
import {KeyInput} from '../common/USKeyboardLayout.js';
|
import {KeyInput} from '../common/USKeyboardLayout.js';
|
||||||
@ -158,8 +159,108 @@ export class ElementHandle<
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
constructor() {
|
protected handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
constructor(handle: JSHandle<ElementType>) {
|
||||||
super();
|
super();
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override get id(): string | undefined {
|
||||||
|
return this.handle.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override get disposed(): boolean {
|
||||||
|
return this.handle.disposed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override async getProperty<K extends keyof ElementType>(
|
||||||
|
propertyName: HandleOr<K>
|
||||||
|
): Promise<HandleFor<ElementType[K]>>;
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override async getProperty(propertyName: string): Promise<JSHandle<unknown>>;
|
||||||
|
override async getProperty<K extends keyof ElementType>(
|
||||||
|
propertyName: HandleOr<K>
|
||||||
|
): Promise<HandleFor<ElementType[K]>> {
|
||||||
|
return this.handle.getProperty(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override async getProperties(): Promise<Map<string, JSHandle>> {
|
||||||
|
return this.handle.getProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override async evaluate<
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFuncWith<ElementType, Params> = EvaluateFuncWith<
|
||||||
|
ElementType,
|
||||||
|
Params
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
|
return this.handle.evaluate(pageFunction, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override evaluateHandle<
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFuncWith<ElementType, Params> = EvaluateFuncWith<
|
||||||
|
ElementType,
|
||||||
|
Params
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<HandleFor<Awaited<ReturnType<Func>>>> {
|
||||||
|
return this.handle.evaluateHandle(pageFunction, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override async jsonValue(): Promise<ElementType> {
|
||||||
|
return this.handle.jsonValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override toString(): string {
|
||||||
|
return this.handle.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override async dispose(): Promise<void> {
|
||||||
|
return await this.handle.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
override asElement(): ElementHandle<ElementType> {
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -468,10 +569,6 @@ export class ElementHandle<
|
|||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
override asElement(): ElementHandle<ElementType> | null {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves to the content frame for element handles referencing
|
* Resolves to the content frame for element handles referencing
|
||||||
* iframe nodes, or null otherwise
|
* iframe nodes, or null otherwise
|
||||||
|
@ -25,7 +25,6 @@ import {
|
|||||||
Point,
|
Point,
|
||||||
PressOptions,
|
PressOptions,
|
||||||
} from '../api/ElementHandle.js';
|
} from '../api/ElementHandle.js';
|
||||||
import {JSHandle} from '../api/JSHandle.js';
|
|
||||||
import {Page, ScreenshotOptions} from '../api/Page.js';
|
import {Page, ScreenshotOptions} from '../api/Page.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
|
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
|
||||||
@ -38,13 +37,7 @@ import {getQueryHandlerAndSelector} from './GetQueryHandler.js';
|
|||||||
import {WaitForSelectorOptions} from './IsolatedWorld.js';
|
import {WaitForSelectorOptions} from './IsolatedWorld.js';
|
||||||
import {CDPJSHandle} from './JSHandle.js';
|
import {CDPJSHandle} from './JSHandle.js';
|
||||||
import {CDPPage} from './Page.js';
|
import {CDPPage} from './Page.js';
|
||||||
import {
|
import {ElementFor, EvaluateFuncWith, HandleFor, NodeFor} from './types.js';
|
||||||
ElementFor,
|
|
||||||
EvaluateFuncWith,
|
|
||||||
HandleFor,
|
|
||||||
HandleOr,
|
|
||||||
NodeFor,
|
|
||||||
} from './types.js';
|
|
||||||
import {KeyInput} from './USKeyboardLayout.js';
|
import {KeyInput} from './USKeyboardLayout.js';
|
||||||
import {debugError, isString} from './util.js';
|
import {debugError, isString} from './util.js';
|
||||||
|
|
||||||
@ -69,15 +62,14 @@ export class CDPElementHandle<
|
|||||||
ElementType extends Node = Element
|
ElementType extends Node = Element
|
||||||
> extends ElementHandle<ElementType> {
|
> extends ElementHandle<ElementType> {
|
||||||
#frame: Frame;
|
#frame: Frame;
|
||||||
#jsHandle: CDPJSHandle<ElementType>;
|
declare handle: CDPJSHandle<ElementType>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
remoteObject: Protocol.Runtime.RemoteObject,
|
remoteObject: Protocol.Runtime.RemoteObject,
|
||||||
frame: Frame
|
frame: Frame
|
||||||
) {
|
) {
|
||||||
super();
|
super(new CDPJSHandle(context, remoteObject));
|
||||||
this.#jsHandle = new CDPJSHandle(context, remoteObject);
|
|
||||||
this.#frame = frame;
|
this.#frame = frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,48 +77,18 @@ export class CDPElementHandle<
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
override executionContext(): ExecutionContext {
|
override executionContext(): ExecutionContext {
|
||||||
return this.#jsHandle.executionContext();
|
return this.handle.executionContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
override get client(): CDPSession {
|
override get client(): CDPSession {
|
||||||
return this.#jsHandle.client;
|
return this.handle.client;
|
||||||
}
|
|
||||||
|
|
||||||
override get id(): string | undefined {
|
|
||||||
return this.#jsHandle.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override remoteObject(): Protocol.Runtime.RemoteObject {
|
override remoteObject(): Protocol.Runtime.RemoteObject {
|
||||||
return this.#jsHandle.remoteObject();
|
return this.handle.remoteObject();
|
||||||
}
|
|
||||||
|
|
||||||
override async evaluate<
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFuncWith<ElementType, Params> = EvaluateFuncWith<
|
|
||||||
ElementType,
|
|
||||||
Params
|
|
||||||
>
|
|
||||||
>(
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<Awaited<ReturnType<Func>>> {
|
|
||||||
return this.executionContext().evaluate(pageFunction, this, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
override evaluateHandle<
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFuncWith<ElementType, Params> = EvaluateFuncWith<
|
|
||||||
ElementType,
|
|
||||||
Params
|
|
||||||
>
|
|
||||||
>(
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<HandleFor<Awaited<ReturnType<Func>>>> {
|
|
||||||
return this.executionContext().evaluateHandle(pageFunction, this, ...args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get #frameManager(): FrameManager {
|
get #frameManager(): FrameManager {
|
||||||
@ -141,40 +103,6 @@ export class CDPElementHandle<
|
|||||||
return this.#frame;
|
return this.#frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
override get disposed(): boolean {
|
|
||||||
return this.#jsHandle.disposed;
|
|
||||||
}
|
|
||||||
|
|
||||||
override async getProperty<K extends keyof ElementType>(
|
|
||||||
propertyName: HandleOr<K>
|
|
||||||
): Promise<HandleFor<ElementType[K]>>;
|
|
||||||
override async getProperty(propertyName: string): Promise<JSHandle<unknown>>;
|
|
||||||
override async getProperty<K extends keyof ElementType>(
|
|
||||||
propertyName: HandleOr<K>
|
|
||||||
): Promise<HandleFor<ElementType[K]>> {
|
|
||||||
return this.#jsHandle.getProperty(propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async getProperties(): Promise<Map<string, JSHandle>> {
|
|
||||||
return this.#jsHandle.getProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
override asElement(): CDPElementHandle<ElementType> | null {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
override async jsonValue(): Promise<ElementType> {
|
|
||||||
return this.#jsHandle.jsonValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
override toString(): string {
|
|
||||||
return this.#jsHandle.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
override async dispose(): Promise<void> {
|
|
||||||
return await this.#jsHandle.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
override async $<Selector extends string>(
|
override async $<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<CDPElementHandle<NodeFor<Selector>> | null> {
|
): Promise<CDPElementHandle<NodeFor<Selector>> | null> {
|
||||||
|
@ -22,6 +22,7 @@ import {EvaluateFunc, HandleFor} from '../types.js';
|
|||||||
import {isString} from '../util.js';
|
import {isString} from '../util.js';
|
||||||
|
|
||||||
import {Connection} from './Connection.js';
|
import {Connection} from './Connection.js';
|
||||||
|
import {ElementHandle} from './ElementHandle.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
import {BidiSerializer} from './Serializer.js';
|
import {BidiSerializer} from './Serializer.js';
|
||||||
|
|
||||||
@ -131,10 +132,9 @@ export class Context extends EventEmitter {
|
|||||||
export function getBidiHandle(
|
export function getBidiHandle(
|
||||||
context: Context,
|
context: Context,
|
||||||
result: Bidi.CommonDataTypes.RemoteValue
|
result: Bidi.CommonDataTypes.RemoteValue
|
||||||
): JSHandle {
|
): JSHandle | ElementHandle<Node> {
|
||||||
if ((result.type === 'node' || result.type === 'window') && context) {
|
if (result.type === 'node' || result.type === 'window') {
|
||||||
// TODO: Implement ElementHandle
|
return new ElementHandle(context, result);
|
||||||
return new JSHandle(context, result);
|
|
||||||
}
|
}
|
||||||
return new JSHandle(context, result);
|
return new JSHandle(context, result);
|
||||||
}
|
}
|
||||||
|
52
packages/puppeteer-core/src/common/bidi/ElementHandle.ts
Normal file
52
packages/puppeteer-core/src/common/bidi/ElementHandle.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 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 * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
|
|
||||||
|
import {ElementHandle as BaseElementHandle} from '../../api/ElementHandle.js';
|
||||||
|
|
||||||
|
import {Connection} from './Connection.js';
|
||||||
|
import {Context} from './Context.js';
|
||||||
|
import {JSHandle} from './JSHandle.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export class ElementHandle<
|
||||||
|
ElementType extends Node = Element
|
||||||
|
> extends BaseElementHandle<ElementType> {
|
||||||
|
declare handle: JSHandle<ElementType>;
|
||||||
|
|
||||||
|
constructor(context: Context, remoteValue: Bidi.CommonDataTypes.RemoteValue) {
|
||||||
|
super(new JSHandle(context, remoteValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
context(): Context {
|
||||||
|
return this.handle.context();
|
||||||
|
}
|
||||||
|
|
||||||
|
get connection(): Connection {
|
||||||
|
return this.handle.connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isPrimitiveValue(): boolean {
|
||||||
|
return this.handle.isPrimitiveValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteValue(): Bidi.CommonDataTypes.RemoteValue {
|
||||||
|
return this.handle.remoteValue();
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,6 @@ import {Page as PageBase, PageEmittedEvents} from '../../api/Page.js';
|
|||||||
import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js';
|
import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js';
|
||||||
import {EvaluateFunc, HandleFor} from '../types.js';
|
import {EvaluateFunc, HandleFor} from '../types.js';
|
||||||
|
|
||||||
import {Connection} from './Connection.js';
|
|
||||||
import {Context, getBidiHandle} from './Context.js';
|
import {Context, getBidiHandle} from './Context.js';
|
||||||
import {BidiSerializer} from './Serializer.js';
|
import {BidiSerializer} from './Serializer.js';
|
||||||
|
|
||||||
@ -38,10 +37,9 @@ export class Page extends PageBase {
|
|||||||
super();
|
super();
|
||||||
this.#context = context;
|
this.#context = context;
|
||||||
|
|
||||||
// TODO: Investigate an implementation similar to CDPSession
|
this.#context.connection.send('session.subscribe', {
|
||||||
this.connection.send('session.subscribe', {
|
|
||||||
events: this.#subscribedEvents,
|
events: this.#subscribedEvents,
|
||||||
contexts: [this.contextId],
|
contexts: [this.#context.id],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#context.on('log.entryAdded', this.#boundOnLogEntryAdded);
|
this.#context.on('log.entryAdded', this.#boundOnLogEntryAdded);
|
||||||
@ -85,26 +83,18 @@ export class Page extends PageBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async close(): Promise<void> {
|
override async close(): Promise<void> {
|
||||||
await this.connection.send('session.unsubscribe', {
|
await this.#context.connection.send('session.unsubscribe', {
|
||||||
events: this.#subscribedEvents,
|
events: this.#subscribedEvents,
|
||||||
contexts: [this.contextId],
|
contexts: [this.#context.id],
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.connection.send('browsingContext.close', {
|
await this.#context.connection.send('browsingContext.close', {
|
||||||
context: this.contextId,
|
context: this.#context.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#context.off('log.entryAdded', this.#boundOnLogEntryAdded);
|
this.#context.off('log.entryAdded', this.#boundOnLogEntryAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
get connection(): Connection {
|
|
||||||
return this.#context.connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
get contextId(): string {
|
|
||||||
return this.#context.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
override async evaluateHandle<
|
override async evaluateHandle<
|
||||||
Params extends unknown[],
|
Params extends unknown[],
|
||||||
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
||||||
|
@ -19,6 +19,7 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
|||||||
import {debugError, isDate, isPlainObject, isRegExp} from '../util.js';
|
import {debugError, isDate, isPlainObject, isRegExp} from '../util.js';
|
||||||
|
|
||||||
import {Context} from './Context.js';
|
import {Context} from './Context.js';
|
||||||
|
import {ElementHandle} from './ElementHandle.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,7 +150,10 @@ export class BidiSerializer {
|
|||||||
context: Context
|
context: Context
|
||||||
): Bidi.CommonDataTypes.LocalOrRemoteValue {
|
): Bidi.CommonDataTypes.LocalOrRemoteValue {
|
||||||
// TODO: See use case of LazyArgs
|
// TODO: See use case of LazyArgs
|
||||||
const objectHandle = arg && arg instanceof JSHandle ? arg : null;
|
const objectHandle =
|
||||||
|
arg && (arg instanceof JSHandle || arg instanceof ElementHandle)
|
||||||
|
? arg
|
||||||
|
: null;
|
||||||
if (objectHandle) {
|
if (objectHandle) {
|
||||||
if (objectHandle.context() !== context) {
|
if (objectHandle.context() !== context) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -1775,12 +1775,6 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.asElement should work",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.asElement should return ElementHandle for TextNodes",
|
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.asElement should return ElementHandle for TextNodes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
Loading…
Reference in New Issue
Block a user