Skip to content

Commit

Permalink
chore: implement simple BiDi ElementHandle (#9753)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lightning00Blade committed Mar 1, 2023
1 parent 232873a commit 004a99a
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 112 deletions.
4 changes: 2 additions & 2 deletions docs/api/puppeteer.elementhandle.aselement.md
Expand Up @@ -8,10 +8,10 @@ sidebar_label: ElementHandle.asElement

```typescript
class ElementHandle {
asElement(): ElementHandle<ElementType> | null;
asElement(): ElementHandle<ElementType>;
}
```

**Returns:**

[ElementHandle](./puppeteer.elementhandle.md)&lt;ElementType&gt; \| null
[ElementHandle](./puppeteer.elementhandle.md)&lt;ElementType&gt;
107 changes: 102 additions & 5 deletions packages/puppeteer-core/src/api/ElementHandle.ts
Expand Up @@ -25,6 +25,7 @@ import {
ElementFor,
EvaluateFuncWith,
HandleFor,
HandleOr,
NodeFor,
} from '../common/types.js';
import {KeyInput} from '../common/USKeyboardLayout.js';
Expand Down Expand Up @@ -158,8 +159,108 @@ export class ElementHandle<
/**
* @internal
*/
constructor() {
protected handle;

/**
* @internal
*/
constructor(handle: JSHandle<ElementType>) {
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;
}

/**
Expand Down Expand Up @@ -468,10 +569,6 @@ export class ElementHandle<
throw new Error('Not implemented');
}

override asElement(): ElementHandle<ElementType> | null {
return this;
}

/**
* Resolves to the content frame for element handles referencing
* iframe nodes, or null otherwise
Expand Down
84 changes: 6 additions & 78 deletions packages/puppeteer-core/src/common/ElementHandle.ts
Expand Up @@ -25,7 +25,6 @@ import {
Point,
PressOptions,
} from '../api/ElementHandle.js';
import {JSHandle} from '../api/JSHandle.js';
import {Page, ScreenshotOptions} from '../api/Page.js';
import {assert} from '../util/assert.js';
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
Expand All @@ -38,13 +37,7 @@ import {getQueryHandlerAndSelector} from './GetQueryHandler.js';
import {WaitForSelectorOptions} from './IsolatedWorld.js';
import {CDPJSHandle} from './JSHandle.js';
import {CDPPage} from './Page.js';
import {
ElementFor,
EvaluateFuncWith,
HandleFor,
HandleOr,
NodeFor,
} from './types.js';
import {ElementFor, EvaluateFuncWith, HandleFor, NodeFor} from './types.js';
import {KeyInput} from './USKeyboardLayout.js';
import {debugError, isString} from './util.js';

Expand All @@ -69,64 +62,33 @@ export class CDPElementHandle<
ElementType extends Node = Element
> extends ElementHandle<ElementType> {
#frame: Frame;
#jsHandle: CDPJSHandle<ElementType>;
declare handle: CDPJSHandle<ElementType>;

constructor(
context: ExecutionContext,
remoteObject: Protocol.Runtime.RemoteObject,
frame: Frame
) {
super();
this.#jsHandle = new CDPJSHandle(context, remoteObject);
super(new CDPJSHandle(context, remoteObject));
this.#frame = frame;
}

/**
* @internal
*/
override executionContext(): ExecutionContext {
return this.#jsHandle.executionContext();
return this.handle.executionContext();
}

/**
* @internal
*/
override get client(): CDPSession {
return this.#jsHandle.client;
}

override get id(): string | undefined {
return this.#jsHandle.id;
return this.handle.client;
}

override remoteObject(): Protocol.Runtime.RemoteObject {
return this.#jsHandle.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);
return this.handle.remoteObject();
}

get #frameManager(): FrameManager {
Expand All @@ -141,40 +103,6 @@ export class CDPElementHandle<
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>(
selector: Selector
): Promise<CDPElementHandle<NodeFor<Selector>> | null> {
Expand Down
8 changes: 4 additions & 4 deletions packages/puppeteer-core/src/common/bidi/Context.ts
Expand Up @@ -22,6 +22,7 @@ import {EvaluateFunc, HandleFor} from '../types.js';
import {isString} from '../util.js';

import {Connection} from './Connection.js';
import {ElementHandle} from './ElementHandle.js';
import {JSHandle} from './JSHandle.js';
import {BidiSerializer} from './Serializer.js';

Expand Down Expand Up @@ -131,10 +132,9 @@ export class Context extends EventEmitter {
export function getBidiHandle(
context: Context,
result: Bidi.CommonDataTypes.RemoteValue
): JSHandle {
if ((result.type === 'node' || result.type === 'window') && context) {
// TODO: Implement ElementHandle
return new JSHandle(context, result);
): JSHandle | ElementHandle<Node> {
if (result.type === 'node' || result.type === 'window') {
return new ElementHandle(context, result);
}
return new JSHandle(context, result);
}
52 changes: 52 additions & 0 deletions packages/puppeteer-core/src/common/bidi/ElementHandle.ts
@@ -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();
}
}

0 comments on commit 004a99a

Please sign in to comment.