chore: implement waitForFrame
and use clickablePoint
for ElementHandle operations (#10778)
This commit is contained in:
parent
a4a2cf1d39
commit
c4a4412920
@ -10,9 +10,9 @@ This method scrolls element into view if needed, and then uses [Page.mouse](./pu
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
abstract click(
|
click(
|
||||||
this: ElementHandle<Element>,
|
this: ElementHandle<Element>,
|
||||||
options?: ClickOptions
|
options?: Readonly<ClickOptions>
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -22,7 +22,7 @@ class ElementHandle {
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ------------------------------------------------------------ | ------------ |
|
| --------- | ------------------------------------------------------------ | ------------ |
|
||||||
| this | [ElementHandle](./puppeteer.elementhandle.md)<Element> | |
|
| this | [ElementHandle](./puppeteer.elementhandle.md)<Element> | |
|
||||||
| options | [ClickOptions](./puppeteer.clickoptions.md) | _(Optional)_ |
|
| options | Readonly<[ClickOptions](./puppeteer.clickoptions.md)> | _(Optional)_ |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ This method scrolls element into view if needed, and then uses [Page](./puppetee
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
abstract hover(this: ElementHandle<Element>): Promise<void>;
|
hover(this: ElementHandle<Element>): Promise<void>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -10,10 +10,7 @@ Focuses the element, and then uses [Keyboard.down()](./puppeteer.keyboard.down.m
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
abstract press(
|
press(key: KeyInput, options?: Readonly<KeyPressOptions>): Promise<void>;
|
||||||
key: KeyInput,
|
|
||||||
options?: Readonly<KeyPressOptions>
|
|
||||||
): Promise<void>;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ This method scrolls element into view if needed, and then uses [Touchscreen.tap(
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
abstract tap(this: ElementHandle<Element>): Promise<void>;
|
tap(this: ElementHandle<Element>): Promise<void>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ sidebar_label: ElementHandle.touchEnd
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
abstract touchEnd(this: ElementHandle<Element>): Promise<void>;
|
touchEnd(this: ElementHandle<Element>): Promise<void>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ sidebar_label: ElementHandle.touchMove
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
abstract touchMove(this: ElementHandle<Element>): Promise<void>;
|
touchMove(this: ElementHandle<Element>): Promise<void>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ sidebar_label: ElementHandle.touchStart
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
abstract touchStart(this: ElementHandle<Element>): Promise<void>;
|
touchStart(this: ElementHandle<Element>): Promise<void>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -12,10 +12,7 @@ To press a special key, like `Control` or `ArrowDown`, use [ElementHandle.press(
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class ElementHandle {
|
class ElementHandle {
|
||||||
abstract type(
|
type(text: string, options?: Readonly<KeyboardTypeOptions>): Promise<void>;
|
||||||
text: string,
|
|
||||||
options?: Readonly<KeyboardTypeOptions>
|
|
||||||
): Promise<void>;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ page.off('request', logRequest);
|
|||||||
| [viewport()](./puppeteer.page.viewport.md) | | Current page viewport settings. |
|
| [viewport()](./puppeteer.page.viewport.md) | | Current page viewport settings. |
|
||||||
| [waitForDevicePrompt(options)](./puppeteer.page.waitfordeviceprompt.md) | | <p>This method is typically coupled with an action that triggers a device request from an api such as WebBluetooth.</p><p>:::caution</p><p>This must be called before the device request is made. It will not return a currently active device prompt.</p><p>:::</p> |
|
| [waitForDevicePrompt(options)](./puppeteer.page.waitfordeviceprompt.md) | | <p>This method is typically coupled with an action that triggers a device request from an api such as WebBluetooth.</p><p>:::caution</p><p>This must be called before the device request is made. It will not return a currently active device prompt.</p><p>:::</p> |
|
||||||
| [waitForFileChooser(options)](./puppeteer.page.waitforfilechooser.md) | | <p>This method is typically coupled with an action that triggers file choosing.</p><p>:::caution</p><p>This must be called before the file chooser is launched. It will not return a currently active file chooser.</p><p>:::</p> |
|
| [waitForFileChooser(options)](./puppeteer.page.waitforfilechooser.md) | | <p>This method is typically coupled with an action that triggers file choosing.</p><p>:::caution</p><p>This must be called before the file chooser is launched. It will not return a currently active file chooser.</p><p>:::</p> |
|
||||||
| [waitForFrame(urlOrPredicate, options)](./puppeteer.page.waitforframe.md) | | |
|
| [waitForFrame(urlOrPredicate, options)](./puppeteer.page.waitforframe.md) | | Waits for a frame matching the given conditions to appear. |
|
||||||
| [waitForFunction(pageFunction, options, args)](./puppeteer.page.waitforfunction.md) | | Waits for a function to finish evaluating in the page's context. |
|
| [waitForFunction(pageFunction, options, args)](./puppeteer.page.waitforfunction.md) | | Waits for a function to finish evaluating in the page's context. |
|
||||||
| [waitForNavigation(options)](./puppeteer.page.waitfornavigation.md) | | Waits for the page to navigate to a new URL or to reload. It is useful when you run code that will indirectly cause the page to navigate. |
|
| [waitForNavigation(options)](./puppeteer.page.waitfornavigation.md) | | Waits for the page to navigate to a new URL or to reload. It is useful when you run code that will indirectly cause the page to navigate. |
|
||||||
| [waitForNetworkIdle(options)](./puppeteer.page.waitfornetworkidle.md) | | |
|
| [waitForNetworkIdle(options)](./puppeteer.page.waitfornetworkidle.md) | | |
|
||||||
|
@ -4,15 +4,15 @@ sidebar_label: Page.waitForFrame
|
|||||||
|
|
||||||
# Page.waitForFrame() method
|
# Page.waitForFrame() method
|
||||||
|
|
||||||
|
Waits for a frame matching the given conditions to appear.
|
||||||
|
|
||||||
#### Signature:
|
#### Signature:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class Page {
|
class Page {
|
||||||
waitForFrame(
|
waitForFrame(
|
||||||
urlOrPredicate: string | ((frame: Frame) => boolean | Promise<boolean>),
|
urlOrPredicate: string | ((frame: Frame) => Awaitable<boolean>),
|
||||||
options?: {
|
options?: WaitTimeoutOptions
|
||||||
timeout?: number;
|
|
||||||
}
|
|
||||||
): Promise<Frame>;
|
): Promise<Frame>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -20,22 +20,14 @@ class Page {
|
|||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| -------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------- |
|
| -------------- | ------------------------------------------------------------------------------------------------------------- | ------------ |
|
||||||
| urlOrPredicate | string \| ((frame: [Frame](./puppeteer.frame.md)) => boolean \| Promise<boolean>) | A URL or predicate to wait for. |
|
| urlOrPredicate | string \| ((frame: [Frame](./puppeteer.frame.md)) => [Awaitable](./puppeteer.awaitable.md)<boolean>) | |
|
||||||
| options | { timeout?: number; } | _(Optional)_ Optional waiting parameters |
|
| options | [WaitTimeoutOptions](./puppeteer.waittimeoutoptions.md) | _(Optional)_ |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
Promise<[Frame](./puppeteer.frame.md)>
|
Promise<[Frame](./puppeteer.frame.md)>
|
||||||
|
|
||||||
Promise which resolves to the matched frame.
|
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
Optional Parameter have:
|
|
||||||
|
|
||||||
- `timeout`: Maximum wait time in milliseconds, defaults to `30` seconds, pass `0` to disable the timeout. The default value can be changed by using the [Page.setDefaultTimeout()](./puppeteer.page.setdefaulttimeout.md) method.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
@ -652,17 +652,25 @@ export abstract class ElementHandle<
|
|||||||
* uses {@link Page} to hover over the center of the element.
|
* uses {@link Page} to hover over the center of the element.
|
||||||
* If the element is detached from DOM, the method throws an error.
|
* If the element is detached from DOM, the method throws an error.
|
||||||
*/
|
*/
|
||||||
abstract hover(this: ElementHandle<Element>): Promise<void>;
|
async hover(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const {x, y} = await this.clickablePoint();
|
||||||
|
await this.frame.page().mouse.move(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method scrolls element into view if needed, and then
|
* This method scrolls element into view if needed, and then
|
||||||
* uses {@link Page | Page.mouse} to click in the center of the element.
|
* uses {@link Page | Page.mouse} to click in the center of the element.
|
||||||
* If the element is detached from DOM, the method throws an error.
|
* If the element is detached from DOM, the method throws an error.
|
||||||
*/
|
*/
|
||||||
abstract click(
|
async click(
|
||||||
this: ElementHandle<Element>,
|
this: ElementHandle<Element>,
|
||||||
options?: ClickOptions
|
options: Readonly<ClickOptions> = {}
|
||||||
): Promise<void>;
|
): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const {x, y} = await this.clickablePoint(options.offset);
|
||||||
|
await this.frame.page().mouse.click(x, y, options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method creates and captures a dragevent from the element.
|
* This method creates and captures a dragevent from the element.
|
||||||
@ -804,13 +812,29 @@ export abstract class ElementHandle<
|
|||||||
* {@link Touchscreen.tap} to tap in the center of the element.
|
* {@link Touchscreen.tap} to tap in the center of the element.
|
||||||
* If the element is detached from DOM, the method throws an error.
|
* If the element is detached from DOM, the method throws an error.
|
||||||
*/
|
*/
|
||||||
abstract tap(this: ElementHandle<Element>): Promise<void>;
|
async tap(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const {x, y} = await this.clickablePoint();
|
||||||
|
await this.frame.page().touchscreen.touchStart(x, y);
|
||||||
|
await this.frame.page().touchscreen.touchEnd();
|
||||||
|
}
|
||||||
|
|
||||||
abstract touchStart(this: ElementHandle<Element>): Promise<void>;
|
async touchStart(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const {x, y} = await this.clickablePoint();
|
||||||
|
await this.frame.page().touchscreen.touchStart(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
abstract touchMove(this: ElementHandle<Element>): Promise<void>;
|
async touchMove(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
const {x, y} = await this.clickablePoint();
|
||||||
|
await this.frame.page().touchscreen.touchMove(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
abstract touchEnd(this: ElementHandle<Element>): Promise<void>;
|
async touchEnd(this: ElementHandle<Element>): Promise<void> {
|
||||||
|
await this.scrollIntoViewIfNeeded();
|
||||||
|
await this.frame.page().touchscreen.touchEnd();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | focus} on the element.
|
* Calls {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | focus} on the element.
|
||||||
@ -849,10 +873,13 @@ export abstract class ElementHandle<
|
|||||||
*
|
*
|
||||||
* @param options - Delay in milliseconds. Defaults to 0.
|
* @param options - Delay in milliseconds. Defaults to 0.
|
||||||
*/
|
*/
|
||||||
abstract type(
|
async type(
|
||||||
text: string,
|
text: string,
|
||||||
options?: Readonly<KeyboardTypeOptions>
|
options?: Readonly<KeyboardTypeOptions>
|
||||||
): Promise<void>;
|
): Promise<void> {
|
||||||
|
await this.focus();
|
||||||
|
await this.frame.page().keyboard.type(text, options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focuses the element, and then uses {@link Keyboard.down} and {@link Keyboard.up}.
|
* Focuses the element, and then uses {@link Keyboard.down} and {@link Keyboard.up}.
|
||||||
@ -868,26 +895,29 @@ export abstract class ElementHandle<
|
|||||||
* @param key - Name of key to press, such as `ArrowLeft`.
|
* @param key - Name of key to press, such as `ArrowLeft`.
|
||||||
* See {@link KeyInput} for a list of all key names.
|
* See {@link KeyInput} for a list of all key names.
|
||||||
*/
|
*/
|
||||||
abstract press(
|
async press(
|
||||||
key: KeyInput,
|
key: KeyInput,
|
||||||
options?: Readonly<KeyPressOptions>
|
options?: Readonly<KeyPressOptions>
|
||||||
): Promise<void>;
|
): Promise<void> {
|
||||||
|
await this.focus();
|
||||||
|
await this.frame.page().keyboard.press(key, options);
|
||||||
|
}
|
||||||
|
|
||||||
async #clickableBox(): Promise<BoundingBox | null> {
|
async #clickableBox(): Promise<BoundingBox | null> {
|
||||||
const adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
|
const adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
|
||||||
const rects = await adoptedThis.evaluate(element => {
|
const boxes = await adoptedThis.evaluate(element => {
|
||||||
if (!(element instanceof Element)) {
|
if (!(element instanceof Element)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return [...element.getClientRects()].map(rect => {
|
return [...element.getClientRects()].map(rect => {
|
||||||
return rect.toJSON();
|
return {x: rect.x, y: rect.y, width: rect.width, height: rect.height};
|
||||||
}) as DOMRect[];
|
});
|
||||||
});
|
});
|
||||||
void adoptedThis.dispose().catch(debugError);
|
void adoptedThis.dispose().catch(debugError);
|
||||||
if (!rects?.length) {
|
if (!boxes?.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
await this.#intersectBoundingBoxesWithFrame(rects);
|
await this.#intersectBoundingBoxesWithFrame(boxes);
|
||||||
let frame: Frame | null | undefined = this.frame;
|
let frame: Frame | null | undefined = this.frame;
|
||||||
let element: HandleFor<HTMLIFrameElement> | null | undefined;
|
let element: HandleFor<HTMLIFrameElement> | null | undefined;
|
||||||
while ((element = await frame?.frameElement())) {
|
while ((element = await frame?.frameElement())) {
|
||||||
@ -914,27 +944,27 @@ export abstract class ElementHandle<
|
|||||||
if (!parentBox) {
|
if (!parentBox) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for (const box of rects) {
|
for (const box of boxes) {
|
||||||
box.x += parentBox.left;
|
box.x += parentBox.left;
|
||||||
box.y += parentBox.top;
|
box.y += parentBox.top;
|
||||||
}
|
}
|
||||||
await element.#intersectBoundingBoxesWithFrame(rects);
|
await element.#intersectBoundingBoxesWithFrame(boxes);
|
||||||
frame = frame?.parentFrame();
|
frame = frame?.parentFrame();
|
||||||
} finally {
|
} finally {
|
||||||
void element.dispose().catch(debugError);
|
void element.dispose().catch(debugError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const rect = rects.find(box => {
|
const box = boxes.find(box => {
|
||||||
return box.width >= 1 && box.height >= 1;
|
return box.width >= 1 && box.height >= 1;
|
||||||
});
|
});
|
||||||
if (!rect) {
|
if (!box) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
x: rect.x,
|
x: box.x,
|
||||||
y: rect.y,
|
y: box.y,
|
||||||
height: rect.height,
|
height: box.height,
|
||||||
width: rect.width,
|
width: box.width,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -967,7 +997,7 @@ export abstract class ElementHandle<
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const rect = element.getBoundingClientRect();
|
const rect = element.getBoundingClientRect();
|
||||||
return rect.toJSON() as DOMRect;
|
return {x: rect.x, y: rect.y, width: rect.width, height: rect.height};
|
||||||
});
|
});
|
||||||
void adoptedThis.dispose().catch(debugError);
|
void adoptedThis.dispose().catch(debugError);
|
||||||
if (!box) {
|
if (!box) {
|
||||||
@ -977,11 +1007,9 @@ export abstract class ElementHandle<
|
|||||||
if (!offset) {
|
if (!offset) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
box.x += offset.x;
|
|
||||||
box.y += offset.y;
|
|
||||||
return {
|
return {
|
||||||
x: box.x,
|
x: box.x + offset.x,
|
||||||
y: box.y,
|
y: box.y + offset.y,
|
||||||
height: box.height,
|
height: box.height,
|
||||||
width: box.width,
|
width: box.width,
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,18 @@ import type {Readable} from 'stream';
|
|||||||
|
|
||||||
import {Protocol} from 'devtools-protocol';
|
import {Protocol} from 'devtools-protocol';
|
||||||
|
|
||||||
|
import {
|
||||||
|
filterAsync,
|
||||||
|
first,
|
||||||
|
firstValueFrom,
|
||||||
|
from,
|
||||||
|
fromEvent,
|
||||||
|
map,
|
||||||
|
merge,
|
||||||
|
Observable,
|
||||||
|
raceWith,
|
||||||
|
timer,
|
||||||
|
} from '../../third_party/rxjs/rxjs.js';
|
||||||
import type {HTTPRequest} from '../api/HTTPRequest.js';
|
import type {HTTPRequest} from '../api/HTTPRequest.js';
|
||||||
import type {HTTPResponse} from '../api/HTTPResponse.js';
|
import type {HTTPResponse} from '../api/HTTPResponse.js';
|
||||||
import type {Accessibility} from '../common/Accessibility.js';
|
import type {Accessibility} from '../common/Accessibility.js';
|
||||||
@ -26,7 +38,7 @@ import type {ConsoleMessage} from '../common/ConsoleMessage.js';
|
|||||||
import type {Coverage} from '../common/Coverage.js';
|
import type {Coverage} from '../common/Coverage.js';
|
||||||
import {Device} from '../common/Device.js';
|
import {Device} from '../common/Device.js';
|
||||||
import {DeviceRequestPrompt} from '../common/DeviceRequestPrompt.js';
|
import {DeviceRequestPrompt} from '../common/DeviceRequestPrompt.js';
|
||||||
import {TargetCloseError} from '../common/Errors.js';
|
import {TargetCloseError, TimeoutError} from '../common/Errors.js';
|
||||||
import {EventEmitter, Handler} from '../common/EventEmitter.js';
|
import {EventEmitter, Handler} from '../common/EventEmitter.js';
|
||||||
import type {FileChooser} from '../common/FileChooser.js';
|
import type {FileChooser} from '../common/FileChooser.js';
|
||||||
import type {WaitForSelectorOptions} from '../common/IsolatedWorld.js';
|
import type {WaitForSelectorOptions} from '../common/IsolatedWorld.js';
|
||||||
@ -1745,9 +1757,8 @@ export class Page extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param urlOrPredicate - A URL or predicate to wait for.
|
* Waits for a frame matching the given conditions to appear.
|
||||||
* @param options - Optional waiting parameters
|
*
|
||||||
* @returns Promise which resolves to the matched frame.
|
|
||||||
* @example
|
* @example
|
||||||
*
|
*
|
||||||
* ```ts
|
* ```ts
|
||||||
@ -1755,20 +1766,41 @@ export class Page extends EventEmitter {
|
|||||||
* return frame.name() === 'Test';
|
* return frame.name() === 'Test';
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Optional Parameter have:
|
|
||||||
*
|
|
||||||
* - `timeout`: Maximum wait time in milliseconds, defaults to `30` seconds,
|
|
||||||
* pass `0` to disable the timeout. The default value can be changed by using
|
|
||||||
* the {@link Page.setDefaultTimeout} method.
|
|
||||||
*/
|
*/
|
||||||
async waitForFrame(
|
async waitForFrame(
|
||||||
urlOrPredicate: string | ((frame: Frame) => boolean | Promise<boolean>),
|
urlOrPredicate: string | ((frame: Frame) => Awaitable<boolean>),
|
||||||
options?: {timeout?: number}
|
options: WaitTimeoutOptions = {}
|
||||||
): Promise<Frame>;
|
): Promise<Frame> {
|
||||||
async waitForFrame(): Promise<Frame> {
|
const {timeout: ms = this.getDefaultTimeout()} = options;
|
||||||
throw new Error('Not implemented');
|
|
||||||
|
if (isString(urlOrPredicate)) {
|
||||||
|
urlOrPredicate = (frame: Frame) => {
|
||||||
|
return urlOrPredicate === frame.url();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstValueFrom(
|
||||||
|
merge(
|
||||||
|
fromEvent(this, PageEmittedEvents.FrameAttached) as Observable<Frame>,
|
||||||
|
fromEvent(this, PageEmittedEvents.FrameNavigated) as Observable<Frame>,
|
||||||
|
from(this.frames())
|
||||||
|
).pipe(
|
||||||
|
filterAsync(urlOrPredicate),
|
||||||
|
first(),
|
||||||
|
raceWith(
|
||||||
|
timer(ms === 0 ? Infinity : ms).pipe(
|
||||||
|
map(() => {
|
||||||
|
throw new TimeoutError(`Timed out after waiting ${ms}ms`);
|
||||||
|
})
|
||||||
|
),
|
||||||
|
fromEvent(this, PageEmittedEvents.Close).pipe(
|
||||||
|
map(() => {
|
||||||
|
throw new TargetCloseError('Page closed.');
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,13 +16,7 @@
|
|||||||
|
|
||||||
import {Protocol} from 'devtools-protocol';
|
import {Protocol} from 'devtools-protocol';
|
||||||
|
|
||||||
import {
|
import {AutofillData, ElementHandle, Point} from '../api/ElementHandle.js';
|
||||||
AutofillData,
|
|
||||||
ClickOptions,
|
|
||||||
ElementHandle,
|
|
||||||
Point,
|
|
||||||
} from '../api/ElementHandle.js';
|
|
||||||
import {KeyboardTypeOptions, KeyPressOptions} from '../api/Input.js';
|
|
||||||
import {Page, ScreenshotOptions} from '../api/Page.js';
|
import {Page, ScreenshotOptions} from '../api/Page.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
|
|
||||||
@ -33,7 +27,6 @@ import {FrameManager} from './FrameManager.js';
|
|||||||
import {WaitForSelectorOptions} from './IsolatedWorld.js';
|
import {WaitForSelectorOptions} from './IsolatedWorld.js';
|
||||||
import {CDPJSHandle} from './JSHandle.js';
|
import {CDPJSHandle} from './JSHandle.js';
|
||||||
import {NodeFor} from './types.js';
|
import {NodeFor} from './types.js';
|
||||||
import {KeyInput} from './USKeyboardLayout.js';
|
|
||||||
import {debugError} from './util.js';
|
import {debugError} from './util.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,31 +134,6 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method scrolls element into view if needed, and then
|
|
||||||
* uses {@link Page.mouse} to hover over the center of the element.
|
|
||||||
* If the element is detached from DOM, the method throws an error.
|
|
||||||
*/
|
|
||||||
override async hover(this: CDPElementHandle<Element>): Promise<void> {
|
|
||||||
await this.scrollIntoViewIfNeeded();
|
|
||||||
const {x, y} = await this.clickablePoint();
|
|
||||||
await this.#page.mouse.move(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method scrolls element into view if needed, and then
|
|
||||||
* uses {@link Page.mouse} to click in the center of the element.
|
|
||||||
* If the element is detached from DOM, the method throws an error.
|
|
||||||
*/
|
|
||||||
override async click(
|
|
||||||
this: CDPElementHandle<Element>,
|
|
||||||
options: Readonly<ClickOptions> = {}
|
|
||||||
): Promise<void> {
|
|
||||||
await this.scrollIntoViewIfNeeded();
|
|
||||||
const {x, y} = await this.clickablePoint(options.offset);
|
|
||||||
await this.#page.mouse.click(x, y, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method creates and captures a dragevent from the element.
|
* This method creates and captures a dragevent from the element.
|
||||||
*/
|
*/
|
||||||
@ -281,46 +249,6 @@ export class CDPElementHandle<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override async tap(this: CDPElementHandle<Element>): Promise<void> {
|
|
||||||
await this.scrollIntoViewIfNeeded();
|
|
||||||
const {x, y} = await this.clickablePoint();
|
|
||||||
await this.#page.touchscreen.touchStart(x, y);
|
|
||||||
await this.#page.touchscreen.touchEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
override async touchStart(this: CDPElementHandle<Element>): Promise<void> {
|
|
||||||
await this.scrollIntoViewIfNeeded();
|
|
||||||
const {x, y} = await this.clickablePoint();
|
|
||||||
await this.#page.touchscreen.touchStart(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async touchMove(this: CDPElementHandle<Element>): Promise<void> {
|
|
||||||
await this.scrollIntoViewIfNeeded();
|
|
||||||
const {x, y} = await this.clickablePoint();
|
|
||||||
await this.#page.touchscreen.touchMove(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async touchEnd(this: CDPElementHandle<Element>): Promise<void> {
|
|
||||||
await this.scrollIntoViewIfNeeded();
|
|
||||||
await this.#page.touchscreen.touchEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
override async type(
|
|
||||||
text: string,
|
|
||||||
options?: Readonly<KeyboardTypeOptions>
|
|
||||||
): Promise<void> {
|
|
||||||
await this.focus();
|
|
||||||
await this.#page.keyboard.type(text, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async press(
|
|
||||||
key: KeyInput,
|
|
||||||
options?: Readonly<KeyPressOptions>
|
|
||||||
): Promise<void> {
|
|
||||||
await this.focus();
|
|
||||||
await this.#page.keyboard.press(key, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async screenshot(
|
override async screenshot(
|
||||||
this: CDPElementHandle<Element>,
|
this: CDPElementHandle<Element>,
|
||||||
options: ScreenshotOptions = {}
|
options: ScreenshotOptions = {}
|
||||||
|
@ -997,53 +997,6 @@ export class CDPPage extends Page {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async waitForFrame(
|
|
||||||
urlOrPredicate: string | ((frame: Frame) => boolean | Promise<boolean>),
|
|
||||||
options: {timeout?: number} = {}
|
|
||||||
): Promise<Frame> {
|
|
||||||
const {timeout = this.#timeoutSettings.timeout()} = options;
|
|
||||||
|
|
||||||
let predicate: (frame: Frame) => Promise<boolean>;
|
|
||||||
if (isString(urlOrPredicate)) {
|
|
||||||
predicate = (frame: Frame) => {
|
|
||||||
return Promise.resolve(urlOrPredicate === frame.url());
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
predicate = (frame: Frame) => {
|
|
||||||
const value = urlOrPredicate(frame);
|
|
||||||
if (typeof value === 'boolean') {
|
|
||||||
return Promise.resolve(value);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const eventRace: Promise<Frame> = Deferred.race([
|
|
||||||
waitForEvent(
|
|
||||||
this.#frameManager,
|
|
||||||
FrameManagerEmittedEvents.FrameAttached,
|
|
||||||
predicate,
|
|
||||||
timeout,
|
|
||||||
this.#sessionCloseDeferred.valueOrThrow()
|
|
||||||
),
|
|
||||||
waitForEvent(
|
|
||||||
this.#frameManager,
|
|
||||||
FrameManagerEmittedEvents.FrameNavigated,
|
|
||||||
predicate,
|
|
||||||
timeout,
|
|
||||||
this.#sessionCloseDeferred.valueOrThrow()
|
|
||||||
),
|
|
||||||
...this.frames().map(async frame => {
|
|
||||||
if (await predicate(frame)) {
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
return await eventRace;
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return eventRace;
|
|
||||||
}
|
|
||||||
|
|
||||||
override async goBack(
|
override async goBack(
|
||||||
options: WaitForOptions = {}
|
options: WaitForOptions = {}
|
||||||
): Promise<HTTPResponse | null> {
|
): Promise<HTTPResponse | null> {
|
||||||
|
@ -19,11 +19,7 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
|||||||
import {
|
import {
|
||||||
AutofillData,
|
AutofillData,
|
||||||
ElementHandle as BaseElementHandle,
|
ElementHandle as BaseElementHandle,
|
||||||
ClickOptions,
|
|
||||||
} from '../../api/ElementHandle.js';
|
} from '../../api/ElementHandle.js';
|
||||||
import {KeyboardTypeOptions, KeyPressOptions} from '../../api/Input.js';
|
|
||||||
import {assert} from '../../util/assert.js';
|
|
||||||
import {KeyInput} from '../USKeyboardLayout.js';
|
|
||||||
import {debugError} from '../util.js';
|
import {debugError} from '../util.js';
|
||||||
|
|
||||||
import {Frame} from './Frame.js';
|
import {Frame} from './Frame.js';
|
||||||
@ -105,96 +101,4 @@ export class ElementHandle<
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ///////////////////
|
|
||||||
// // 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.Script.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.Script.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.Script.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.Script.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.Script.SharedReference,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
override async touchEnd(this: ElementHandle<Element>): Promise<void> {
|
|
||||||
await this.scrollIntoViewIfNeeded();
|
|
||||||
await this.#frame.page().touchscreen.touchEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
override async type(
|
|
||||||
text: string,
|
|
||||||
options?: Readonly<KeyboardTypeOptions>
|
|
||||||
): Promise<void> {
|
|
||||||
await this.focus();
|
|
||||||
await this.#frame.page().keyboard.type(text, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async press(
|
|
||||||
key: KeyInput,
|
|
||||||
options?: Readonly<KeyPressOptions>
|
|
||||||
): Promise<void> {
|
|
||||||
await this.focus();
|
|
||||||
await this.#frame.page().keyboard.press(key, options);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -483,9 +483,10 @@ export class Mouse extends BaseMouse {
|
|||||||
y: number,
|
y: number,
|
||||||
options: Readonly<BidiMouseMoveOptions> = {}
|
options: Readonly<BidiMouseMoveOptions> = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
// https://w3c.github.io/webdriver-bidi/#command-input-performActions:~:text=input.PointerMoveAction%20%3D%20%7B%0A%20%20type%3A%20%22pointerMove%22%2C%0A%20%20x%3A%20js%2Dint%2C
|
||||||
this.#lastMovePoint = {
|
this.#lastMovePoint = {
|
||||||
x,
|
x: Math.round(x),
|
||||||
y,
|
y: Math.round(y),
|
||||||
};
|
};
|
||||||
await this.#context.connection.send('input.performActions', {
|
await this.#context.connection.send('input.performActions', {
|
||||||
context: this.#context.id,
|
context: this.#context.id,
|
||||||
@ -496,8 +497,7 @@ export class Mouse extends BaseMouse {
|
|||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: ActionType.PointerMove,
|
type: ActionType.PointerMove,
|
||||||
x,
|
...this.#lastMovePoint,
|
||||||
y,
|
|
||||||
duration: (options.steps ?? 0) * 50,
|
duration: (options.steps ?? 0) * 50,
|
||||||
origin: options.origin,
|
origin: options.origin,
|
||||||
},
|
},
|
||||||
@ -551,8 +551,8 @@ export class Mouse extends BaseMouse {
|
|||||||
const actions: Bidi.Input.PointerSourceAction[] = [
|
const actions: Bidi.Input.PointerSourceAction[] = [
|
||||||
{
|
{
|
||||||
type: ActionType.PointerMove,
|
type: ActionType.PointerMove,
|
||||||
x,
|
x: Math.round(x),
|
||||||
y,
|
y: Math.round(y),
|
||||||
origin: options.origin,
|
origin: options.origin,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -653,8 +653,8 @@ export class Touchscreen extends BaseTouchscreen {
|
|||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: ActionType.PointerMove,
|
type: ActionType.PointerMove,
|
||||||
x,
|
x: Math.round(x),
|
||||||
y,
|
y: Math.round(y),
|
||||||
origin: options.origin,
|
origin: options.origin,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -684,8 +684,8 @@ export class Touchscreen extends BaseTouchscreen {
|
|||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: ActionType.PointerMove,
|
type: ActionType.PointerMove,
|
||||||
x,
|
x: Math.round(x),
|
||||||
y,
|
y: Math.round(y),
|
||||||
origin: options.origin,
|
origin: options.origin,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -32,6 +32,7 @@ import {CDPElementHandle} from './ElementHandle.js';
|
|||||||
import type {CommonEventEmitter} from './EventEmitter.js';
|
import type {CommonEventEmitter} from './EventEmitter.js';
|
||||||
import type {ExecutionContext} from './ExecutionContext.js';
|
import type {ExecutionContext} from './ExecutionContext.js';
|
||||||
import {CDPJSHandle} from './JSHandle.js';
|
import {CDPJSHandle} from './JSHandle.js';
|
||||||
|
import {Awaitable} from './types.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -381,7 +382,7 @@ export const isDate = (obj: unknown): obj is Date => {
|
|||||||
export async function waitForEvent<T>(
|
export async function waitForEvent<T>(
|
||||||
emitter: CommonEventEmitter,
|
emitter: CommonEventEmitter,
|
||||||
eventName: string | symbol,
|
eventName: string | symbol,
|
||||||
predicate: (event: T) => Promise<boolean> | boolean,
|
predicate: (event: T) => Awaitable<boolean>,
|
||||||
timeout: number,
|
timeout: number,
|
||||||
abortPromise: Promise<Error> | Deferred<Error>
|
abortPromise: Promise<Error> | Deferred<Error>
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
|
17
packages/puppeteer-core/third_party/rxjs/rxjs.ts
vendored
17
packages/puppeteer-core/third_party/rxjs/rxjs.ts
vendored
@ -39,3 +39,20 @@ export {
|
|||||||
pipe,
|
pipe,
|
||||||
Observable,
|
Observable,
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
|
|
||||||
|
import {mergeMap, from, filter, map, type Observable} from 'rxjs';
|
||||||
|
|
||||||
|
export function filterAsync<T>(
|
||||||
|
predicate: (value: T) => boolean | PromiseLike<boolean>
|
||||||
|
) {
|
||||||
|
return mergeMap<T, Observable<T>>(value => {
|
||||||
|
return from(Promise.resolve(predicate(value))).pipe(
|
||||||
|
filter(isMatch => {
|
||||||
|
return isMatch;
|
||||||
|
}),
|
||||||
|
map(() => {
|
||||||
|
return value;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -653,12 +653,30 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should throw for <br> elements",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should throw for detached nodes",
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should throw for detached nodes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should throw for hidden nodes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should throw for recursively hidden nodes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should work",
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should work",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -671,6 +689,12 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should not work if the click box is not visible",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should work",
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should work",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -1049,12 +1073,6 @@
|
|||||||
"parameters": ["firefox"],
|
"parameters": ["firefox"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[locator.spec] Locator Locator.click should work with a OOPIF",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[mouse.spec] Mouse should click the document",
|
"testIdPattern": "[mouse.spec] Mouse should click the document",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -1919,6 +1937,18 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click the button inside an iframe",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[click.spec] Page.click should click the button with deviceScaleFactor set",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe",
|
"testIdPattern": "[click.spec] Page.click should click the button with fixed position inside an iframe",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -2099,18 +2129,6 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should throw for hidden nodes",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
|
||||||
"expectations": ["PASS"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.click should throw for recursively hidden nodes",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
|
||||||
"expectations": ["PASS"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should work for iframes",
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should work for iframes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -2147,12 +2165,6 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.clickablePoint should not work if the click box is not visible",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["PASS"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should throw in case of bad argument",
|
"testIdPattern": "[emulation.spec] Emulation Page.emulateMediaFeatures should throw in case of bad argument",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -2747,6 +2759,18 @@
|
|||||||
"parameters": ["firefox", "webDriverBiDi"],
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[locator.spec] Locator Locator.click should work with a OOPIF",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[locator.spec] Locator Locator.click should work with a OOPIF",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[locator.spec] Locator Locator.race races multiple locators",
|
"testIdPattern": "[locator.spec] Locator Locator.race races multiple locators",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -3377,6 +3401,48 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[oopif.spec] OOPIF clickablePoint, boundingBox, boxModel should work for elements inside OOPIFs",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[oopif.spec] OOPIF should provide access to elements",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[oopif.spec] OOPIF should support evaluating in oop iframes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[oopif.spec] OOPIF should support frames within OOP frames",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[oopif.spec] OOPIF should support frames within OOP iframes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[oopif.spec] OOPIF should track navigations within OOP iframes",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[oopif.spec] OOPIF should treat OOP iframes and normal iframes the same",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[oopif.spec] OOPIF-debug OOPIF should support wait for navigation for transitions from local to OOPIF",
|
"testIdPattern": "[oopif.spec] OOPIF-debug OOPIF should support wait for navigation for transitions from local to OOPIF",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
Loading…
Reference in New Issue
Block a user