From 39847bd23193c8dff1b3f557a9d04f1d81596542 Mon Sep 17 00:00:00 2001 From: jrandolf <101637635+jrandolf@users.noreply.github.com> Date: Mon, 19 Jun 2023 10:12:43 +0200 Subject: [PATCH] refactor: use input API for CDP inputs (#10401) --- docs/api/index.md | 4 +- docs/api/puppeteer.elementhandle.press.md | 10 +- docs/api/puppeteer.elementhandle.type.md | 15 +- docs/api/puppeteer.keyboard.down.md | 16 +- docs/api/puppeteer.keyboard.press.md | 17 +- docs/api/puppeteer.keyboard.type.md | 15 +- docs/api/puppeteer.keydownoptions.md | 18 + docs/api/puppeteer.keypressoptions.md | 13 + docs/api/puppeteer.mouse.down.md | 8 +- docs/api/puppeteer.mouse.move.md | 16 +- docs/api/puppeteer.mouse.up.md | 8 +- docs/api/puppeteer.mouse.wheel.md | 8 +- docs/api/puppeteer.pressoptions.md | 18 - docs/api/puppeteer.typeoptions.md | 17 + .../puppeteer-core/src/api/ElementHandle.ts | 23 +- packages/puppeteer-core/src/api/Input.ts | 15 + packages/puppeteer-core/src/api/Page.ts | 2 +- packages/puppeteer-core/src/api/api.ts | 1 + .../src/common/ElementHandle.ts | 12 +- packages/puppeteer-core/src/common/Input.ts | 475 +++--------------- packages/puppeteer-core/src/common/Page.ts | 20 +- test/src/mouse.spec.ts | 2 +- 22 files changed, 209 insertions(+), 524 deletions(-) create mode 100644 docs/api/puppeteer.keydownoptions.md create mode 100644 docs/api/puppeteer.keypressoptions.md delete mode 100644 docs/api/puppeteer.pressoptions.md create mode 100644 docs/api/puppeteer.typeoptions.md diff --git a/docs/api/index.md b/docs/api/index.md index cf3370d754c..f10ff5d0890 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -92,6 +92,7 @@ sidebar_label: API | [InternalNetworkConditions](./puppeteer.internalnetworkconditions.md) | | | [JSCoverageEntry](./puppeteer.jscoverageentry.md) | The CoverageEntry class for JavaScript | | [JSCoverageOptions](./puppeteer.jscoverageoptions.md) | Set of configurable options for JS coverage. | +| [KeyDownOptions](./puppeteer.keydownoptions.md) | | | [LaunchOptions](./puppeteer.launchoptions.md) | Generic launch options that can be passed when launching any browser. | | [LocatorEventObject](./puppeteer.locatoreventobject.md) | | | [LocatorOptions](./puppeteer.locatoroptions.md) | | @@ -108,7 +109,6 @@ sidebar_label: API | [PDFMargin](./puppeteer.pdfmargin.md) | | | [PDFOptions](./puppeteer.pdfoptions.md) | Valid options to configure PDF generation via [Page.pdf()](./puppeteer.page.pdf.md). | | [Point](./puppeteer.point.md) | | -| [PressOptions](./puppeteer.pressoptions.md) | | | [PuppeteerErrors](./puppeteer.puppeteererrors.md) | | | [PuppeteerLaunchOptions](./puppeteer.puppeteerlaunchoptions.md) | | | [RemoteAddress](./puppeteer.remoteaddress.md) | | @@ -118,6 +118,7 @@ sidebar_label: API | [SerializedAXNode](./puppeteer.serializedaxnode.md) | Represents a Node and the properties of it that are relevant to Accessibility. | | [SnapshotOptions](./puppeteer.snapshotoptions.md) | | | [TracingOptions](./puppeteer.tracingoptions.md) | | +| [TypeOptions](./puppeteer.typeoptions.md) | | | [Viewport](./puppeteer.viewport.md) | Sets the viewport of the page. | | [WaitForOptions](./puppeteer.waitforoptions.md) | | | [WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md) | | @@ -165,6 +166,7 @@ sidebar_label: API | [InnerParams](./puppeteer.innerparams.md) | | | [InterceptResolutionStrategy](./puppeteer.interceptresolutionstrategy.md) | | | [KeyInput](./puppeteer.keyinput.md) | All the valid keys that can be passed to functions that take user input, such as [keyboard.press](./puppeteer.keyboard.press.md) | +| [KeyPressOptions](./puppeteer.keypressoptions.md) | | | [LowerCasePaperFormat](./puppeteer.lowercasepaperformat.md) | | | [MouseButton](./puppeteer.mousebutton.md) | | | [NodeFor](./puppeteer.nodefor.md) | | diff --git a/docs/api/puppeteer.elementhandle.press.md b/docs/api/puppeteer.elementhandle.press.md index 01587453271..acfb8cc55d3 100644 --- a/docs/api/puppeteer.elementhandle.press.md +++ b/docs/api/puppeteer.elementhandle.press.md @@ -10,16 +10,16 @@ Focuses the element, and then uses [Keyboard.down()](./puppeteer.keyboard.down.m ```typescript class ElementHandle { - press(key: KeyInput, options?: PressOptions): Promise; + press(key: KeyInput, options?: Readonly): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| key | [KeyInput](./puppeteer.keyinput.md) | Name of key to press, such as ArrowLeft. See [KeyInput](./puppeteer.keyinput.md) for a list of all key names. | -| options | [PressOptions](./puppeteer.pressoptions.md) | _(Optional)_ | +| Parameter | Type | Description | +| --------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| key | [KeyInput](./puppeteer.keyinput.md) | Name of key to press, such as ArrowLeft. See [KeyInput](./puppeteer.keyinput.md) for a list of all key names. | +| options | Readonly<[KeyPressOptions](./puppeteer.keypressoptions.md)> | _(Optional)_ | **Returns:** diff --git a/docs/api/puppeteer.elementhandle.type.md b/docs/api/puppeteer.elementhandle.type.md index 3ee7cf591e8..073d95aea33 100644 --- a/docs/api/puppeteer.elementhandle.type.md +++ b/docs/api/puppeteer.elementhandle.type.md @@ -12,21 +12,16 @@ To press a special key, like `Control` or `ArrowDown`, use [ElementHandle.press( ```typescript class ElementHandle { - type( - text: string, - options?: { - delay: number; - } - ): Promise; + type(text: string, options?: Readonly): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ------------------ | -------------------------------------------------- | -| text | string | | -| options | { delay: number; } | _(Optional)_ Delay in milliseconds. Defaults to 0. | +| Parameter | Type | Description | +| --------- | --------------------------------------------------------- | -------------------------------------------------- | +| text | string | | +| options | Readonly<[TypeOptions](./puppeteer.typeoptions.md)> | _(Optional)_ Delay in milliseconds. Defaults to 0. | **Returns:** diff --git a/docs/api/puppeteer.keyboard.down.md b/docs/api/puppeteer.keyboard.down.md index 3f7c6cfe6dd..cd972ca2438 100644 --- a/docs/api/puppeteer.keyboard.down.md +++ b/docs/api/puppeteer.keyboard.down.md @@ -10,22 +10,16 @@ Dispatches a `keydown` event. ```typescript class Keyboard { - down( - key: KeyInput, - options?: { - text?: string; - commands?: string[]; - } - ): Promise; + down(key: KeyInput, options?: Readonly): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| key | [KeyInput](./puppeteer.keyinput.md) | Name of key to press, such as ArrowLeft. See [KeyInput](./puppeteer.keyinput.md) for a list of all key names. | -| options | { text?: string; commands?: string\[\]; } | _(Optional)_ An object of options. Accepts text which, if specified, generates an input event with this text. Accepts commands which, if specified, is the commands of keyboard shortcuts, see [Chromium Source Code](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h) for valid command names. | +| Parameter | Type | Description | +| --------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| key | [KeyInput](./puppeteer.keyinput.md) | Name of key to press, such as ArrowLeft. See [KeyInput](./puppeteer.keyinput.md) for a list of all key names. | +| options | Readonly<[KeyDownOptions](./puppeteer.keydownoptions.md)> | _(Optional)_ An object of options. Accepts text which, if specified, generates an input event with this text. Accepts commands which, if specified, is the commands of keyboard shortcuts, see [Chromium Source Code](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h) for valid command names. | **Returns:** diff --git a/docs/api/puppeteer.keyboard.press.md b/docs/api/puppeteer.keyboard.press.md index ff585937c3d..8edb6342da9 100644 --- a/docs/api/puppeteer.keyboard.press.md +++ b/docs/api/puppeteer.keyboard.press.md @@ -10,23 +10,16 @@ Shortcut for [Keyboard.down()](./puppeteer.keyboard.down.md) and [Keyboard.up()] ```typescript class Keyboard { - press( - key: KeyInput, - options?: { - delay?: number; - text?: string; - commands?: string[]; - } - ): Promise; + press(key: KeyInput, options?: Readonly): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| key | [KeyInput](./puppeteer.keyinput.md) | Name of key to press, such as ArrowLeft. See [KeyInput](./puppeteer.keyinput.md) for a list of all key names. | -| options | { delay?: number; text?: string; commands?: string\[\]; } | _(Optional)_ An object of options. Accepts text which, if specified, generates an input event with this text. Accepts delay which, if specified, is the time to wait between keydown and keyup in milliseconds. Defaults to 0. Accepts commands which, if specified, is the commands of keyboard shortcuts, see [Chromium Source Code](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h) for valid command names. | +| Parameter | Type | Description | +| --------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| key | [KeyInput](./puppeteer.keyinput.md) | Name of key to press, such as ArrowLeft. See [KeyInput](./puppeteer.keyinput.md) for a list of all key names. | +| options | Readonly<[KeyPressOptions](./puppeteer.keypressoptions.md)> | _(Optional)_ An object of options. Accepts text which, if specified, generates an input event with this text. Accepts delay which, if specified, is the time to wait between keydown and keyup in milliseconds. Defaults to 0. Accepts commands which, if specified, is the commands of keyboard shortcuts, see [Chromium Source Code](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h) for valid command names. | **Returns:** diff --git a/docs/api/puppeteer.keyboard.type.md b/docs/api/puppeteer.keyboard.type.md index 21c2f0a6c9e..f3dd2398046 100644 --- a/docs/api/puppeteer.keyboard.type.md +++ b/docs/api/puppeteer.keyboard.type.md @@ -10,21 +10,16 @@ Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in t ```typescript class Keyboard { - type( - text: string, - options?: { - delay?: number; - } - ): Promise; + type(text: string, options?: Readonly): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| text | string | A text to type into a focused element. | -| options | { delay?: number; } | _(Optional)_ An object of options. Accepts delay which, if specified, is the time to wait between keydown and keyup in milliseconds. Defaults to 0. | +| Parameter | Type | Description | +| --------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| text | string | A text to type into a focused element. | +| options | Readonly<[TypeOptions](./puppeteer.typeoptions.md)> | _(Optional)_ An object of options. Accepts delay which, if specified, is the time to wait between keydown and keyup in milliseconds. Defaults to 0. | **Returns:** diff --git a/docs/api/puppeteer.keydownoptions.md b/docs/api/puppeteer.keydownoptions.md new file mode 100644 index 00000000000..d931426da84 --- /dev/null +++ b/docs/api/puppeteer.keydownoptions.md @@ -0,0 +1,18 @@ +--- +sidebar_label: KeyDownOptions +--- + +# KeyDownOptions interface + +#### Signature: + +```typescript +export interface KeyDownOptions +``` + +## Properties + +| Property | Modifiers | Type | Description | Default | +| -------- | --------------------- | ---------- | ----------- | ------- | +| commands | optional | string\[\] | | | +| text | optional | string | | | diff --git a/docs/api/puppeteer.keypressoptions.md b/docs/api/puppeteer.keypressoptions.md new file mode 100644 index 00000000000..fb147124b2b --- /dev/null +++ b/docs/api/puppeteer.keypressoptions.md @@ -0,0 +1,13 @@ +--- +sidebar_label: KeyPressOptions +--- + +# KeyPressOptions type + +#### Signature: + +```typescript +export type KeyPressOptions = KeyDownOptions & TypeOptions; +``` + +**References:** [KeyDownOptions](./puppeteer.keydownoptions.md), [TypeOptions](./puppeteer.typeoptions.md) diff --git a/docs/api/puppeteer.mouse.down.md b/docs/api/puppeteer.mouse.down.md index 5116b9ceeac..bf3c6f5f0cf 100644 --- a/docs/api/puppeteer.mouse.down.md +++ b/docs/api/puppeteer.mouse.down.md @@ -10,15 +10,15 @@ Presses the mouse. ```typescript class Mouse { - down(options?: MouseOptions): Promise; + down(options?: Readonly): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ------------------------------------------- | ------------------------------------------- | -| options | [MouseOptions](./puppeteer.mouseoptions.md) | _(Optional)_ Options to configure behavior. | +| Parameter | Type | Description | +| --------- | ----------------------------------------------------------- | ------------------------------------------- | +| options | Readonly<[MouseOptions](./puppeteer.mouseoptions.md)> | _(Optional)_ Options to configure behavior. | **Returns:** diff --git a/docs/api/puppeteer.mouse.move.md b/docs/api/puppeteer.mouse.move.md index 01ca410915d..fca91421c65 100644 --- a/docs/api/puppeteer.mouse.move.md +++ b/docs/api/puppeteer.mouse.move.md @@ -10,17 +10,21 @@ Moves the mouse to the given coordinate. ```typescript class Mouse { - move(x: number, y: number, options?: MouseMoveOptions): Promise; + move( + x: number, + y: number, + options?: Readonly + ): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | --------------------------------------------------- | ------------------------------------------- | -| x | number | Horizontal position of the mouse. | -| y | number | Vertical position of the mouse. | -| options | [MouseMoveOptions](./puppeteer.mousemoveoptions.md) | _(Optional)_ Options to configure behavior. | +| Parameter | Type | Description | +| --------- | ------------------------------------------------------------------- | ------------------------------------------- | +| x | number | Horizontal position of the mouse. | +| y | number | Vertical position of the mouse. | +| options | Readonly<[MouseMoveOptions](./puppeteer.mousemoveoptions.md)> | _(Optional)_ Options to configure behavior. | **Returns:** diff --git a/docs/api/puppeteer.mouse.up.md b/docs/api/puppeteer.mouse.up.md index e460f8a944d..8effca27370 100644 --- a/docs/api/puppeteer.mouse.up.md +++ b/docs/api/puppeteer.mouse.up.md @@ -10,15 +10,15 @@ Releases the mouse. ```typescript class Mouse { - up(options?: MouseOptions): Promise; + up(options?: Readonly): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ------------------------------------------- | ------------------------------------------- | -| options | [MouseOptions](./puppeteer.mouseoptions.md) | _(Optional)_ Options to configure behavior. | +| Parameter | Type | Description | +| --------- | ----------------------------------------------------------- | ------------------------------------------- | +| options | Readonly<[MouseOptions](./puppeteer.mouseoptions.md)> | _(Optional)_ Options to configure behavior. | **Returns:** diff --git a/docs/api/puppeteer.mouse.wheel.md b/docs/api/puppeteer.mouse.wheel.md index c7c21d599cc..e502fdf4b3b 100644 --- a/docs/api/puppeteer.mouse.wheel.md +++ b/docs/api/puppeteer.mouse.wheel.md @@ -10,15 +10,15 @@ Dispatches a `mousewheel` event. ```typescript class Mouse { - wheel(options?: MouseWheelOptions): Promise; + wheel(options?: Readonly): Promise; } ``` ## Parameters -| Parameter | Type | Description | -| --------- | ----------------------------------------------------- | ------------------------------------------------------ | -| options | [MouseWheelOptions](./puppeteer.mousewheeloptions.md) | _(Optional)_ Optional: MouseWheelOptions. | +| Parameter | Type | Description | +| --------- | --------------------------------------------------------------------- | ------------------------------------------------------ | +| options | Readonly<[MouseWheelOptions](./puppeteer.mousewheeloptions.md)> | _(Optional)_ Optional: MouseWheelOptions. | **Returns:** diff --git a/docs/api/puppeteer.pressoptions.md b/docs/api/puppeteer.pressoptions.md deleted file mode 100644 index 2cdefe8a841..00000000000 --- a/docs/api/puppeteer.pressoptions.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -sidebar_label: PressOptions ---- - -# PressOptions interface - -#### Signature: - -```typescript -export interface PressOptions -``` - -## Properties - -| Property | Modifiers | Type | Description | Default | -| -------- | --------------------- | ------ | ------------------------------------------------------------------------------------------------ | ------- | -| delay | optional | number | Time to wait between keydown and keyup in milliseconds. Defaults to 0. | | -| text | optional | string | If specified, generates an input event with this text. | | diff --git a/docs/api/puppeteer.typeoptions.md b/docs/api/puppeteer.typeoptions.md new file mode 100644 index 00000000000..340cbc0de96 --- /dev/null +++ b/docs/api/puppeteer.typeoptions.md @@ -0,0 +1,17 @@ +--- +sidebar_label: TypeOptions +--- + +# TypeOptions interface + +#### Signature: + +```typescript +export interface TypeOptions +``` + +## Properties + +| Property | Modifiers | Type | Description | Default | +| -------- | --------------------- | ------ | ----------- | ------- | +| delay | optional | number | | | diff --git a/packages/puppeteer-core/src/api/ElementHandle.ts b/packages/puppeteer-core/src/api/ElementHandle.ts index 59a6f78d5d4..fa97e33be0e 100644 --- a/packages/puppeteer-core/src/api/ElementHandle.ts +++ b/packages/puppeteer-core/src/api/ElementHandle.ts @@ -20,7 +20,6 @@ import {Frame} from '../api/Frame.js'; import {CDPSession} from '../common/Connection.js'; import {ExecutionContext} from '../common/ExecutionContext.js'; import {getQueryHandlerAndSelector} from '../common/GetQueryHandler.js'; -import {MouseClickOptions} from '../common/Input.js'; import {WaitForSelectorOptions} from '../common/IsolatedWorld.js'; import {LazyArg} from '../common/LazyArg.js'; import { @@ -35,6 +34,7 @@ import {isString, withSourcePuppeteerURLIfNone} from '../common/util.js'; import {assert} from '../util/assert.js'; import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js'; +import {KeyPressOptions, MouseClickOptions, TypeOptions} from './Input.js'; import {JSHandle} from './JSHandle.js'; import {ScreenshotOptions} from './Page.js'; @@ -88,20 +88,6 @@ export interface ClickOptions extends MouseClickOptions { offset?: Offset; } -/** - * @public - */ -export interface PressOptions { - /** - * Time to wait between `keydown` and `keyup` in milliseconds. Defaults to 0. - */ - delay?: number; - /** - * If specified, generates an input event with this text. - */ - text?: string; -} - /** * @public */ @@ -858,7 +844,7 @@ export class ElementHandle< * * @param options - Delay in milliseconds. Defaults to 0. */ - async type(text: string, options?: {delay: number}): Promise; + async type(text: string, options?: Readonly): Promise; async type(): Promise { throw new Error('Not implemented'); } @@ -877,7 +863,10 @@ export class ElementHandle< * @param key - Name of key to press, such as `ArrowLeft`. * See {@link KeyInput} for a list of all key names. */ - async press(key: KeyInput, options?: PressOptions): Promise; + async press( + key: KeyInput, + options?: Readonly + ): Promise; async press(): Promise { throw new Error('Not implemented'); } diff --git a/packages/puppeteer-core/src/api/Input.ts b/packages/puppeteer-core/src/api/Input.ts index 5f734c1cbf0..6966a733c67 100644 --- a/packages/puppeteer-core/src/api/Input.ts +++ b/packages/puppeteer-core/src/api/Input.ts @@ -82,6 +82,11 @@ export type KeyPressOptions = KeyDownOptions & TypeOptions; * @public */ export class Keyboard { + /** + * @internal + */ + constructor() {} + /** * Dispatches a `keydown` event. * @@ -354,6 +359,11 @@ export type MouseButton = (typeof MouseButton)[keyof typeof MouseButton]; * @public */ export class Mouse { + /** + * @internal + */ + constructor() {} + /** * Resets the mouse to the default state: No buttons pressed; position at * (0,0). @@ -504,6 +514,11 @@ export class Mouse { * @public */ export class Touchscreen { + /** + * @internal + */ + constructor() {} + /** * Dispatches a `touchstart` and `touchend` event. * @param x - Horizontal position of the tap. diff --git a/packages/puppeteer-core/src/api/Page.ts b/packages/puppeteer-core/src/api/Page.ts index 2c9c872eac0..04995a49bf0 100644 --- a/packages/puppeteer-core/src/api/Page.ts +++ b/packages/puppeteer-core/src/api/Page.ts @@ -29,7 +29,6 @@ import type {Dialog} from '../common/Dialog.js'; import {TargetCloseError} from '../common/Errors.js'; import {EventEmitter, Handler} from '../common/EventEmitter.js'; import type {FileChooser} from '../common/FileChooser.js'; -import type {Keyboard, Mouse, Touchscreen} from '../common/Input.js'; import type {WaitForSelectorOptions} from '../common/IsolatedWorld.js'; import type {PuppeteerLifeCycleEvent} from '../common/LifecycleWatcher.js'; import { @@ -72,6 +71,7 @@ import type { FrameAddStyleTagOptions, FrameWaitForFunctionOptions, } from './Frame.js'; +import {Keyboard, Mouse, Touchscreen} from './Input.js'; import type {JSHandle} from './JSHandle.js'; import {Locator} from './Locator.js'; diff --git a/packages/puppeteer-core/src/api/api.ts b/packages/puppeteer-core/src/api/api.ts index e9245ceded8..f4bcd2ef4fe 100644 --- a/packages/puppeteer-core/src/api/api.ts +++ b/packages/puppeteer-core/src/api/api.ts @@ -19,6 +19,7 @@ export * from './BrowserContext.js'; export * from './Page.js'; export * from './JSHandle.js'; export * from './ElementHandle.js'; +export * from './Input.js'; export * from './Frame.js'; export * from './HTTPResponse.js'; export * from './HTTPRequest.js'; diff --git a/packages/puppeteer-core/src/common/ElementHandle.ts b/packages/puppeteer-core/src/common/ElementHandle.ts index 0204133825a..3f43abedbe0 100644 --- a/packages/puppeteer-core/src/common/ElementHandle.ts +++ b/packages/puppeteer-core/src/common/ElementHandle.ts @@ -23,8 +23,8 @@ import { ElementHandle, Offset, Point, - PressOptions, } from '../api/ElementHandle.js'; +import {KeyPressOptions, TypeOptions} from '../api/Input.js'; import {Page, ScreenshotOptions} from '../api/Page.js'; import {assert} from '../util/assert.js'; @@ -458,12 +458,18 @@ export class CDPElementHandle< await this.#page.touchscreen.touchEnd(); } - override async type(text: string, options?: {delay: number}): Promise { + override async type( + text: string, + options?: Readonly + ): Promise { await this.focus(); await this.#page.keyboard.type(text, options); } - override async press(key: KeyInput, options?: PressOptions): Promise { + override async press( + key: KeyInput, + options?: Readonly + ): Promise { await this.focus(); await this.#page.keyboard.press(key, options); } diff --git a/packages/puppeteer-core/src/common/Input.ts b/packages/puppeteer-core/src/common/Input.ts index 6cb489a151f..64479be4d80 100644 --- a/packages/puppeteer-core/src/common/Input.ts +++ b/packages/puppeteer-core/src/common/Input.ts @@ -17,6 +17,19 @@ import {Protocol} from 'devtools-protocol'; import {Point} from '../api/ElementHandle.js'; +import { + Keyboard, + KeyDownOptions, + KeyPressOptions, + Mouse, + MouseButton, + MouseClickOptions, + MouseMoveOptions, + MouseOptions, + MouseWheelOptions, + Touchscreen, + TypeOptions, +} from '../api/Input.js'; import {assert} from '../util/assert.js'; import {CDPSession} from './Connection.js'; @@ -27,47 +40,9 @@ type KeyDescription = Required< >; /** - * Keyboard provides an api for managing a virtual keyboard. - * The high level api is {@link Keyboard."type"}, - * which takes raw characters and generates proper keydown, keypress/input, - * and keyup events on your page. - * - * @remarks - * For finer control, you can use {@link Keyboard.down}, - * {@link Keyboard.up}, and {@link Keyboard.sendCharacter} - * to manually fire events as if they were generated from a real keyboard. - * - * On macOS, keyboard shortcuts like `⌘ A` -\> Select All do not work. - * See {@link https://github.com/puppeteer/puppeteer/issues/1313 | #1313}. - * - * @example - * An example of holding down `Shift` in order to select and delete some text: - * - * ```ts - * await page.keyboard.type('Hello World!'); - * await page.keyboard.press('ArrowLeft'); - * - * await page.keyboard.down('Shift'); - * for (let i = 0; i < ' World'.length; i++) - * await page.keyboard.press('ArrowLeft'); - * await page.keyboard.up('Shift'); - * - * await page.keyboard.press('Backspace'); - * // Result text will end up saying 'Hello!' - * ``` - * - * @example - * An example of pressing `A` - * - * ```ts - * await page.keyboard.down('Shift'); - * await page.keyboard.press('KeyA'); - * await page.keyboard.up('Shift'); - * ``` - * - * @public + * @internal */ -export class Keyboard { +export class CDPKeyboard extends Keyboard { #client: CDPSession; #pressedKeys = new Set(); @@ -80,39 +55,13 @@ export class Keyboard { * @internal */ constructor(client: CDPSession) { + super(); this.#client = client; } - /** - * Dispatches a `keydown` event. - * - * @remarks - * If `key` is a single character and no modifier keys besides `Shift` - * are being held down, a `keypress`/`input` event will also generated. - * The `text` option can be specified to force an input event to be generated. - * If `key` is a modifier key, `Shift`, `Meta`, `Control`, or `Alt`, - * subsequent key presses will be sent with that modifier active. - * To release the modifier key, use {@link Keyboard.up}. - * - * After the key is pressed once, subsequent calls to - * {@link Keyboard.down} will have - * {@link https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat | repeat} - * set to true. To release the key, use {@link Keyboard.up}. - * - * Modifier keys DO influence {@link Keyboard.down}. - * Holding down `Shift` will type the text in upper case. - * - * @param key - Name of key to press, such as `ArrowLeft`. - * See {@link KeyInput} for a list of all key names. - * - * @param options - An object of options. Accepts text which, if specified, - * generates an input event with this text. Accepts commands which, if specified, - * is the commands of keyboard shortcuts, - * see {@link https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h | Chromium Source Code} for valid command names. - */ - async down( + override async down( key: KeyInput, - options: {text?: string; commands?: string[]} = { + options: Readonly = { text: undefined, commands: [], } @@ -209,14 +158,7 @@ export class Keyboard { return description; } - /** - * Dispatches a `keyup` event. - * - * @param key - Name of key to release, such as `ArrowLeft`. - * See {@link KeyInput | KeyInput} - * for a list of all key names. - */ - async up(key: KeyInput): Promise { + override async up(key: KeyInput): Promise { const description = this.#keyDescriptionForString(key); this._modifiers &= ~this.#modifierBit(description.key); @@ -231,23 +173,7 @@ export class Keyboard { }); } - /** - * Dispatches a `keypress` and `input` event. - * This does not send a `keydown` or `keyup` event. - * - * @remarks - * Modifier keys DO NOT effect {@link Keyboard.sendCharacter | Keyboard.sendCharacter}. - * Holding down `Shift` will not type the text in upper case. - * - * @example - * - * ```ts - * page.keyboard.sendCharacter('嗨'); - * ``` - * - * @param char - Character to send into the page. - */ - async sendCharacter(char: string): Promise { + override async sendCharacter(char: string): Promise { await this.#client.send('Input.insertText', {text: char}); } @@ -255,30 +181,10 @@ export class Keyboard { return !!_keyDefinitions[char as KeyInput]; } - /** - * Sends a `keydown`, `keypress`/`input`, - * and `keyup` event for each character in the text. - * - * @remarks - * To press a special key, like `Control` or `ArrowDown`, - * use {@link Keyboard.press}. - * - * Modifier keys DO NOT effect `keyboard.type`. - * Holding down `Shift` will not type the text in upper case. - * - * @example - * - * ```ts - * await page.keyboard.type('Hello'); // Types instantly - * await page.keyboard.type('World', {delay: 100}); // Types slower, like a user - * ``` - * - * @param text - A text to type into a focused element. - * @param options - An object of options. Accepts delay which, - * if specified, is the time to wait between `keydown` and `keyup` in milliseconds. - * Defaults to 0. - */ - async type(text: string, options: {delay?: number} = {}): Promise { + override async type( + text: string, + options: Readonly = {} + ): Promise { const delay = options.delay || undefined; for (const char of text) { if (this.charIsKey(char)) { @@ -294,31 +200,9 @@ export class Keyboard { } } - /** - * Shortcut for {@link Keyboard.down} - * and {@link Keyboard.up}. - * - * @remarks - * If `key` is a single character and no modifier keys besides `Shift` - * are being held down, a `keypress`/`input` event will also generated. - * The `text` option can be specified to force an input event to be generated. - * - * Modifier keys DO effect {@link Keyboard.press}. - * Holding down `Shift` will type the text in upper case. - * - * @param key - Name of key to press, such as `ArrowLeft`. - * See {@link KeyInput} for a list of all key names. - * - * @param options - An object of options. Accepts text which, if specified, - * generates an input event with this text. Accepts delay which, - * if specified, is the time to wait between `keydown` and `keyup` in milliseconds. - * Defaults to 0. Accepts commands which, if specified, - * is the commands of keyboard shortcuts, - * see {@link https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h | Chromium Source Code} for valid command names. - */ - async press( + override async press( key: KeyInput, - options: {delay?: number; text?: string; commands?: string[]} = {} + options: Readonly = {} ): Promise { const {delay = null} = options; await this.down(key, options); @@ -331,82 +215,6 @@ export class Keyboard { } } -/** - * @public - */ -export interface MouseOptions { - /** - * Determines which button will be pressed. - * - * @defaultValue `'left'` - */ - button?: MouseButton; - /** - * @deprecated Use {@link MouseClickOptions.count}. - * - * Determines the click count for the mouse event. This does not perform - * multiple clicks. - * - * @defaultValue `1` - */ - clickCount?: number; -} - -/** - * @public - */ -export interface MouseClickOptions extends MouseOptions { - /** - * Time (in ms) to delay the mouse release after the mouse press. - */ - delay?: number; - /** - * Number of clicks to perform. - * - * @defaultValue `1` - */ - count?: number; -} - -/** - * @public - */ -export interface MouseWheelOptions { - deltaX?: number; - deltaY?: number; -} - -/** - * @public - */ -export interface MouseMoveOptions { - /** - * Determines the number of movements to make from the current mouse position - * to the new one. - * - * @defaultValue `1` - */ - steps?: number; -} - -/** - * Enum of valid mouse buttons. - * - * @public - */ -export const MouseButton = Object.freeze({ - Left: 'left', - Right: 'right', - Middle: 'middle', - Back: 'back', - Forward: 'forward', -}) satisfies Record; - -/** - * @public - */ -export type MouseButton = (typeof MouseButton)[keyof typeof MouseButton]; - /** * This must follow {@link Protocol.Input.DispatchMouseEventRequest.buttons}. */ @@ -467,84 +275,17 @@ interface MouseState { } /** - * The Mouse class operates in main-frame CSS pixels - * relative to the top-left corner of the viewport. - * @remarks - * Every `page` object has its own Mouse, accessible with [`page.mouse`](#pagemouse). - * - * @example - * - * ```ts - * // Using ‘page.mouse’ to trace a 100x100 square. - * await page.mouse.move(0, 0); - * await page.mouse.down(); - * await page.mouse.move(0, 100); - * await page.mouse.move(100, 100); - * await page.mouse.move(100, 0); - * await page.mouse.move(0, 0); - * await page.mouse.up(); - * ``` - * - * **Note**: The mouse events trigger synthetic `MouseEvent`s. - * This means that it does not fully replicate the functionality of what a normal user - * would be able to do with their mouse. - * - * For example, dragging and selecting text is not possible using `page.mouse`. - * Instead, you can use the {@link https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/getSelection | `DocumentOrShadowRoot.getSelection()`} functionality implemented in the platform. - * - * @example - * For example, if you want to select all content between nodes: - * - * ```ts - * await page.evaluate( - * (from, to) => { - * const selection = from.getRootNode().getSelection(); - * const range = document.createRange(); - * range.setStartBefore(from); - * range.setEndAfter(to); - * selection.removeAllRanges(); - * selection.addRange(range); - * }, - * fromJSHandle, - * toJSHandle - * ); - * ``` - * - * If you then would want to copy-paste your selection, you can use the clipboard api: - * - * ```ts - * // The clipboard api does not allow you to copy, unless the tab is focused. - * await page.bringToFront(); - * await page.evaluate(() => { - * // Copy the selected content to the clipboard - * document.execCommand('copy'); - * // Obtain the content of the clipboard as a string - * return navigator.clipboard.readText(); - * }); - * ``` - * - * **Note**: If you want access to the clipboard API, - * you have to give it permission to do so: - * - * ```ts - * await browser - * .defaultBrowserContext() - * .overridePermissions('', [ - * 'clipboard-read', - * 'clipboard-write', - * ]); - * ``` - * - * @public + * @internal */ -export class Mouse { +export class CDPMouse extends Mouse { #client: CDPSession; - #keyboard: Keyboard; + #keyboard: CDPKeyboard; /** * @internal */ - constructor(client: CDPSession, keyboard: Keyboard) { + constructor(client: CDPSession, keyboard: CDPKeyboard) { + super(); this.#client = client; this.#keyboard = keyboard; } @@ -598,11 +339,7 @@ export class Mouse { } } - /** - * Resets the mouse to the default state: No buttons pressed; position at - * (0,0). - */ - async reset(): Promise { + override async reset(): Promise { const actions = []; for (const [flag, button] of [ [MouseButtonFlag.Left, MouseButton.Left], @@ -621,17 +358,10 @@ export class Mouse { await Promise.all(actions); } - /** - * Moves the mouse to the given coordinate. - * - * @param x - Horizontal position of the mouse. - * @param y - Vertical position of the mouse. - * @param options - Options to configure behavior. - */ - async move( + override async move( x: number, y: number, - options: MouseMoveOptions = {} + options: Readonly = {} ): Promise { const {steps = 1} = options; const from = this.#state.position; @@ -656,12 +386,7 @@ export class Mouse { } } - /** - * Presses the mouse. - * - * @param options - Options to configure behavior. - */ - async down(options: MouseOptions = {}): Promise { + override async down(options: Readonly = {}): Promise { const {button = MouseButton.Left, clickCount = 1} = options; const flag = getFlag(button); if (!flag) { @@ -686,12 +411,7 @@ export class Mouse { }); } - /** - * Releases the mouse. - * - * @param options - Options to configure behavior. - */ - async up(options: MouseOptions = {}): Promise { + override async up(options: Readonly = {}): Promise { const {button = MouseButton.Left, clickCount = 1} = options; const flag = getFlag(button); if (!flag) { @@ -716,14 +436,7 @@ export class Mouse { }); } - /** - * Shortcut for `mouse.move`, `mouse.down` and `mouse.up`. - * - * @param x - Horizontal position of the mouse. - * @param y - Vertical position of the mouse. - * @param options - Options to configure behavior. - */ - async click( + override async click( x: number, y: number, options: Readonly = {} @@ -753,29 +466,9 @@ export class Mouse { await Promise.all(actions); } - /** - * Dispatches a `mousewheel` event. - * @param options - Optional: `MouseWheelOptions`. - * - * @example - * An example of zooming into an element: - * - * ```ts - * await page.goto( - * 'https://mdn.mozillademos.org/en-US/docs/Web/API/Element/wheel_event$samples/Scaling_an_element_via_the_wheel?revision=1587366' - * ); - * - * const elem = await page.$('div'); - * const boundingBox = await elem.boundingBox(); - * await page.mouse.move( - * boundingBox.x + boundingBox.width / 2, - * boundingBox.y + boundingBox.height / 2 - * ); - * - * await page.mouse.wheel({deltaY: -100}); - * ``` - */ - async wheel(options: MouseWheelOptions = {}): Promise { + override async wheel( + options: Readonly = {} + ): Promise { const {deltaX = 0, deltaY = 0} = options; const {position, buttons} = this.#state; await this.#client.send('Input.dispatchMouseEvent', { @@ -789,12 +482,10 @@ export class Mouse { }); } - /** - * Dispatches a `drag` event. - * @param start - starting point for drag - * @param target - point to drag to - */ - async drag(start: Point, target: Point): Promise { + override async drag( + start: Point, + target: Point + ): Promise { const promise = new Promise(resolve => { this.#client.once('Input.dragIntercepted', event => { return resolve(event.data); @@ -806,12 +497,10 @@ export class Mouse { return promise; } - /** - * Dispatches a `dragenter` event. - * @param target - point for emitting `dragenter` event - * @param data - drag data containing items and operations mask - */ - async dragEnter(target: Point, data: Protocol.Input.DragData): Promise { + override async dragEnter( + target: Point, + data: Protocol.Input.DragData + ): Promise { await this.#client.send('Input.dispatchDragEvent', { type: 'dragEnter', x: target.x, @@ -821,12 +510,10 @@ export class Mouse { }); } - /** - * Dispatches a `dragover` event. - * @param target - point for emitting `dragover` event - * @param data - drag data containing items and operations mask - */ - async dragOver(target: Point, data: Protocol.Input.DragData): Promise { + override async dragOver( + target: Point, + data: Protocol.Input.DragData + ): Promise { await this.#client.send('Input.dispatchDragEvent', { type: 'dragOver', x: target.x, @@ -836,12 +523,10 @@ export class Mouse { }); } - /** - * Performs a dragenter, dragover, and drop in sequence. - * @param target - point to drop on - * @param data - drag data containing items and operations mask - */ - async drop(target: Point, data: Protocol.Input.DragData): Promise { + override async drop( + target: Point, + data: Protocol.Input.DragData + ): Promise { await this.#client.send('Input.dispatchDragEvent', { type: 'drop', x: target.x, @@ -851,15 +536,7 @@ export class Mouse { }); } - /** - * Performs a drag, dragenter, dragover, and drop in sequence. - * @param start - point to drag from - * @param target - point to drop on - * @param options - An object of options. Accepts delay which, - * if specified, is the time to wait between `dragover` and `drop` in milliseconds. - * Defaults to 0. - */ - async dragAndDrop( + override async dragAndDrop( start: Point, target: Point, options: {delay?: number} = {} @@ -879,37 +556,27 @@ export class Mouse { } /** - * The Touchscreen class exposes touchscreen events. - * @public + * @internal */ -export class Touchscreen { +export class CDPTouchscreen extends Touchscreen { #client: CDPSession; - #keyboard: Keyboard; + #keyboard: CDPKeyboard; /** * @internal */ - constructor(client: CDPSession, keyboard: Keyboard) { + constructor(client: CDPSession, keyboard: CDPKeyboard) { + super(); this.#client = client; this.#keyboard = keyboard; } - /** - * Dispatches a `touchstart` and `touchend` event. - * @param x - Horizontal position of the tap. - * @param y - Vertical position of the tap. - */ - async tap(x: number, y: number): Promise { + override async tap(x: number, y: number): Promise { await this.touchStart(x, y); await this.touchEnd(); } - /** - * Dispatches a `touchstart` event. - * @param x - Horizontal position of the tap. - * @param y - Vertical position of the tap. - */ - async touchStart(x: number, y: number): Promise { + override async touchStart(x: number, y: number): Promise { const touchPoints = [{x: Math.round(x), y: Math.round(y)}]; await this.#client.send('Input.dispatchTouchEvent', { type: 'touchStart', @@ -917,12 +584,8 @@ export class Touchscreen { modifiers: this.#keyboard._modifiers, }); } - /** - * Dispatches a `touchMove` event. - * @param x - Horizontal position of the move. - * @param y - Vertical position of the move. - */ - async touchMove(x: number, y: number): Promise { + + override async touchMove(x: number, y: number): Promise { const movePoints = [{x: Math.round(x), y: Math.round(y)}]; await this.#client.send('Input.dispatchTouchEvent', { type: 'touchMove', @@ -930,10 +593,8 @@ export class Touchscreen { modifiers: this.#keyboard._modifiers, }); } - /** - * Dispatches a `touchend` event. - */ - async touchEnd(): Promise { + + override async touchEnd(): Promise { await this.#client.send('Input.dispatchTouchEvent', { type: 'touchEnd', touchPoints: [], diff --git a/packages/puppeteer-core/src/common/Page.ts b/packages/puppeteer-core/src/common/Page.ts index 6dbfebf1df7..15edb8f70fc 100644 --- a/packages/puppeteer-core/src/common/Page.ts +++ b/packages/puppeteer-core/src/common/Page.ts @@ -60,7 +60,7 @@ import {EmulationManager} from './EmulationManager.js'; import {TargetCloseError} from './Errors.js'; import {FileChooser} from './FileChooser.js'; import {FrameManager, FrameManagerEmittedEvents} from './FrameManager.js'; -import {Keyboard, Mouse, Touchscreen} from './Input.js'; +import {CDPKeyboard, CDPMouse, CDPTouchscreen} from './Input.js'; import {WaitForSelectorOptions} from './IsolatedWorld.js'; import {MAIN_WORLD} from './IsolatedWorlds.js'; import { @@ -131,10 +131,10 @@ export class CDPPage extends Page { #closed = false; #client: CDPSession; #target: Target; - #keyboard: Keyboard; - #mouse: Mouse; + #keyboard: CDPKeyboard; + #mouse: CDPMouse; #timeoutSettings = new TimeoutSettings(); - #touchscreen: Touchscreen; + #touchscreen: CDPTouchscreen; #accessibility: Accessibility; #frameManager: FrameManager; #emulationManager: EmulationManager; @@ -162,9 +162,9 @@ export class CDPPage extends Page { super(); this.#client = client; this.#target = target; - this.#keyboard = new Keyboard(client); - this.#mouse = new Mouse(client, this.#keyboard); - this.#touchscreen = new Touchscreen(client, this.#keyboard); + this.#keyboard = new CDPKeyboard(client); + this.#mouse = new CDPMouse(client, this.#keyboard); + this.#touchscreen = new CDPTouchscreen(client, this.#keyboard); this.#accessibility = new Accessibility(client); this.#frameManager = new FrameManager( client, @@ -427,11 +427,11 @@ export class CDPPage extends Page { return this.#frameManager.mainFrame(); } - override get keyboard(): Keyboard { + override get keyboard(): CDPKeyboard { return this.#keyboard; } - override get touchscreen(): Touchscreen { + override get touchscreen(): CDPTouchscreen { return this.#touchscreen; } @@ -1395,7 +1395,7 @@ export class CDPPage extends Page { return this.#closed; } - override get mouse(): Mouse { + override get mouse(): CDPMouse { return this.#mouse; } diff --git a/test/src/mouse.spec.ts b/test/src/mouse.spec.ts index 93fc885a197..df19dfd08b8 100644 --- a/test/src/mouse.spec.ts +++ b/test/src/mouse.spec.ts @@ -16,7 +16,7 @@ import os from 'os'; import expect from 'expect'; -import {MouseButton} from 'puppeteer-core'; +import {MouseButton} from 'puppeteer-core/internal/api/Input.js'; import {Page} from 'puppeteer-core/internal/api/Page.js'; import {KeyInput} from 'puppeteer-core/internal/common/USKeyboardLayout.js';