From 4f6b0d4e45203a240c32412384121531570e5cfd Mon Sep 17 00:00:00 2001 From: jrandolf <101637635+jrandolf@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:26:30 +0200 Subject: [PATCH] chore: implement Webdriver BiDi mouse and touchscreen (#10402) Co-authored-by: Alex Rudenko --- docs/api/puppeteer.frame.type.md | 14 +- docs/api/puppeteer.page.type.md | 14 +- .../puppeteer-core/src/api/ElementHandle.ts | 16 + packages/puppeteer-core/src/api/Frame.ts | 48 +-- packages/puppeteer-core/src/api/Page.ts | 34 +- .../src/common/ElementHandle.ts | 37 +- packages/puppeteer-core/src/common/Frame.ts | 33 +- .../src/common/IsolatedWorld.ts | 5 +- packages/puppeteer-core/src/common/Page.ts | 35 +- .../src/common/bidi/Connection.ts | 9 + .../src/common/bidi/ElementHandle.ts | 82 ++++- .../puppeteer-core/src/common/bidi/Frame.ts | 9 +- .../puppeteer-core/src/common/bidi/Input.ts | 332 ++++++++++++++++++ .../puppeteer-core/src/common/bidi/Page.ts | 15 +- .../puppeteer-core/src/common/bidi/Sandbox.ts | 57 ++- test/TestExpectations.json | 290 +++++++++++++-- test/src/elementhandle.spec.ts | 31 +- 17 files changed, 869 insertions(+), 192 deletions(-) create mode 100644 packages/puppeteer-core/src/common/bidi/Input.ts diff --git a/docs/api/puppeteer.frame.type.md b/docs/api/puppeteer.frame.type.md index e4601a67401..bf1e27d210f 100644 --- a/docs/api/puppeteer.frame.type.md +++ b/docs/api/puppeteer.frame.type.md @@ -13,20 +13,18 @@ class Frame { type( selector: string, text: string, - options?: { - delay: number; - } + options?: Readonly ): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | -| selector | string | the selector for the element to type into. If there are multiple the first will be used. | -| text | string | text to type into the element | -| options | { delay: number; } | _(Optional)_ takes one option, delay, which sets the time to wait between key presses in milliseconds. Defaults to 0. | +| Parameter | Type | Description | +| --------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| selector | string | the selector for the element to type into. If there are multiple the first will be used. | +| text | string | text to type into the element | +| options | Readonly<[TypeOptions](./puppeteer.typeoptions.md)> | _(Optional)_ takes one option, delay, which sets the time to wait between key presses in milliseconds. Defaults to 0. | **Returns:** diff --git a/docs/api/puppeteer.page.type.md b/docs/api/puppeteer.page.type.md index 23517c99376..2391e21378f 100644 --- a/docs/api/puppeteer.page.type.md +++ b/docs/api/puppeteer.page.type.md @@ -15,20 +15,18 @@ class Page { type( selector: string, text: string, - options?: { - delay: number; - } + options?: Readonly ): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| selector | string | A [selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) of an element to type into. If there are multiple elements satisfying the selector, the first will be used. | -| text | string | A text to type into a focused element. | -| options | { delay: number; } | _(Optional)_ have property delay which is the Time to wait between key presses in milliseconds. Defaults to 0. | +| Parameter | Type | Description | +| --------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| selector | string | A [selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) of an element to type into. If there are multiple elements satisfying the selector, the first will be used. | +| text | string | A text to type into a focused element. | +| options | Readonly<[TypeOptions](./puppeteer.typeoptions.md)> | _(Optional)_ have property delay which is the Time to wait between key presses in milliseconds. Defaults to 0. | **Returns:** diff --git a/packages/puppeteer-core/src/api/ElementHandle.ts b/packages/puppeteer-core/src/api/ElementHandle.ts index fa97e33be0e..0dddb95c3d1 100644 --- a/packages/puppeteer-core/src/api/ElementHandle.ts +++ b/packages/puppeteer-core/src/api/ElementHandle.ts @@ -925,6 +925,22 @@ export class ElementHandle< } } + /** + * @internal + */ + protected async scrollIntoViewIfNeeded( + this: ElementHandle + ): Promise { + if ( + await this.isIntersectingViewport({ + threshold: 1, + }) + ) { + return; + } + await this.scrollIntoView(); + } + /** * Resolves to true if the element is visible in the current viewport. If an * element is an SVG, we check if the svg owner element is in the viewport diff --git a/packages/puppeteer-core/src/api/Frame.ts b/packages/puppeteer-core/src/api/Frame.ts index a45cc2fbf80..b974f284f21 100644 --- a/packages/puppeteer-core/src/api/Frame.ts +++ b/packages/puppeteer-core/src/api/Frame.ts @@ -35,6 +35,7 @@ import { } from '../common/types.js'; import {TaskManager} from '../common/WaitTask.js'; +import {TypeOptions} from './Input.js'; import {JSHandle} from './JSHandle.js'; import {Locator} from './Locator.js'; @@ -74,6 +75,16 @@ export interface Realm { pageFunction: Func | string, ...args: Params ): Promise>>; + click(selector: string, options: Readonly): Promise; + focus(selector: string): Promise; + hover(selector: string): Promise; + select(selector: string, ...values: string[]): Promise; + tap(selector: string): Promise; + type( + selector: string, + text: string, + options?: Readonly + ): Promise; } /** @@ -793,12 +804,8 @@ export class Frame { * * @param selector - The selector to query for. */ - async click( - selector: string, - options?: Readonly - ): Promise; - async click(): Promise { - throw new Error('Not implemented'); + click(selector: string, options: Readonly = {}): Promise { + return this.isolatedRealm().click(selector, options); } /** @@ -807,9 +814,8 @@ export class Frame { * @param selector - The selector to query for. * @throws Throws if there's no element matching `selector`. */ - async focus(selector: string): Promise; - async focus(): Promise { - throw new Error('Not implemented'); + async focus(selector: string): Promise { + return this.isolatedRealm().focus(selector); } /** @@ -819,9 +825,8 @@ export class Frame { * @param selector - The selector to query for. * @throws Throws if there's no element matching `selector`. */ - async hover(selector: string): Promise; - async hover(): Promise { - throw new Error('Not implemented'); + hover(selector: string): Promise { + return this.isolatedRealm().hover(selector); } /** @@ -842,9 +847,8 @@ export class Frame { * @returns the list of values that were successfully selected. * @throws Throws if there's no `