mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: implement Webdriver BiDi mouse and touchscreen (#10402)
Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
This commit is contained in:
parent
4b49212f24
commit
4f6b0d4e45
@ -13,20 +13,18 @@ class Frame {
|
|||||||
type(
|
type(
|
||||||
selector: string,
|
selector: string,
|
||||||
text: string,
|
text: string,
|
||||||
options?: {
|
options?: Readonly<TypeOptions>
|
||||||
delay: number;
|
|
||||||
}
|
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| selector | string | the selector for the element to type into. If there are multiple the first will be used. |
|
| 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 |
|
| text | string | text to type into the element |
|
||||||
| options | { delay: number; } | _(Optional)_ takes one option, <code>delay</code>, which sets the time to wait between key presses in milliseconds. Defaults to <code>0</code>. |
|
| options | Readonly<[TypeOptions](./puppeteer.typeoptions.md)> | _(Optional)_ takes one option, <code>delay</code>, which sets the time to wait between key presses in milliseconds. Defaults to <code>0</code>. |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
|
@ -15,20 +15,18 @@ class Page {
|
|||||||
type(
|
type(
|
||||||
selector: string,
|
selector: string,
|
||||||
text: string,
|
text: string,
|
||||||
options?: {
|
options?: Readonly<TypeOptions>
|
||||||
delay: number;
|
|
||||||
}
|
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| 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. |
|
| 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. |
|
| text | string | A text to type into a focused element. |
|
||||||
| options | { delay: number; } | _(Optional)_ have property <code>delay</code> which is the Time to wait between key presses in milliseconds. Defaults to <code>0</code>. |
|
| options | Readonly<[TypeOptions](./puppeteer.typeoptions.md)> | _(Optional)_ have property <code>delay</code> which is the Time to wait between key presses in milliseconds. Defaults to <code>0</code>. |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
|
@ -925,6 +925,22 @@ export class ElementHandle<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
protected async scrollIntoViewIfNeeded(
|
||||||
|
this: ElementHandle<Element>
|
||||||
|
): Promise<void> {
|
||||||
|
if (
|
||||||
|
await this.isIntersectingViewport({
|
||||||
|
threshold: 1,
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves to true if the element is visible in the current viewport. If an
|
* 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
|
* element is an SVG, we check if the svg owner element is in the viewport
|
||||||
|
@ -35,6 +35,7 @@ import {
|
|||||||
} from '../common/types.js';
|
} from '../common/types.js';
|
||||||
import {TaskManager} from '../common/WaitTask.js';
|
import {TaskManager} from '../common/WaitTask.js';
|
||||||
|
|
||||||
|
import {TypeOptions} from './Input.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
import {Locator} from './Locator.js';
|
import {Locator} from './Locator.js';
|
||||||
|
|
||||||
@ -74,6 +75,16 @@ export interface Realm {
|
|||||||
pageFunction: Func | string,
|
pageFunction: Func | string,
|
||||||
...args: Params
|
...args: Params
|
||||||
): Promise<Awaited<ReturnType<Func>>>;
|
): Promise<Awaited<ReturnType<Func>>>;
|
||||||
|
click(selector: string, options: Readonly<ClickOptions>): Promise<void>;
|
||||||
|
focus(selector: string): Promise<void>;
|
||||||
|
hover(selector: string): Promise<void>;
|
||||||
|
select(selector: string, ...values: string[]): Promise<string[]>;
|
||||||
|
tap(selector: string): Promise<void>;
|
||||||
|
type(
|
||||||
|
selector: string,
|
||||||
|
text: string,
|
||||||
|
options?: Readonly<TypeOptions>
|
||||||
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -793,12 +804,8 @@ export class Frame {
|
|||||||
*
|
*
|
||||||
* @param selector - The selector to query for.
|
* @param selector - The selector to query for.
|
||||||
*/
|
*/
|
||||||
async click(
|
click(selector: string, options: Readonly<ClickOptions> = {}): Promise<void> {
|
||||||
selector: string,
|
return this.isolatedRealm().click(selector, options);
|
||||||
options?: Readonly<ClickOptions>
|
|
||||||
): Promise<void>;
|
|
||||||
async click(): Promise<void> {
|
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -807,9 +814,8 @@ export class Frame {
|
|||||||
* @param selector - The selector to query for.
|
* @param selector - The selector to query for.
|
||||||
* @throws Throws if there's no element matching `selector`.
|
* @throws Throws if there's no element matching `selector`.
|
||||||
*/
|
*/
|
||||||
async focus(selector: string): Promise<void>;
|
async focus(selector: string): Promise<void> {
|
||||||
async focus(): Promise<void> {
|
return this.isolatedRealm().focus(selector);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -819,9 +825,8 @@ export class Frame {
|
|||||||
* @param selector - The selector to query for.
|
* @param selector - The selector to query for.
|
||||||
* @throws Throws if there's no element matching `selector`.
|
* @throws Throws if there's no element matching `selector`.
|
||||||
*/
|
*/
|
||||||
async hover(selector: string): Promise<void>;
|
hover(selector: string): Promise<void> {
|
||||||
async hover(): Promise<void> {
|
return this.isolatedRealm().hover(selector);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -842,9 +847,8 @@ export class Frame {
|
|||||||
* @returns the list of values that were successfully selected.
|
* @returns the list of values that were successfully selected.
|
||||||
* @throws Throws if there's no `<select>` matching `selector`.
|
* @throws Throws if there's no `<select>` matching `selector`.
|
||||||
*/
|
*/
|
||||||
select(selector: string, ...values: string[]): Promise<string[]>;
|
select(selector: string, ...values: string[]): Promise<string[]> {
|
||||||
select(): Promise<string[]> {
|
return this.isolatedRealm().select(selector, ...values);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -853,9 +857,8 @@ export class Frame {
|
|||||||
* @param selector - The selector to query for.
|
* @param selector - The selector to query for.
|
||||||
* @throws Throws if there's no element matching `selector`.
|
* @throws Throws if there's no element matching `selector`.
|
||||||
*/
|
*/
|
||||||
async tap(selector: string): Promise<void>;
|
tap(selector: string): Promise<void> {
|
||||||
async tap(): Promise<void> {
|
return this.isolatedRealm().tap(selector);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -879,13 +882,12 @@ export class Frame {
|
|||||||
* @param options - takes one option, `delay`, which sets the time to wait
|
* @param options - takes one option, `delay`, which sets the time to wait
|
||||||
* between key presses in milliseconds. Defaults to `0`.
|
* between key presses in milliseconds. Defaults to `0`.
|
||||||
*/
|
*/
|
||||||
async type(
|
type(
|
||||||
selector: string,
|
selector: string,
|
||||||
text: string,
|
text: string,
|
||||||
options?: {delay: number}
|
options?: Readonly<TypeOptions>
|
||||||
): Promise<void>;
|
): Promise<void> {
|
||||||
async type(): Promise<void> {
|
return this.isolatedRealm().type(selector, text, options);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,7 +71,7 @@ import type {
|
|||||||
FrameAddStyleTagOptions,
|
FrameAddStyleTagOptions,
|
||||||
FrameWaitForFunctionOptions,
|
FrameWaitForFunctionOptions,
|
||||||
} from './Frame.js';
|
} from './Frame.js';
|
||||||
import {Keyboard, Mouse, Touchscreen} from './Input.js';
|
import {Keyboard, Mouse, Touchscreen, TypeOptions} from './Input.js';
|
||||||
import type {JSHandle} from './JSHandle.js';
|
import type {JSHandle} from './JSHandle.js';
|
||||||
import {Locator} from './Locator.js';
|
import {Locator} from './Locator.js';
|
||||||
|
|
||||||
@ -2445,9 +2445,8 @@ export class Page extends EventEmitter {
|
|||||||
* successfully clicked. The Promise will be rejected if there is no element
|
* successfully clicked. The Promise will be rejected if there is no element
|
||||||
* matching `selector`.
|
* matching `selector`.
|
||||||
*/
|
*/
|
||||||
click(selector: string, options?: Readonly<ClickOptions>): Promise<void>;
|
click(selector: string, options?: Readonly<ClickOptions>): Promise<void> {
|
||||||
click(): Promise<void> {
|
return this.mainFrame().click(selector, options);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2463,9 +2462,8 @@ export class Page extends EventEmitter {
|
|||||||
* @remarks
|
* @remarks
|
||||||
* Shortcut for {@link Frame.focus | page.mainFrame().focus(selector)}.
|
* Shortcut for {@link Frame.focus | page.mainFrame().focus(selector)}.
|
||||||
*/
|
*/
|
||||||
focus(selector: string): Promise<void>;
|
focus(selector: string): Promise<void> {
|
||||||
focus(): Promise<void> {
|
return this.mainFrame().focus(selector);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2483,9 +2481,8 @@ export class Page extends EventEmitter {
|
|||||||
* @remarks
|
* @remarks
|
||||||
* Shortcut for {@link Page.hover | page.mainFrame().hover(selector)}.
|
* Shortcut for {@link Page.hover | page.mainFrame().hover(selector)}.
|
||||||
*/
|
*/
|
||||||
hover(selector: string): Promise<void>;
|
hover(selector: string): Promise<void> {
|
||||||
hover(): Promise<void> {
|
return this.mainFrame().hover(selector);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2511,9 +2508,8 @@ export class Page extends EventEmitter {
|
|||||||
* @remarks
|
* @remarks
|
||||||
* Shortcut for {@link Frame.select | page.mainFrame().select()}
|
* Shortcut for {@link Frame.select | page.mainFrame().select()}
|
||||||
*/
|
*/
|
||||||
select(selector: string, ...values: string[]): Promise<string[]>;
|
select(selector: string, ...values: string[]): Promise<string[]> {
|
||||||
select(): Promise<string[]> {
|
return this.mainFrame().select(selector, ...values);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2529,9 +2525,8 @@ export class Page extends EventEmitter {
|
|||||||
* @remarks
|
* @remarks
|
||||||
* Shortcut for {@link Frame.tap | page.mainFrame().tap(selector)}.
|
* Shortcut for {@link Frame.tap | page.mainFrame().tap(selector)}.
|
||||||
*/
|
*/
|
||||||
tap(selector: string): Promise<void>;
|
tap(selector: string): Promise<void> {
|
||||||
tap(): Promise<void> {
|
return this.mainFrame().tap(selector);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2561,10 +2556,9 @@ export class Page extends EventEmitter {
|
|||||||
type(
|
type(
|
||||||
selector: string,
|
selector: string,
|
||||||
text: string,
|
text: string,
|
||||||
options?: {delay: number}
|
options?: Readonly<TypeOptions>
|
||||||
): Promise<void>;
|
): Promise<void> {
|
||||||
type(): Promise<void> {
|
return this.mainFrame().type(selector, text, options);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,19 +151,6 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async #scrollIntoViewIfNeeded(
|
|
||||||
this: CDPElementHandle<Element>
|
|
||||||
): Promise<void> {
|
|
||||||
if (
|
|
||||||
await this.isIntersectingViewport({
|
|
||||||
threshold: 1,
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.scrollIntoView();
|
|
||||||
}
|
|
||||||
|
|
||||||
async #getOOPIFOffsets(
|
async #getOOPIFOffsets(
|
||||||
frame: Frame
|
frame: Frame
|
||||||
): Promise<{offsetX: number; offsetY: number}> {
|
): Promise<{offsetX: number; offsetY: number}> {
|
||||||
@ -300,7 +287,7 @@ export class CDPElementHandle<
|
|||||||
* If the element is detached from DOM, the method throws an error.
|
* If the element is detached from DOM, the method throws an error.
|
||||||
*/
|
*/
|
||||||
override async hover(this: CDPElementHandle<Element>): Promise<void> {
|
override async hover(this: CDPElementHandle<Element>): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint();
|
const {x, y} = await this.clickablePoint();
|
||||||
await this.#page.mouse.move(x, y);
|
await this.#page.mouse.move(x, y);
|
||||||
}
|
}
|
||||||
@ -314,7 +301,7 @@ export class CDPElementHandle<
|
|||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
options: Readonly<ClickOptions> = {}
|
options: Readonly<ClickOptions> = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint(options.offset);
|
const {x, y} = await this.clickablePoint(options.offset);
|
||||||
await this.#page.mouse.click(x, y, options);
|
await this.#page.mouse.click(x, y, options);
|
||||||
}
|
}
|
||||||
@ -330,7 +317,7 @@ export class CDPElementHandle<
|
|||||||
this.#page.isDragInterceptionEnabled(),
|
this.#page.isDragInterceptionEnabled(),
|
||||||
'Drag Interception is not enabled!'
|
'Drag Interception is not enabled!'
|
||||||
);
|
);
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const start = await this.clickablePoint();
|
const start = await this.clickablePoint();
|
||||||
return await this.#page.mouse.drag(start, target);
|
return await this.#page.mouse.drag(start, target);
|
||||||
}
|
}
|
||||||
@ -339,7 +326,7 @@ export class CDPElementHandle<
|
|||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const target = await this.clickablePoint();
|
const target = await this.clickablePoint();
|
||||||
await this.#page.mouse.dragEnter(target, data);
|
await this.#page.mouse.dragEnter(target, data);
|
||||||
}
|
}
|
||||||
@ -348,7 +335,7 @@ export class CDPElementHandle<
|
|||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const target = await this.clickablePoint();
|
const target = await this.clickablePoint();
|
||||||
await this.#page.mouse.dragOver(target, data);
|
await this.#page.mouse.dragOver(target, data);
|
||||||
}
|
}
|
||||||
@ -357,7 +344,7 @@ export class CDPElementHandle<
|
|||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const destination = await this.clickablePoint();
|
const destination = await this.clickablePoint();
|
||||||
await this.#page.mouse.drop(destination, data);
|
await this.#page.mouse.drop(destination, data);
|
||||||
}
|
}
|
||||||
@ -371,7 +358,7 @@ export class CDPElementHandle<
|
|||||||
this.#page.isDragInterceptionEnabled(),
|
this.#page.isDragInterceptionEnabled(),
|
||||||
'Drag Interception is not enabled!'
|
'Drag Interception is not enabled!'
|
||||||
);
|
);
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const startPoint = await this.clickablePoint();
|
const startPoint = await this.clickablePoint();
|
||||||
const targetPoint = await target.clickablePoint();
|
const targetPoint = await target.clickablePoint();
|
||||||
await this.#page.mouse.dragAndDrop(startPoint, targetPoint, options);
|
await this.#page.mouse.dragAndDrop(startPoint, targetPoint, options);
|
||||||
@ -435,26 +422,26 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async tap(this: CDPElementHandle<Element>): Promise<void> {
|
override async tap(this: CDPElementHandle<Element>): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint();
|
const {x, y} = await this.clickablePoint();
|
||||||
await this.#page.touchscreen.touchStart(x, y);
|
await this.#page.touchscreen.touchStart(x, y);
|
||||||
await this.#page.touchscreen.touchEnd();
|
await this.#page.touchscreen.touchEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
override async touchStart(this: CDPElementHandle<Element>): Promise<void> {
|
override async touchStart(this: CDPElementHandle<Element>): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint();
|
const {x, y} = await this.clickablePoint();
|
||||||
await this.#page.touchscreen.touchStart(x, y);
|
await this.#page.touchscreen.touchStart(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async touchMove(this: CDPElementHandle<Element>): Promise<void> {
|
override async touchMove(this: CDPElementHandle<Element>): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
const {x, y} = await this.clickablePoint();
|
const {x, y} = await this.clickablePoint();
|
||||||
await this.#page.touchscreen.touchMove(x, y);
|
await this.#page.touchscreen.touchMove(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async touchEnd(this: CDPElementHandle<Element>): Promise<void> {
|
override async touchEnd(this: CDPElementHandle<Element>): Promise<void> {
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
await this.#page.touchscreen.touchEnd();
|
await this.#page.touchscreen.touchEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,7 +539,7 @@ export class CDPElementHandle<
|
|||||||
needsViewportReset = true;
|
needsViewportReset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.#scrollIntoViewIfNeeded();
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
|
||||||
boundingBox = await this.boundingBox();
|
boundingBox = await this.boundingBox();
|
||||||
assert(boundingBox, 'Node is either not visible or not an HTMLElement');
|
assert(boundingBox, 'Node is either not visible or not an HTMLElement');
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import {Protocol} from 'devtools-protocol';
|
import {Protocol} from 'devtools-protocol';
|
||||||
|
|
||||||
import {type ClickOptions, ElementHandle} from '../api/ElementHandle.js';
|
import {ElementHandle} from '../api/ElementHandle.js';
|
||||||
import {
|
import {
|
||||||
Frame as BaseFrame,
|
Frame as BaseFrame,
|
||||||
FrameAddScriptTagOptions,
|
FrameAddScriptTagOptions,
|
||||||
@ -470,37 +470,6 @@ export class Frame extends BaseFrame {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async click(
|
|
||||||
selector: string,
|
|
||||||
options: Readonly<ClickOptions> = {}
|
|
||||||
): Promise<void> {
|
|
||||||
return this.isolatedRealm().click(selector, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async focus(selector: string): Promise<void> {
|
|
||||||
return this.isolatedRealm().focus(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async hover(selector: string): Promise<void> {
|
|
||||||
return this.isolatedRealm().hover(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
override select(selector: string, ...values: string[]): Promise<string[]> {
|
|
||||||
return this.isolatedRealm().select(selector, ...values);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async tap(selector: string): Promise<void> {
|
|
||||||
return this.isolatedRealm().tap(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async type(
|
|
||||||
selector: string,
|
|
||||||
text: string,
|
|
||||||
options?: {delay: number}
|
|
||||||
): Promise<void> {
|
|
||||||
return this.isolatedRealm().type(selector, text, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async title(): Promise<string> {
|
override async title(): Promise<string> {
|
||||||
return this.isolatedRealm().title();
|
return this.isolatedRealm().title();
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import {Protocol} from 'devtools-protocol';
|
|||||||
|
|
||||||
import type {ClickOptions, ElementHandle} from '../api/ElementHandle.js';
|
import type {ClickOptions, ElementHandle} from '../api/ElementHandle.js';
|
||||||
import {Realm} from '../api/Frame.js';
|
import {Realm} from '../api/Frame.js';
|
||||||
|
import {TypeOptions} from '../api/Input.js';
|
||||||
import {JSHandle} from '../api/JSHandle.js';
|
import {JSHandle} from '../api/JSHandle.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
import {Deferred} from '../util/Deferred.js';
|
import {Deferred} from '../util/Deferred.js';
|
||||||
@ -309,7 +310,7 @@ export class IsolatedWorld implements Realm {
|
|||||||
|
|
||||||
async click(
|
async click(
|
||||||
selector: string,
|
selector: string,
|
||||||
options: Readonly<ClickOptions> = {}
|
options?: Readonly<ClickOptions>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const handle = await this.$(selector);
|
const handle = await this.$(selector);
|
||||||
assert(handle, `No element found for selector: ${selector}`);
|
assert(handle, `No element found for selector: ${selector}`);
|
||||||
@ -349,7 +350,7 @@ export class IsolatedWorld implements Realm {
|
|||||||
async type(
|
async type(
|
||||||
selector: string,
|
selector: string,
|
||||||
text: string,
|
text: string,
|
||||||
options?: {delay: number}
|
options?: Readonly<TypeOptions>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const handle = await this.$(selector);
|
const handle = await this.$(selector);
|
||||||
assert(handle, `No element found for selector: ${selector}`);
|
assert(handle, `No element found for selector: ${selector}`);
|
||||||
|
@ -20,7 +20,7 @@ import {Protocol} from 'devtools-protocol';
|
|||||||
|
|
||||||
import type {Browser} from '../api/Browser.js';
|
import type {Browser} from '../api/Browser.js';
|
||||||
import type {BrowserContext} from '../api/BrowserContext.js';
|
import type {BrowserContext} from '../api/BrowserContext.js';
|
||||||
import {ClickOptions, ElementHandle} from '../api/ElementHandle.js';
|
import {ElementHandle} from '../api/ElementHandle.js';
|
||||||
import {
|
import {
|
||||||
Frame,
|
Frame,
|
||||||
FrameAddScriptTagOptions,
|
FrameAddScriptTagOptions,
|
||||||
@ -33,13 +33,13 @@ import {
|
|||||||
GeolocationOptions,
|
GeolocationOptions,
|
||||||
MediaFeature,
|
MediaFeature,
|
||||||
Metrics,
|
Metrics,
|
||||||
|
NewDocumentScriptEvaluation,
|
||||||
Page,
|
Page,
|
||||||
PageEmittedEvents,
|
PageEmittedEvents,
|
||||||
ScreenshotClip,
|
ScreenshotClip,
|
||||||
ScreenshotOptions,
|
ScreenshotOptions,
|
||||||
WaitForOptions,
|
WaitForOptions,
|
||||||
WaitTimeoutOptions,
|
WaitTimeoutOptions,
|
||||||
NewDocumentScriptEvaluation,
|
|
||||||
} from '../api/Page.js';
|
} from '../api/Page.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
import {Deferred} from '../util/Deferred.js';
|
import {Deferred} from '../util/Deferred.js';
|
||||||
@ -1399,37 +1399,6 @@ export class CDPPage extends Page {
|
|||||||
return this.#mouse;
|
return this.#mouse;
|
||||||
}
|
}
|
||||||
|
|
||||||
override click(
|
|
||||||
selector: string,
|
|
||||||
options: Readonly<ClickOptions> = {}
|
|
||||||
): Promise<void> {
|
|
||||||
return this.mainFrame().click(selector, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
override focus(selector: string): Promise<void> {
|
|
||||||
return this.mainFrame().focus(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
override hover(selector: string): Promise<void> {
|
|
||||||
return this.mainFrame().hover(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
override select(selector: string, ...values: string[]): Promise<string[]> {
|
|
||||||
return this.mainFrame().select(selector, ...values);
|
|
||||||
}
|
|
||||||
|
|
||||||
override tap(selector: string): Promise<void> {
|
|
||||||
return this.mainFrame().tap(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
override type(
|
|
||||||
selector: string,
|
|
||||||
text: string,
|
|
||||||
options?: {delay: number}
|
|
||||||
): Promise<void> {
|
|
||||||
return this.mainFrame().type(selector, text, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
override waitForXPath(
|
override waitForXPath(
|
||||||
xpath: string,
|
xpath: string,
|
||||||
options: WaitForSelectorOptions = {}
|
options: WaitForSelectorOptions = {}
|
||||||
|
@ -99,6 +99,15 @@ interface Commands {
|
|||||||
returnType: Bidi.BrowsingContext.CaptureScreenshotResult;
|
returnType: Bidi.BrowsingContext.CaptureScreenshotResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
'input.performActions': {
|
||||||
|
params: Bidi.Input.PerformActionsParameters;
|
||||||
|
returnType: Bidi.Message.EmptyResult;
|
||||||
|
};
|
||||||
|
'input.releaseActions': {
|
||||||
|
params: Bidi.Input.ReleaseActionsParameters;
|
||||||
|
returnType: Bidi.Message.EmptyResult;
|
||||||
|
};
|
||||||
|
|
||||||
'session.new': {
|
'session.new': {
|
||||||
params: {
|
params: {
|
||||||
// capabilities: session.CapabilitiesRequest
|
// capabilities: session.CapabilitiesRequest
|
||||||
|
@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
|
|
||||||
import {ElementHandle as BaseElementHandle} from '../../api/ElementHandle.js';
|
import {
|
||||||
|
ElementHandle as BaseElementHandle,
|
||||||
|
ClickOptions,
|
||||||
|
} from '../../api/ElementHandle.js';
|
||||||
|
import {assert} from '../../util/assert.js';
|
||||||
|
|
||||||
import {Frame} from './Frame.js';
|
import {Frame} from './Frame.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
@ -63,4 +67,80 @@ export class ElementHandle<
|
|||||||
// TODO: Should assert element has a Sandbox
|
// TODO: Should assert element has a Sandbox
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ///////////////////
|
||||||
|
// // Input methods //
|
||||||
|
// ///////////////////
|
||||||
|
override async click(
|
||||||
|
this: ElementHandle<Element>,
|
||||||
|
options?: Readonly<ClickOptions>
|
||||||
|
): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const {x = 0, y = 0} = options?.offset ?? {};
|
||||||
|
const remoteValue = this.remoteValue();
|
||||||
|
assert('sharedId' in remoteValue);
|
||||||
|
return this.#frame.page().mouse.click(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
Object.assign({}, options, {
|
||||||
|
origin: {
|
||||||
|
type: 'element' as const,
|
||||||
|
element: remoteValue as Bidi.CommonDataTypes.SharedReference,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async hover(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const remoteValue = this.remoteValue();
|
||||||
|
assert('sharedId' in remoteValue);
|
||||||
|
return this.#frame.page().mouse.move(0, 0, {
|
||||||
|
origin: {
|
||||||
|
type: 'element' as const,
|
||||||
|
element: remoteValue as Bidi.CommonDataTypes.SharedReference,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async tap(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const remoteValue = this.remoteValue();
|
||||||
|
assert('sharedId' in remoteValue);
|
||||||
|
return this.#frame.page().touchscreen.tap(0, 0, {
|
||||||
|
origin: {
|
||||||
|
type: 'element' as const,
|
||||||
|
element: remoteValue as Bidi.CommonDataTypes.SharedReference,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async touchStart(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const remoteValue = this.remoteValue();
|
||||||
|
assert('sharedId' in remoteValue);
|
||||||
|
return this.#frame.page().touchscreen.touchStart(0, 0, {
|
||||||
|
origin: {
|
||||||
|
type: 'element' as const,
|
||||||
|
element: remoteValue as Bidi.CommonDataTypes.SharedReference,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async touchMove(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const remoteValue = this.remoteValue();
|
||||||
|
assert('sharedId' in remoteValue);
|
||||||
|
return this.#frame.page().touchscreen.touchMove(0, 0, {
|
||||||
|
origin: {
|
||||||
|
type: 'element' as const,
|
||||||
|
element: remoteValue as Bidi.CommonDataTypes.SharedReference,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async touchEnd(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
await this.#frame.page().touchscreen.touchEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,13 +54,14 @@ export class Frame extends BaseFrame {
|
|||||||
this._id = this.#context.id;
|
this._id = this.#context.id;
|
||||||
this._parentId = parentId ?? undefined;
|
this._parentId = parentId ?? undefined;
|
||||||
|
|
||||||
|
const puppeteerRealm = context.createSandboxRealm(UTILITY_WORLD_NAME);
|
||||||
this.sandboxes = {
|
this.sandboxes = {
|
||||||
[MAIN_SANDBOX]: new Sandbox(context, timeoutSettings),
|
[MAIN_SANDBOX]: new Sandbox(context, timeoutSettings),
|
||||||
[PUPPETEER_SANDBOX]: new Sandbox(
|
[PUPPETEER_SANDBOX]: new Sandbox(puppeteerRealm, timeoutSettings),
|
||||||
context.createSandboxRealm(UTILITY_WORLD_NAME),
|
|
||||||
timeoutSettings
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
puppeteerRealm.setFrame(this);
|
||||||
|
context.setFrame(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
override mainRealm(): Sandbox {
|
override mainRealm(): Sandbox {
|
||||||
|
332
packages/puppeteer-core/src/common/bidi/Input.ts
Normal file
332
packages/puppeteer-core/src/common/bidi/Input.ts
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2017 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 {Point} from '../../api/ElementHandle.js';
|
||||||
|
import {
|
||||||
|
Mouse as BaseMouse,
|
||||||
|
MouseButton,
|
||||||
|
MouseClickOptions,
|
||||||
|
MouseMoveOptions,
|
||||||
|
MouseOptions,
|
||||||
|
MouseWheelOptions,
|
||||||
|
Touchscreen as BaseTouchscreen,
|
||||||
|
} from '../../api/Input.js';
|
||||||
|
|
||||||
|
import {BrowsingContext} from './BrowsingContext.js';
|
||||||
|
|
||||||
|
const enum InputId {
|
||||||
|
Mouse = '__puppeteer_mouse',
|
||||||
|
Wheel = '__puppeteer_wheel',
|
||||||
|
Finger = '__puppeteer_finger',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
interface BidiMouseClickOptions extends MouseClickOptions {
|
||||||
|
origin?: Bidi.Input.Origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
interface BidiMouseMoveOptions extends MouseMoveOptions {
|
||||||
|
origin?: Bidi.Input.Origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
interface BidiTouchMoveOptions {
|
||||||
|
origin?: Bidi.Input.Origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBidiButton = (button: MouseButton) => {
|
||||||
|
switch (button) {
|
||||||
|
case MouseButton.Left:
|
||||||
|
return 0;
|
||||||
|
case MouseButton.Middle:
|
||||||
|
return 1;
|
||||||
|
case MouseButton.Right:
|
||||||
|
return 2;
|
||||||
|
case MouseButton.Back:
|
||||||
|
return 3;
|
||||||
|
case MouseButton.Forward:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export class Mouse extends BaseMouse {
|
||||||
|
#context: BrowsingContext;
|
||||||
|
#lastMovePoint?: Point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
constructor(context: BrowsingContext) {
|
||||||
|
super();
|
||||||
|
this.#context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
override async reset(): Promise<void> {
|
||||||
|
this.#lastMovePoint = undefined;
|
||||||
|
await this.#context.connection.send('input.releaseActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async move(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
options: Readonly<BidiMouseMoveOptions> = {}
|
||||||
|
): Promise<void> {
|
||||||
|
this.#lastMovePoint = {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
};
|
||||||
|
await this.#context.connection.send('input.performActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.SourceActionsType.Pointer,
|
||||||
|
id: InputId.Mouse,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.PointerMove,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
duration: (options.steps ?? 0) * 50,
|
||||||
|
origin: options.origin,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async down(options: Readonly<MouseOptions> = {}): Promise<void> {
|
||||||
|
await this.#context.connection.send('input.performActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.SourceActionsType.Pointer,
|
||||||
|
id: InputId.Mouse,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.PointerDown,
|
||||||
|
button: getBidiButton(options.button ?? MouseButton.Left),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async up(options: Readonly<MouseOptions> = {}): Promise<void> {
|
||||||
|
await this.#context.connection.send('input.performActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.SourceActionsType.Pointer,
|
||||||
|
id: InputId.Mouse,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.PointerUp,
|
||||||
|
button: getBidiButton(options.button ?? MouseButton.Left),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async click(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
options: Readonly<BidiMouseClickOptions> = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const actions: Bidi.Input.PointerSourceAction[] = [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.PointerMove,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
origin: options.origin,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const pointerDownAction = {
|
||||||
|
type: Bidi.Input.ActionType.PointerDown,
|
||||||
|
button: getBidiButton(options.button ?? MouseButton.Left),
|
||||||
|
} as const;
|
||||||
|
const pointerUpAction = {
|
||||||
|
type: Bidi.Input.ActionType.PointerUp,
|
||||||
|
button: pointerDownAction.button,
|
||||||
|
} as const;
|
||||||
|
for (let i = 1; i < (options.count ?? 1); ++i) {
|
||||||
|
actions.push(pointerDownAction, pointerUpAction);
|
||||||
|
}
|
||||||
|
actions.push(pointerDownAction);
|
||||||
|
if (options.delay) {
|
||||||
|
actions.push({
|
||||||
|
type: Bidi.Input.ActionType.Pause,
|
||||||
|
duration: options.delay,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
actions.push(pointerUpAction);
|
||||||
|
await this.#context.connection.send('input.performActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.SourceActionsType.Pointer,
|
||||||
|
id: InputId.Mouse,
|
||||||
|
actions,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async wheel(
|
||||||
|
options: Readonly<MouseWheelOptions> = {}
|
||||||
|
): Promise<void> {
|
||||||
|
await this.#context.connection.send('input.performActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.SourceActionsType.Wheel,
|
||||||
|
id: InputId.Wheel,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.Scroll,
|
||||||
|
...(this.#lastMovePoint ?? {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
}),
|
||||||
|
deltaX: options.deltaX ?? 0,
|
||||||
|
deltaY: options.deltaY ?? 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export class Touchscreen extends BaseTouchscreen {
|
||||||
|
#context: BrowsingContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
constructor(context: BrowsingContext) {
|
||||||
|
super();
|
||||||
|
this.#context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
override async tap(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
options: BidiTouchMoveOptions = {}
|
||||||
|
): Promise<void> {
|
||||||
|
await this.touchStart(x, y, options);
|
||||||
|
await this.touchEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
override async touchStart(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
options: BidiTouchMoveOptions = {}
|
||||||
|
): Promise<void> {
|
||||||
|
await this.#context.connection.send('input.performActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.SourceActionsType.Pointer,
|
||||||
|
id: InputId.Finger,
|
||||||
|
parameters: {
|
||||||
|
pointerType: Bidi.Input.PointerType.Touch,
|
||||||
|
},
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.PointerMove,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
origin: options.origin,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.PointerDown,
|
||||||
|
button: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async touchMove(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
options: BidiTouchMoveOptions = {}
|
||||||
|
): Promise<void> {
|
||||||
|
await this.#context.connection.send('input.performActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.SourceActionsType.Pointer,
|
||||||
|
id: InputId.Finger,
|
||||||
|
parameters: {
|
||||||
|
pointerType: Bidi.Input.PointerType.Touch,
|
||||||
|
},
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.PointerMove,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
origin: options.origin,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async touchEnd(): Promise<void> {
|
||||||
|
await this.#context.connection.send('input.performActions', {
|
||||||
|
context: this.#context.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.SourceActionsType.Pointer,
|
||||||
|
id: InputId.Finger,
|
||||||
|
parameters: {
|
||||||
|
pointerType: Bidi.Input.PointerType.Touch,
|
||||||
|
},
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: Bidi.Input.ActionType.PointerUp,
|
||||||
|
button: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -58,6 +58,7 @@ import {Connection} from './Connection.js';
|
|||||||
import {Frame} from './Frame.js';
|
import {Frame} from './Frame.js';
|
||||||
import {HTTPRequest} from './HTTPRequest.js';
|
import {HTTPRequest} from './HTTPRequest.js';
|
||||||
import {HTTPResponse} from './HTTPResponse.js';
|
import {HTTPResponse} from './HTTPResponse.js';
|
||||||
|
import {Mouse, Touchscreen} from './Input.js';
|
||||||
import {NetworkManager} from './NetworkManager.js';
|
import {NetworkManager} from './NetworkManager.js';
|
||||||
import {getBidiHandle} from './Realm.js';
|
import {getBidiHandle} from './Realm.js';
|
||||||
import {BidiSerializer} from './Serializer.js';
|
import {BidiSerializer} from './Serializer.js';
|
||||||
@ -127,6 +128,8 @@ export class Page extends PageBase {
|
|||||||
#tracing: Tracing;
|
#tracing: Tracing;
|
||||||
#coverage: Coverage;
|
#coverage: Coverage;
|
||||||
#emulationManager: EmulationManager;
|
#emulationManager: EmulationManager;
|
||||||
|
#mouse: Mouse;
|
||||||
|
#touchscreen: Touchscreen;
|
||||||
|
|
||||||
constructor(browserContext: BrowserContext, info: {context: string}) {
|
constructor(browserContext: BrowserContext, info: {context: string}) {
|
||||||
super();
|
super();
|
||||||
@ -157,6 +160,8 @@ export class Page extends PageBase {
|
|||||||
this.#emulationManager = new EmulationManager(
|
this.#emulationManager = new EmulationManager(
|
||||||
this.mainFrame().context().cdpSession
|
this.mainFrame().context().cdpSession
|
||||||
);
|
);
|
||||||
|
this.#mouse = new Mouse(this.mainFrame().context());
|
||||||
|
this.#touchscreen = new Touchscreen(this.mainFrame().context());
|
||||||
}
|
}
|
||||||
|
|
||||||
override get accessibility(): Accessibility {
|
override get accessibility(): Accessibility {
|
||||||
@ -171,6 +176,14 @@ export class Page extends PageBase {
|
|||||||
return this.#coverage;
|
return this.#coverage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override get mouse(): Mouse {
|
||||||
|
return this.#mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
override get touchscreen(): Touchscreen {
|
||||||
|
return this.#touchscreen;
|
||||||
|
}
|
||||||
|
|
||||||
override browser(): Browser {
|
override browser(): Browser {
|
||||||
return this.#browserContext.browser();
|
return this.#browserContext.browser();
|
||||||
}
|
}
|
||||||
@ -215,8 +228,6 @@ export class Page extends PageBase {
|
|||||||
this.#timeoutSettings,
|
this.#timeoutSettings,
|
||||||
info.parent
|
info.parent
|
||||||
);
|
);
|
||||||
context.setFrame(frame);
|
|
||||||
|
|
||||||
this.#frameTree.addFrame(frame);
|
this.#frameTree.addFrame(frame);
|
||||||
this.emit(FrameManagerEmittedEvents.FrameAttached, frame);
|
this.emit(FrameManagerEmittedEvents.FrameAttached, frame);
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ElementHandle} from '../../api/ElementHandle.js';
|
import {ClickOptions, ElementHandle} from '../../api/ElementHandle.js';
|
||||||
import {Realm as RealmBase} from '../../api/Frame.js';
|
import {Realm as RealmBase} from '../../api/Frame.js';
|
||||||
|
import {TypeOptions} from '../../api/Input.js';
|
||||||
import {JSHandle as BaseJSHandle} from '../../api/JSHandle.js';
|
import {JSHandle as BaseJSHandle} from '../../api/JSHandle.js';
|
||||||
|
import {assert} from '../../util/assert.js';
|
||||||
import {TimeoutSettings} from '../TimeoutSettings.js';
|
import {TimeoutSettings} from '../TimeoutSettings.js';
|
||||||
import {
|
import {
|
||||||
EvaluateFunc,
|
EvaluateFunc,
|
||||||
@ -221,4 +223,57 @@ export class Sandbox implements RealmBase {
|
|||||||
);
|
);
|
||||||
return waitTask.result;
|
return waitTask.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ///////////////////
|
||||||
|
// // Input methods //
|
||||||
|
// ///////////////////
|
||||||
|
async click(
|
||||||
|
selector: string,
|
||||||
|
options?: Readonly<ClickOptions>
|
||||||
|
): Promise<void> {
|
||||||
|
const handle = await this.$(selector);
|
||||||
|
assert(handle, `No element found for selector: ${selector}`);
|
||||||
|
await handle.click(options);
|
||||||
|
await handle.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
async focus(selector: string): Promise<void> {
|
||||||
|
const handle = await this.$(selector);
|
||||||
|
assert(handle, `No element found for selector: ${selector}`);
|
||||||
|
await handle.focus();
|
||||||
|
await handle.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
async hover(selector: string): Promise<void> {
|
||||||
|
const handle = await this.$(selector);
|
||||||
|
assert(handle, `No element found for selector: ${selector}`);
|
||||||
|
await handle.hover();
|
||||||
|
await handle.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
async select(selector: string, ...values: string[]): Promise<string[]> {
|
||||||
|
const handle = await this.$(selector);
|
||||||
|
assert(handle, `No element found for selector: ${selector}`);
|
||||||
|
const result = await handle.select(...values);
|
||||||
|
await handle.dispose();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async tap(selector: string): Promise<void> {
|
||||||
|
const handle = await this.$(selector);
|
||||||
|
assert(handle, `No element found for selector: ${selector}`);
|
||||||
|
await handle.tap();
|
||||||
|
await handle.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
async type(
|
||||||
|
selector: string,
|
||||||
|
text: string,
|
||||||
|
options?: Readonly<TypeOptions>
|
||||||
|
): Promise<void> {
|
||||||
|
const handle = await this.$(selector);
|
||||||
|
assert(handle, `No element found for selector: ${selector}`);
|
||||||
|
await handle.type(text, options);
|
||||||
|
await handle.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,12 +293,30 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[browser.spec] Browser specs Browser.process should return child_process instance",
|
"testIdPattern": "[browser.spec] Browser specs Browser.process should return child_process instance",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[CDPSession.spec] Target.createCDPSession should not report created targets for custom CDP sessions",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[chromiumonly.spec] *",
|
"testIdPattern": "[chromiumonly.spec] *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -311,6 +329,132 @@
|
|||||||
"parameters": ["firefox", "webDriverBiDi"],
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click a partially obscured button",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click a rotated button",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click links which cause navigation",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click offscreen buttons",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click on a span with an inline element inside",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click on checkbox input and toggle",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click on checkbox label and toggle",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click svg",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click the button",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click the button if window.Node is removed",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click when one of inline box children is outside of viewport",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click wrapped links",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should double click the button",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should fail to click a missing button",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should fire aux event on middle click",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should fire back click",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should fire contextmenu event on right click",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should fire forward click",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should not hang with touch-enabled viewports",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should not throw UnhandledPromiseRejection when page closes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should scroll and click the button",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[Connection.spec] WebDriver BiDi Connection should work",
|
"testIdPattern": "[Connection.spec] WebDriver BiDi Connection should work",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -365,6 +509,36 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should not work for TextNodes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should throw for detached nodes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should work",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should work for Shadow DOM v1",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.hover should work",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isVisible and ElementHandle.isHidden should work",
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isVisible and ElementHandle.isHidden should work",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -479,6 +653,30 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[headful.spec] headful tests HEADFUL headless should be able to read cookies written by headful",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[headful.spec] headful tests HEADFUL should close browser with beforeunload page",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[headful.spec] headful tests HEADFUL should have default url when launching browser",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[headful.spec] headful tests HEADFUL target.page() should return a DevTools page if custom isPageTarget is provided",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[idle_override.spec] *",
|
"testIdPattern": "[idle_override.spec] *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -509,6 +707,18 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL", "PASS"]
|
"expectations": ["FAIL", "PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject waitForSelector when browser closes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath returns executablePath for channel",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath returns executablePath for channel",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -569,6 +779,12 @@
|
|||||||
"parameters": ["chrome"],
|
"parameters": ["chrome"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments",
|
||||||
|
"platforms": ["linux"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -587,6 +803,18 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[navigation.spec] navigation \"after each\" hook in \"navigation\"",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[navigation.spec] navigation \"after each\" hook in \"navigation\"",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL",
|
"testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -783,7 +1011,7 @@
|
|||||||
"testIdPattern": "[page.spec] Page Page.waitForNetworkIdle should work with aborted requests",
|
"testIdPattern": "[page.spec] Page Page.waitForNetworkIdle should work with aborted requests",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[proxy.spec] *",
|
"testIdPattern": "[proxy.spec] *",
|
||||||
@ -819,7 +1047,7 @@
|
|||||||
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work with :hover",
|
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work with :hover",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[queryhandler.spec] Query handler tests Text selectors in Page should clear caches",
|
"testIdPattern": "[queryhandler.spec] Query handler tests Text selectors in Page should clear caches",
|
||||||
@ -1041,18 +1269,30 @@
|
|||||||
"testIdPattern": "[accessibility.spec] Accessibility get snapshots while the tree is re-calculated",
|
"testIdPattern": "[accessibility.spec] Accessibility get snapshots while the tree is re-calculated",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[accessibility.spec] Accessibility should report uninteresting nodes",
|
"testIdPattern": "[accessibility.spec] Accessibility should report uninteresting nodes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[accessibility.spec] Accessibility should work",
|
"testIdPattern": "[accessibility.spec] Accessibility should work",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1109,6 +1349,12 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL", "PASS"]
|
"expectations": ["FAIL", "PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click offscreen buttons",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
|
"expectations": ["TIMEOUT"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[click.spec] Page.click should click on checkbox label and toggle",
|
"testIdPattern": "[click.spec] Page.click should click on checkbox label and toggle",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -1133,6 +1379,18 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should double click the button",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should not hang with touch-enabled viewports",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript",
|
"testIdPattern": "[click.spec] Page.click should scroll and click with disabled javascript",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -1505,6 +1763,12 @@
|
|||||||
"parameters": ["cdp", "chrome"],
|
"parameters": ["cdp", "chrome"],
|
||||||
"expectations": ["FAIL", "PASS"]
|
"expectations": ["FAIL", "PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[headful.spec] headful tests HEADFUL target.page() should return a DevTools page if custom isPageTarget is provided",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails",
|
"testIdPattern": "[ignorehttpserrors.spec] ignoreHTTPSErrors Response.securityDetails Network redirects should report SecurityDetails",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -3023,30 +3287,12 @@
|
|||||||
"parameters": ["cdp", "chrome", "headless"],
|
"parameters": ["cdp", "chrome", "headless"],
|
||||||
"expectations": ["FAIL", "PASS"]
|
"expectations": ["FAIL", "PASS"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch should work with no default arguments",
|
|
||||||
"platforms": ["linux"],
|
|
||||||
"parameters": ["chrome", "headless", "webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation \"after all\" hook in \"navigation\"",
|
"testIdPattern": "[navigation.spec] navigation \"after all\" hook in \"navigation\"",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["firefox", "headless", "webDriverBiDi"],
|
"parameters": ["firefox", "headless", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation \"after each\" hook in \"navigation\"",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["chrome", "headless", "webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[navigation.spec] navigation \"after each\" hook in \"navigation\"",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["chrome", "headless", "webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[network.spec] network \"after each\" hook for \"Same-origin set-cookie subresource\"",
|
"testIdPattern": "[network.spec] network \"after each\" hook for \"Same-origin set-cookie subresource\"",
|
||||||
"platforms": ["win32"],
|
"platforms": ["win32"],
|
||||||
|
@ -262,7 +262,10 @@ describe('ElementHandle specs', function () {
|
|||||||
await buttonTextNode.click().catch(error_ => {
|
await buttonTextNode.click().catch(error_ => {
|
||||||
return (error = error_);
|
return (error = error_);
|
||||||
});
|
});
|
||||||
expect(error.message).toBe('Node is not of type HTMLElement');
|
expect(error.message).atLeastOneToContain([
|
||||||
|
'Node is not of type HTMLElement',
|
||||||
|
'no such node',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
it('should throw for detached nodes', async () => {
|
it('should throw for detached nodes', async () => {
|
||||||
const {page, server} = getTestState();
|
const {page, server} = getTestState();
|
||||||
@ -276,7 +279,10 @@ describe('ElementHandle specs', function () {
|
|||||||
await button.click().catch(error_ => {
|
await button.click().catch(error_ => {
|
||||||
return (error = error_);
|
return (error = error_);
|
||||||
});
|
});
|
||||||
expect(error.message).toBe('Node is detached from document');
|
expect(error.message).atLeastOneToContain([
|
||||||
|
'Node is detached from document',
|
||||||
|
'no such node',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
it('should throw for hidden nodes', async () => {
|
it('should throw for hidden nodes', async () => {
|
||||||
const {page, server} = getTestState();
|
const {page, server} = getTestState();
|
||||||
@ -289,9 +295,10 @@ describe('ElementHandle specs', function () {
|
|||||||
const error = await button.click().catch(error_ => {
|
const error = await button.click().catch(error_ => {
|
||||||
return error_;
|
return error_;
|
||||||
});
|
});
|
||||||
expect(error.message).toBe(
|
expect(error.message).atLeastOneToContain([
|
||||||
'Node is either not clickable or not an HTMLElement'
|
'Node is either not clickable or not an HTMLElement',
|
||||||
);
|
'no such node',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
it('should throw for recursively hidden nodes', async () => {
|
it('should throw for recursively hidden nodes', async () => {
|
||||||
const {page, server} = getTestState();
|
const {page, server} = getTestState();
|
||||||
@ -304,9 +311,10 @@ describe('ElementHandle specs', function () {
|
|||||||
const error = await button.click().catch(error_ => {
|
const error = await button.click().catch(error_ => {
|
||||||
return error_;
|
return error_;
|
||||||
});
|
});
|
||||||
expect(error.message).toBe(
|
expect(error.message).atLeastOneToContain([
|
||||||
'Node is either not clickable or not an HTMLElement'
|
'Node is either not clickable or not an HTMLElement',
|
||||||
);
|
'no such node',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
it('should throw for <br> elements', async () => {
|
it('should throw for <br> elements', async () => {
|
||||||
const {page} = getTestState();
|
const {page} = getTestState();
|
||||||
@ -316,9 +324,10 @@ describe('ElementHandle specs', function () {
|
|||||||
const error = await br.click().catch(error_ => {
|
const error = await br.click().catch(error_ => {
|
||||||
return error_;
|
return error_;
|
||||||
});
|
});
|
||||||
expect(error.message).toBe(
|
expect(error.message).atLeastOneToContain([
|
||||||
'Node is either not clickable or not an HTMLElement'
|
'Node is either not clickable or not an HTMLElement',
|
||||||
);
|
'no such node',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user