mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: implement common functions for BiDi (#10345)
This commit is contained in:
parent
e3e68a99d2
commit
a31231ef54
@ -29,7 +29,7 @@ import {
|
|||||||
NodeFor,
|
NodeFor,
|
||||||
} from '../common/types.js';
|
} from '../common/types.js';
|
||||||
import {KeyInput} from '../common/USKeyboardLayout.js';
|
import {KeyInput} from '../common/USKeyboardLayout.js';
|
||||||
import {withSourcePuppeteerURLIfNone} from '../common/util.js';
|
import {isString, withSourcePuppeteerURLIfNone} from '../common/util.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
|
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
|
||||||
|
|
||||||
@ -428,9 +428,11 @@ export class ElementHandle<
|
|||||||
* If there are no such elements, the method will resolve to an empty array.
|
* If there are no such elements, the method will resolve to an empty array.
|
||||||
* @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate}
|
* @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate}
|
||||||
*/
|
*/
|
||||||
async $x(expression: string): Promise<Array<ElementHandle<Node>>>;
|
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
||||||
async $x(): Promise<Array<ElementHandle<Node>>> {
|
if (expression.startsWith('//')) {
|
||||||
throw new Error('Not implemented');
|
expression = `.${expression}`;
|
||||||
|
}
|
||||||
|
return this.$$(`xpath/${expression}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -472,12 +474,15 @@ export class ElementHandle<
|
|||||||
*/
|
*/
|
||||||
async waitForSelector<Selector extends string>(
|
async waitForSelector<Selector extends string>(
|
||||||
selector: Selector,
|
selector: Selector,
|
||||||
options?: WaitForSelectorOptions
|
options: WaitForSelectorOptions = {}
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null>;
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
async waitForSelector<Selector extends string>(): Promise<ElementHandle<
|
const {updatedSelector, QueryHandler} =
|
||||||
NodeFor<Selector>
|
getQueryHandlerAndSelector(selector);
|
||||||
> | null> {
|
return (await QueryHandler.waitFor(
|
||||||
throw new Error('Not implemented');
|
this,
|
||||||
|
updatedSelector,
|
||||||
|
options
|
||||||
|
)) as ElementHandle<NodeFor<Selector>> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -591,11 +596,14 @@ export class ElementHandle<
|
|||||||
*/
|
*/
|
||||||
async toElement<
|
async toElement<
|
||||||
K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap
|
K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap
|
||||||
>(tagName: K): Promise<HandleFor<ElementFor<K>>>;
|
>(tagName: K): Promise<HandleFor<ElementFor<K>>> {
|
||||||
async toElement<
|
const isMatchingTagName = await this.evaluate((node, tagName) => {
|
||||||
K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap
|
return node.nodeName === tagName.toUpperCase();
|
||||||
>(): Promise<HandleFor<ElementFor<K>>> {
|
}, tagName);
|
||||||
throw new Error('Not implemented');
|
if (!isMatchingTagName) {
|
||||||
|
throw new Error(`Element is not a(n) \`${tagName}\` element`);
|
||||||
|
}
|
||||||
|
return this as unknown as HandleFor<ElementFor<K>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -708,9 +716,48 @@ export class ElementHandle<
|
|||||||
* `multiple` attribute, all values are considered, otherwise only the first
|
* `multiple` attribute, all values are considered, otherwise only the first
|
||||||
* one is taken into account.
|
* one is taken into account.
|
||||||
*/
|
*/
|
||||||
async select(...values: string[]): Promise<string[]>;
|
async select(...values: string[]): Promise<string[]> {
|
||||||
async select(): Promise<string[]> {
|
for (const value of values) {
|
||||||
throw new Error('Not implemented');
|
assert(
|
||||||
|
isString(value),
|
||||||
|
'Values must be strings. Found value "' +
|
||||||
|
value +
|
||||||
|
'" of type "' +
|
||||||
|
typeof value +
|
||||||
|
'"'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.evaluate((element, vals): string[] => {
|
||||||
|
const values = new Set(vals);
|
||||||
|
if (!(element instanceof HTMLSelectElement)) {
|
||||||
|
throw new Error('Element is not a <select> element.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedValues = new Set<string>();
|
||||||
|
if (!element.multiple) {
|
||||||
|
for (const option of element.options) {
|
||||||
|
option.selected = false;
|
||||||
|
}
|
||||||
|
for (const option of element.options) {
|
||||||
|
if (values.has(option.value)) {
|
||||||
|
option.selected = true;
|
||||||
|
selectedValues.add(option.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const option of element.options) {
|
||||||
|
option.selected = values.has(option.value);
|
||||||
|
if (option.selected) {
|
||||||
|
selectedValues.add(option.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
element.dispatchEvent(new Event('input', {bubbles: true}));
|
||||||
|
element.dispatchEvent(new Event('change', {bubbles: true}));
|
||||||
|
return [...selectedValues.values()];
|
||||||
|
}, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -757,7 +804,12 @@ export class ElementHandle<
|
|||||||
* 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.
|
||||||
*/
|
*/
|
||||||
async focus(): Promise<void> {
|
async focus(): Promise<void> {
|
||||||
throw new Error('Not implemented');
|
await this.evaluate(element => {
|
||||||
|
if (!(element instanceof HTMLElement)) {
|
||||||
|
throw new Error('Cannot focus non-HTMLElement');
|
||||||
|
}
|
||||||
|
return element.focus();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -908,7 +960,14 @@ export class ElementHandle<
|
|||||||
* or by calling element.scrollIntoView.
|
* or by calling element.scrollIntoView.
|
||||||
*/
|
*/
|
||||||
async scrollIntoView(this: ElementHandle<Element>): Promise<void> {
|
async scrollIntoView(this: ElementHandle<Element>): Promise<void> {
|
||||||
throw new Error('Not implemented');
|
await this.assertConnectedElement();
|
||||||
|
await this.evaluate(async (element): Promise<void> => {
|
||||||
|
element.scrollIntoView({
|
||||||
|
block: 'center',
|
||||||
|
inline: 'center',
|
||||||
|
behavior: 'instant',
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1125,9 +1125,8 @@ export class Page extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @param expression - Expression to evaluate
|
* @param expression - Expression to evaluate
|
||||||
*/
|
*/
|
||||||
async $x(expression: string): Promise<Array<ElementHandle<Node>>>;
|
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
||||||
async $x(): Promise<Array<ElementHandle<Node>>> {
|
return this.mainFrame().$x(expression);
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2642,12 +2641,9 @@ export class Page extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
async waitForSelector<Selector extends string>(
|
async waitForSelector<Selector extends string>(
|
||||||
selector: Selector,
|
selector: Selector,
|
||||||
options?: WaitForSelectorOptions
|
options: WaitForSelectorOptions = {}
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null>;
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
async waitForSelector<Selector extends string>(): Promise<ElementHandle<
|
return await this.mainFrame().waitForSelector(selector, options);
|
||||||
NodeFor<Selector>
|
|
||||||
> | null> {
|
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,7 +107,10 @@ export interface SnapshotOptions {
|
|||||||
root?: ElementHandle<Node>;
|
root?: ElementHandle<Node>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DataProvider {
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export interface DataProvider {
|
||||||
getFullAXTree(): Promise<Protocol.Accessibility.GetFullAXTreeResponse>;
|
getFullAXTree(): Promise<Protocol.Accessibility.GetFullAXTreeResponse>;
|
||||||
describeNode(id: string): Promise<Protocol.DOM.DescribeNodeResponse>;
|
describeNode(id: string): Promise<Protocol.DOM.DescribeNodeResponse>;
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,14 @@ import {CDPSession} from './Connection.js';
|
|||||||
import {ExecutionContext} from './ExecutionContext.js';
|
import {ExecutionContext} from './ExecutionContext.js';
|
||||||
import {Frame} from './Frame.js';
|
import {Frame} from './Frame.js';
|
||||||
import {FrameManager} from './FrameManager.js';
|
import {FrameManager} from './FrameManager.js';
|
||||||
import {getQueryHandlerAndSelector} from './GetQueryHandler.js';
|
|
||||||
import {WaitForSelectorOptions} from './IsolatedWorld.js';
|
import {WaitForSelectorOptions} from './IsolatedWorld.js';
|
||||||
import {PUPPETEER_WORLD} from './IsolatedWorlds.js';
|
import {PUPPETEER_WORLD} from './IsolatedWorlds.js';
|
||||||
import {CDPJSHandle} from './JSHandle.js';
|
import {CDPJSHandle} from './JSHandle.js';
|
||||||
import {LazyArg} from './LazyArg.js';
|
import {LazyArg} from './LazyArg.js';
|
||||||
import {CDPPage} from './Page.js';
|
import {CDPPage} from './Page.js';
|
||||||
import {ElementFor, HandleFor, NodeFor} from './types.js';
|
import {NodeFor} from './types.js';
|
||||||
import {KeyInput} from './USKeyboardLayout.js';
|
import {KeyInput} from './USKeyboardLayout.js';
|
||||||
import {debugError, isString} from './util.js';
|
import {debugError} from './util.js';
|
||||||
|
|
||||||
const applyOffsetsToQuad = (
|
const applyOffsetsToQuad = (
|
||||||
quad: Point[],
|
quad: Point[],
|
||||||
@ -120,26 +119,13 @@ export class CDPElementHandle<
|
|||||||
>;
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
override async $x(
|
|
||||||
expression: string
|
|
||||||
): Promise<Array<CDPElementHandle<Node>>> {
|
|
||||||
if (expression.startsWith('//')) {
|
|
||||||
expression = `.${expression}`;
|
|
||||||
}
|
|
||||||
return this.$$(`xpath/${expression}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async waitForSelector<Selector extends string>(
|
override async waitForSelector<Selector extends string>(
|
||||||
selector: Selector,
|
selector: Selector,
|
||||||
options: WaitForSelectorOptions = {}
|
options?: WaitForSelectorOptions
|
||||||
): Promise<CDPElementHandle<NodeFor<Selector>> | null> {
|
): Promise<CDPElementHandle<NodeFor<Selector>> | null> {
|
||||||
const {updatedSelector, QueryHandler} =
|
return (await super.waitForSelector(selector, options)) as CDPElementHandle<
|
||||||
getQueryHandlerAndSelector(selector);
|
NodeFor<Selector>
|
||||||
return (await QueryHandler.waitFor(
|
> | null;
|
||||||
this,
|
|
||||||
updatedSelector,
|
|
||||||
options
|
|
||||||
)) as CDPElementHandle<NodeFor<Selector>> | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override async waitForXPath(
|
override async waitForXPath(
|
||||||
@ -182,18 +168,6 @@ export class CDPElementHandle<
|
|||||||
return this.#checkVisibility(false);
|
return this.#checkVisibility(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async toElement<
|
|
||||||
K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap
|
|
||||||
>(tagName: K): Promise<HandleFor<ElementFor<K>>> {
|
|
||||||
const isMatchingTagName = await this.evaluate((node, tagName) => {
|
|
||||||
return node.nodeName === tagName.toUpperCase();
|
|
||||||
}, tagName);
|
|
||||||
if (!isMatchingTagName) {
|
|
||||||
throw new Error(`Element is not a(n) \`${tagName}\` element`);
|
|
||||||
}
|
|
||||||
return this as unknown as HandleFor<ElementFor<K>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
override async contentFrame(): Promise<Frame | null> {
|
override async contentFrame(): Promise<Frame | null> {
|
||||||
const nodeInfo = await this.client.send('DOM.describeNode', {
|
const nodeInfo = await this.client.send('DOM.describeNode', {
|
||||||
objectId: this.id,
|
objectId: this.id,
|
||||||
@ -208,7 +182,6 @@ export class CDPElementHandle<
|
|||||||
this: CDPElementHandle<Element>
|
this: CDPElementHandle<Element>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.assertConnectedElement();
|
await this.assertConnectedElement();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.client.send('DOM.scrollIntoViewIfNeeded', {
|
await this.client.send('DOM.scrollIntoViewIfNeeded', {
|
||||||
objectId: this.id,
|
objectId: this.id,
|
||||||
@ -216,13 +189,7 @@ export class CDPElementHandle<
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
debugError(error);
|
debugError(error);
|
||||||
// Fallback to Element.scrollIntoView if DOM.scrollIntoViewIfNeeded is not supported
|
// Fallback to Element.scrollIntoView if DOM.scrollIntoViewIfNeeded is not supported
|
||||||
await this.evaluate(async (element): Promise<void> => {
|
await super.scrollIntoView();
|
||||||
element.scrollIntoView({
|
|
||||||
block: 'center',
|
|
||||||
inline: 'center',
|
|
||||||
behavior: 'instant',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,50 +419,6 @@ export class CDPElementHandle<
|
|||||||
await this.#page.mouse.dragAndDrop(startPoint, targetPoint, options);
|
await this.#page.mouse.dragAndDrop(startPoint, targetPoint, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async select(...values: string[]): Promise<string[]> {
|
|
||||||
for (const value of values) {
|
|
||||||
assert(
|
|
||||||
isString(value),
|
|
||||||
'Values must be strings. Found value "' +
|
|
||||||
value +
|
|
||||||
'" of type "' +
|
|
||||||
typeof value +
|
|
||||||
'"'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.evaluate((element, vals): string[] => {
|
|
||||||
const values = new Set(vals);
|
|
||||||
if (!(element instanceof HTMLSelectElement)) {
|
|
||||||
throw new Error('Element is not a <select> element.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedValues = new Set<string>();
|
|
||||||
if (!element.multiple) {
|
|
||||||
for (const option of element.options) {
|
|
||||||
option.selected = false;
|
|
||||||
}
|
|
||||||
for (const option of element.options) {
|
|
||||||
if (values.has(option.value)) {
|
|
||||||
option.selected = true;
|
|
||||||
selectedValues.add(option.value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const option of element.options) {
|
|
||||||
option.selected = values.has(option.value);
|
|
||||||
if (option.selected) {
|
|
||||||
selectedValues.add(option.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
element.dispatchEvent(new Event('input', {bubbles: true}));
|
|
||||||
element.dispatchEvent(new Event('change', {bubbles: true}));
|
|
||||||
return [...selectedValues.values()];
|
|
||||||
}, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async uploadFile(
|
override async uploadFile(
|
||||||
this: CDPElementHandle<HTMLInputElement>,
|
this: CDPElementHandle<HTMLInputElement>,
|
||||||
...filePaths: string[]
|
...filePaths: string[]
|
||||||
@ -577,15 +500,6 @@ export class CDPElementHandle<
|
|||||||
await this.#page.touchscreen.touchEnd();
|
await this.#page.touchscreen.touchEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
override async focus(): Promise<void> {
|
|
||||||
await this.evaluate(element => {
|
|
||||||
if (!(element instanceof HTMLElement)) {
|
|
||||||
throw new Error('Cannot focus non-HTMLElement');
|
|
||||||
}
|
|
||||||
return element.focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
override async type(text: string, options?: {delay: number}): Promise<void> {
|
override async type(text: string, options?: {delay: number}): Promise<void> {
|
||||||
await this.focus();
|
await this.focus();
|
||||||
await this.#page.keyboard.type(text, options);
|
await this.#page.keyboard.type(text, options);
|
||||||
|
@ -531,12 +531,6 @@ export class Frame extends BaseFrame {
|
|||||||
return this.worlds[PUPPETEER_WORLD].type(selector, text, options);
|
return this.worlds[PUPPETEER_WORLD].type(selector, text, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
override waitForTimeout(milliseconds: number): Promise<void> {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(resolve, milliseconds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
override async title(): Promise<string> {
|
override async title(): Promise<string> {
|
||||||
return this.worlds[PUPPETEER_WORLD].title();
|
return this.worlds[PUPPETEER_WORLD].title();
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ import {TargetManagerEmittedEvents} from './TargetManager.js';
|
|||||||
import {TaskQueue} from './TaskQueue.js';
|
import {TaskQueue} from './TaskQueue.js';
|
||||||
import {TimeoutSettings} from './TimeoutSettings.js';
|
import {TimeoutSettings} from './TimeoutSettings.js';
|
||||||
import {Tracing} from './Tracing.js';
|
import {Tracing} from './Tracing.js';
|
||||||
import {BindingPayload, EvaluateFunc, HandleFor, NodeFor} from './types.js';
|
import {BindingPayload, EvaluateFunc, HandleFor} from './types.js';
|
||||||
import {
|
import {
|
||||||
createClientError,
|
createClientError,
|
||||||
createJSHandle,
|
createJSHandle,
|
||||||
@ -554,10 +554,6 @@ export class CDPPage extends Page {
|
|||||||
return createJSHandle(context, response.objects) as HandleFor<Prototype[]>;
|
return createJSHandle(context, response.objects) as HandleFor<Prototype[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
override async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
|
||||||
return this.mainFrame().$x(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async cookies(
|
override async cookies(
|
||||||
...urls: string[]
|
...urls: string[]
|
||||||
): Promise<Protocol.Network.Cookie[]> {
|
): Promise<Protocol.Network.Cookie[]> {
|
||||||
@ -1557,13 +1553,6 @@ export class CDPPage extends Page {
|
|||||||
return this.mainFrame().waitForTimeout(milliseconds);
|
return this.mainFrame().waitForTimeout(milliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async waitForSelector<Selector extends string>(
|
|
||||||
selector: Selector,
|
|
||||||
options: WaitForSelectorOptions = {}
|
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
|
||||||
return await this.mainFrame().waitForSelector(selector, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
override waitForXPath(
|
override waitForXPath(
|
||||||
xpath: string,
|
xpath: string,
|
||||||
options: WaitForSelectorOptions = {}
|
options: WaitForSelectorOptions = {}
|
||||||
|
@ -22,6 +22,7 @@ import {
|
|||||||
Browser as BrowserBase,
|
Browser as BrowserBase,
|
||||||
BrowserCloseCallback,
|
BrowserCloseCallback,
|
||||||
BrowserContextOptions,
|
BrowserContextOptions,
|
||||||
|
BrowserEmittedEvents,
|
||||||
} from '../../api/Browser.js';
|
} from '../../api/Browser.js';
|
||||||
import {BrowserContext as BrowserContextBase} from '../../api/BrowserContext.js';
|
import {BrowserContext as BrowserContextBase} from '../../api/BrowserContext.js';
|
||||||
import {Viewport} from '../PuppeteerViewport.js';
|
import {Viewport} from '../PuppeteerViewport.js';
|
||||||
@ -59,6 +60,10 @@ export class Browser extends BrowserBase {
|
|||||||
this.#closeCallback = opts.closeCallback;
|
this.#closeCallback = opts.closeCallback;
|
||||||
this.#connection = opts.connection;
|
this.#connection = opts.connection;
|
||||||
this.#defaultViewport = opts.defaultViewport;
|
this.#defaultViewport = opts.defaultViewport;
|
||||||
|
|
||||||
|
this.#process?.on('close', () => {
|
||||||
|
return this.emit(BrowserEmittedEvents.Disconnected);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get connection(): Connection {
|
get connection(): Connection {
|
||||||
|
@ -94,4 +94,8 @@ export class BrowserContext extends BrowserContextBase {
|
|||||||
override browser(): Browser {
|
override browser(): Browser {
|
||||||
return this.#browser;
|
return this.#browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override async pages(): Promise<PageBase[]> {
|
||||||
|
return [...this.#pages.values()];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,6 +177,10 @@ export class Frame extends BaseFrame {
|
|||||||
return this.sandboxes[MAIN_SANDBOX].$$eval(selector, pageFunction, ...args);
|
return this.sandboxes[MAIN_SANDBOX].$$eval(selector, pageFunction, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
||||||
|
return this.sandboxes[MAIN_SANDBOX].$x(expression);
|
||||||
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this.#context.dispose();
|
this.#context.dispose();
|
||||||
}
|
}
|
||||||
|
@ -112,4 +112,9 @@ export class Sandbox {
|
|||||||
const document = await this.document();
|
const document = await this.document();
|
||||||
return document.$$eval(selector, pageFunction, ...args);
|
return document.$$eval(selector, pageFunction, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
||||||
|
const document = await this.document();
|
||||||
|
return document.$x(expression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,18 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs Custom queries *",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs ElementHandle.isIntersectingViewport *",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] *",
|
"testIdPattern": "[evaluation.spec] *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -203,6 +215,12 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[queryselector.spec] querySelector *",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[accessibility.spec] *",
|
"testIdPattern": "[accessibility.spec] *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -257,6 +275,30 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs Custom queries should wait correctly with waitFor",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs Custom queries should wait correctly with waitForSelector",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs Custom queries should wait correctly with waitForSelector on an element",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[elementhandle.spec] ElementHandle specs Element.toElement 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"],
|
||||||
@ -372,15 +414,9 @@
|
|||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.jsonValue should not work with dates",
|
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.jsonValue should work with dates",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["cdp"],
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.toString should work for complicated objects",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -413,6 +449,12 @@
|
|||||||
"parameters": ["chrome"],
|
"parameters": ["chrome"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation \"after each\" hook for \"should work with both domcontentloaded and load\"",
|
"testIdPattern": "[navigation.spec] navigation \"after each\" hook for \"should work with both domcontentloaded and load\"",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -695,6 +737,18 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL", "PASS"]
|
"expectations": ["FAIL", "PASS"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |browserURL| option should be able to connect using browserUrl, with and without trailing slash",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests Puppeteer.launch |browserURL| option should throw when trying to connect to non-existing browser",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
|
"expectations": ["PASS"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"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"],
|
||||||
@ -1019,12 +1073,6 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.jsonValue should not work with dates",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["cdp", "firefox"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.toString should work with different subtypes",
|
"testIdPattern": "[jshandle.spec] JSHandle JSHandle.toString should work with different subtypes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -1193,6 +1241,12 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch tmp profile should be cleaned up",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["firefox", "webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch userDataDir argument with non-existent dir",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.launch userDataDir argument with non-existent dir",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
@ -467,12 +467,23 @@ describe('ElementHandle specs', function () {
|
|||||||
it('should work', async () => {
|
it('should work', async () => {
|
||||||
const {page, server} = getTestState();
|
const {page, server} = getTestState();
|
||||||
|
|
||||||
|
async function getVisibilityForButton(selector: string) {
|
||||||
|
const button = (await page.$(selector))!;
|
||||||
|
return await button.isIntersectingViewport();
|
||||||
|
}
|
||||||
|
|
||||||
await page.goto(server.PREFIX + '/offscreenbuttons.html');
|
await page.goto(server.PREFIX + '/offscreenbuttons.html');
|
||||||
|
const buttonsPromises = [];
|
||||||
|
// Firefox seems slow when using `isIntersectingViewport`
|
||||||
|
// so we do all the tasks asynchronously
|
||||||
|
for (let i = 0; i < 11; ++i) {
|
||||||
|
buttonsPromises.push(getVisibilityForButton('#btn' + i));
|
||||||
|
}
|
||||||
|
const buttonVisibility = await Promise.all(buttonsPromises);
|
||||||
for (let i = 0; i < 11; ++i) {
|
for (let i = 0; i < 11; ++i) {
|
||||||
const button = (await page.$('#btn' + i))!;
|
|
||||||
// All but last button are visible.
|
// All but last button are visible.
|
||||||
const visible = i < 10;
|
const visible = i < 10;
|
||||||
expect(await button.isIntersectingViewport()).toBe(visible);
|
expect(buttonVisibility[i]).toBe(visible);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it('should work with threshold', async () => {
|
it('should work with threshold', async () => {
|
||||||
@ -505,51 +516,69 @@ describe('ElementHandle specs', function () {
|
|||||||
const {page, server} = getTestState();
|
const {page, server} = getTestState();
|
||||||
|
|
||||||
await page.goto(server.PREFIX + '/inline-svg.html');
|
await page.goto(server.PREFIX + '/inline-svg.html');
|
||||||
const visibleCircle = await page.$('circle');
|
const [visibleCircle, visibleSvg] = await Promise.all([
|
||||||
const visibleSvg = await page.$('svg');
|
page.$('circle'),
|
||||||
expect(
|
page.$('svg'),
|
||||||
await visibleCircle!.isIntersectingViewport({
|
]);
|
||||||
threshold: 1,
|
|
||||||
})
|
|
||||||
).toBe(true);
|
|
||||||
expect(
|
|
||||||
await visibleCircle!.isIntersectingViewport({
|
|
||||||
threshold: 0,
|
|
||||||
})
|
|
||||||
).toBe(true);
|
|
||||||
expect(
|
|
||||||
await visibleSvg!.isIntersectingViewport({
|
|
||||||
threshold: 1,
|
|
||||||
})
|
|
||||||
).toBe(true);
|
|
||||||
expect(
|
|
||||||
await visibleSvg!.isIntersectingViewport({
|
|
||||||
threshold: 0,
|
|
||||||
})
|
|
||||||
).toBe(true);
|
|
||||||
|
|
||||||
const invisibleCircle = await page.$('div circle');
|
// Firefox seems slow when using `isIntersectingViewport`
|
||||||
const invisibleSvg = await page.$('div svg');
|
// so we do all the tasks asynchronously
|
||||||
expect(
|
const [
|
||||||
await invisibleCircle!.isIntersectingViewport({
|
circleThresholdOne,
|
||||||
|
circleThresholdZero,
|
||||||
|
svgThresholdOne,
|
||||||
|
svgThresholdZero,
|
||||||
|
] = await Promise.all([
|
||||||
|
visibleCircle!.isIntersectingViewport({
|
||||||
threshold: 1,
|
threshold: 1,
|
||||||
})
|
}),
|
||||||
).toBe(false);
|
visibleCircle!.isIntersectingViewport({
|
||||||
expect(
|
|
||||||
await invisibleCircle!.isIntersectingViewport({
|
|
||||||
threshold: 0,
|
threshold: 0,
|
||||||
})
|
}),
|
||||||
).toBe(false);
|
visibleSvg!.isIntersectingViewport({
|
||||||
expect(
|
|
||||||
await invisibleSvg!.isIntersectingViewport({
|
|
||||||
threshold: 1,
|
threshold: 1,
|
||||||
})
|
}),
|
||||||
).toBe(false);
|
visibleSvg!.isIntersectingViewport({
|
||||||
expect(
|
|
||||||
await invisibleSvg!.isIntersectingViewport({
|
|
||||||
threshold: 0,
|
threshold: 0,
|
||||||
})
|
}),
|
||||||
).toBe(false);
|
]);
|
||||||
|
|
||||||
|
expect(circleThresholdOne).toBe(true);
|
||||||
|
expect(circleThresholdZero).toBe(true);
|
||||||
|
expect(svgThresholdOne).toBe(true);
|
||||||
|
expect(svgThresholdZero).toBe(true);
|
||||||
|
|
||||||
|
const [invisibleCircle, invisibleSvg] = await Promise.all([
|
||||||
|
page.$('div circle'),
|
||||||
|
await page.$('div svg'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Firefox seems slow when using `isIntersectingViewport`
|
||||||
|
// so we do all the tasks asynchronously
|
||||||
|
const [
|
||||||
|
invisibleCircleThresholdOne,
|
||||||
|
invisibleCircleThresholdZero,
|
||||||
|
invisibleSvgThresholdOne,
|
||||||
|
invisibleSvgThresholdZero,
|
||||||
|
] = await Promise.all([
|
||||||
|
invisibleCircle!.isIntersectingViewport({
|
||||||
|
threshold: 1,
|
||||||
|
}),
|
||||||
|
invisibleCircle!.isIntersectingViewport({
|
||||||
|
threshold: 0,
|
||||||
|
}),
|
||||||
|
invisibleSvg!.isIntersectingViewport({
|
||||||
|
threshold: 1,
|
||||||
|
}),
|
||||||
|
invisibleSvg!.isIntersectingViewport({
|
||||||
|
threshold: 0,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(invisibleCircleThresholdOne).toBe(false);
|
||||||
|
expect(invisibleCircleThresholdZero).toBe(false);
|
||||||
|
expect(invisibleSvgThresholdOne).toBe(false);
|
||||||
|
expect(invisibleSvgThresholdZero).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -158,14 +158,14 @@ describe('JSHandle', function () {
|
|||||||
expect(await bHandle.jsonValue()).toEqual(undefined);
|
expect(await bHandle.jsonValue()).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not work with dates', async () => {
|
it('should work with dates', async () => {
|
||||||
const {page} = getTestState();
|
const {page} = getTestState();
|
||||||
|
|
||||||
const dateHandle = await page.evaluateHandle(() => {
|
const dateHandle = await page.evaluateHandle(() => {
|
||||||
return new Date('2017-09-26T00:00:00.000Z');
|
return new Date('2017-09-26T00:00:00.000Z');
|
||||||
});
|
});
|
||||||
const json = await dateHandle.jsonValue();
|
const date = await dateHandle.jsonValue();
|
||||||
expect(json).toEqual({});
|
expect(date.toISOString()).toEqual('2017-09-26T00:00:00.000Z');
|
||||||
});
|
});
|
||||||
it('should throw for circular objects', async () => {
|
it('should throw for circular objects', async () => {
|
||||||
const {page} = getTestState();
|
const {page} = getTestState();
|
||||||
@ -277,7 +277,10 @@ describe('JSHandle', function () {
|
|||||||
const aHandle = await page.evaluateHandle(() => {
|
const aHandle = await page.evaluateHandle(() => {
|
||||||
return window;
|
return window;
|
||||||
});
|
});
|
||||||
expect(aHandle.toString()).toBe('JSHandle@object');
|
expect(aHandle.toString()).atLeastOneToContain([
|
||||||
|
'JSHandle@object',
|
||||||
|
'JSHandle@window',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
it('should work with different subtypes', async () => {
|
it('should work with different subtypes', async () => {
|
||||||
const {page} = getTestState();
|
const {page} = getTestState();
|
||||||
|
Loading…
Reference in New Issue
Block a user