mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: $ and $$ BiDi support (#10318)
This commit is contained in:
parent
dea71bac40
commit
0371beebba
@ -79,6 +79,9 @@ Suppose we have the markup
|
|||||||
</custom-element>
|
</custom-element>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> Note: `<template shadowrootmode="open">` is not supported on Firefox.
|
||||||
|
> You can read more about it [here](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template#attributes).
|
||||||
|
|
||||||
Then `custom-element >>> h2` will return `h2`, but `custom-element >>>> h2` will return nothing since the inner `h2` is in a deeper shadow root.
|
Then `custom-element >>> h2` will return `h2`, but `custom-element >>>> h2` will return nothing since the inner `h2` is in a deeper shadow root.
|
||||||
|
|
||||||
### `P`-elements
|
### `P`-elements
|
||||||
|
@ -18,6 +18,7 @@ import {Protocol} from 'devtools-protocol';
|
|||||||
|
|
||||||
import {CDPSession} from '../common/Connection.js';
|
import {CDPSession} from '../common/Connection.js';
|
||||||
import {ExecutionContext} from '../common/ExecutionContext.js';
|
import {ExecutionContext} from '../common/ExecutionContext.js';
|
||||||
|
import {getQueryHandlerAndSelector} from '../common/GetQueryHandler.js';
|
||||||
import {MouseClickOptions} from '../common/Input.js';
|
import {MouseClickOptions} from '../common/Input.js';
|
||||||
import {WaitForSelectorOptions} from '../common/IsolatedWorld.js';
|
import {WaitForSelectorOptions} from '../common/IsolatedWorld.js';
|
||||||
import {
|
import {
|
||||||
@ -28,6 +29,9 @@ 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 {assert} from '../util/assert.js';
|
||||||
|
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
|
||||||
|
|
||||||
import {Frame} from './Frame.js';
|
import {Frame} from './Frame.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
@ -276,11 +280,13 @@ export class ElementHandle<
|
|||||||
*/
|
*/
|
||||||
async $<Selector extends string>(
|
async $<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null>;
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
async $<Selector extends string>(): Promise<ElementHandle<
|
const {updatedSelector, QueryHandler} =
|
||||||
NodeFor<Selector>
|
getQueryHandlerAndSelector(selector);
|
||||||
> | null> {
|
return (await QueryHandler.queryOne(
|
||||||
throw new Error('Not implemented');
|
this,
|
||||||
|
updatedSelector
|
||||||
|
)) as ElementHandle<NodeFor<Selector>> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -292,11 +298,12 @@ export class ElementHandle<
|
|||||||
*/
|
*/
|
||||||
async $$<Selector extends string>(
|
async $$<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<Array<ElementHandle<NodeFor<Selector>>>>;
|
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
|
||||||
async $$<Selector extends string>(): Promise<
|
const {updatedSelector, QueryHandler} =
|
||||||
Array<ElementHandle<NodeFor<Selector>>>
|
getQueryHandlerAndSelector(selector);
|
||||||
> {
|
return AsyncIterableUtil.collect(
|
||||||
throw new Error('Not implemented');
|
QueryHandler.queryAll(this, updatedSelector)
|
||||||
|
) as Promise<Array<ElementHandle<NodeFor<Selector>>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -336,9 +343,17 @@ export class ElementHandle<
|
|||||||
selector: Selector,
|
selector: Selector,
|
||||||
pageFunction: Func | string,
|
pageFunction: Func | string,
|
||||||
...args: Params
|
...args: Params
|
||||||
): Promise<Awaited<ReturnType<Func>>>;
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
async $eval(): Promise<unknown> {
|
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
|
||||||
throw new Error('Not implemented');
|
const elementHandle = await this.$(selector);
|
||||||
|
if (!elementHandle) {
|
||||||
|
throw new Error(
|
||||||
|
`Error: failed to find element matching selector "${selector}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const result = await elementHandle.evaluate(pageFunction, ...args);
|
||||||
|
await elementHandle.dispose();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -385,9 +400,20 @@ export class ElementHandle<
|
|||||||
selector: Selector,
|
selector: Selector,
|
||||||
pageFunction: Func | string,
|
pageFunction: Func | string,
|
||||||
...args: Params
|
...args: Params
|
||||||
): Promise<Awaited<ReturnType<Func>>>;
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
async $$eval(): Promise<unknown> {
|
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
|
||||||
throw new Error('Not implemented');
|
const results = await this.$$(selector);
|
||||||
|
const elements = await this.evaluateHandle((_, ...elements) => {
|
||||||
|
return elements;
|
||||||
|
}, ...results);
|
||||||
|
const [result] = await Promise.all([
|
||||||
|
elements.evaluate(pageFunction, ...args),
|
||||||
|
...results.map(results => {
|
||||||
|
return results.dispose();
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
await elements.dispose();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -914,4 +940,11 @@ export class ElementHandle<
|
|||||||
return element.ownerSVGElement!;
|
return element.ownerSVGElement!;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
assertElementHasWorld(): asserts this {
|
||||||
|
assert(this.executionContext()._world);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ import {
|
|||||||
isNumber,
|
isNumber,
|
||||||
isString,
|
isString,
|
||||||
waitForEvent,
|
waitForEvent,
|
||||||
|
withSourcePuppeteerURLIfNone,
|
||||||
} from '../common/util.js';
|
} from '../common/util.js';
|
||||||
import type {WebWorker} from '../common/WebWorker.js';
|
import type {WebWorker} from '../common/WebWorker.js';
|
||||||
import {assert} from '../util/assert.js';
|
import {assert} from '../util/assert.js';
|
||||||
@ -840,11 +841,8 @@ export class Page extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
async $<Selector extends string>(
|
async $<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null>;
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
async $<Selector extends string>(): Promise<ElementHandle<
|
return this.mainFrame().$(selector);
|
||||||
NodeFor<Selector>
|
|
||||||
> | null> {
|
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -856,11 +854,8 @@ export class Page extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
async $$<Selector extends string>(
|
async $$<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<Array<ElementHandle<NodeFor<Selector>>>>;
|
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
|
||||||
async $$<Selector extends string>(): Promise<
|
return this.mainFrame().$$(selector);
|
||||||
Array<ElementHandle<NodeFor<Selector>>>
|
|
||||||
> {
|
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1037,9 +1032,9 @@ export class Page extends EventEmitter {
|
|||||||
selector: Selector,
|
selector: Selector,
|
||||||
pageFunction: Func | string,
|
pageFunction: Func | string,
|
||||||
...args: Params
|
...args: Params
|
||||||
): Promise<Awaited<ReturnType<Func>>>;
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
async $eval(): Promise<unknown> {
|
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
|
||||||
throw new Error('Not implemented');
|
return this.mainFrame().$eval(selector, pageFunction, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1115,9 +1110,9 @@ export class Page extends EventEmitter {
|
|||||||
selector: Selector,
|
selector: Selector,
|
||||||
pageFunction: Func | string,
|
pageFunction: Func | string,
|
||||||
...args: Params
|
...args: Params
|
||||||
): Promise<Awaited<ReturnType<Func>>>;
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
async $$eval(): Promise<unknown> {
|
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
|
||||||
throw new Error('Not implemented');
|
return this.mainFrame().$$eval(selector, pageFunction, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,7 +27,6 @@ import {
|
|||||||
} from '../api/ElementHandle.js';
|
} from '../api/ElementHandle.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';
|
||||||
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
|
|
||||||
|
|
||||||
import {CDPSession} from './Connection.js';
|
import {CDPSession} from './Connection.js';
|
||||||
import {ExecutionContext} from './ExecutionContext.js';
|
import {ExecutionContext} from './ExecutionContext.js';
|
||||||
@ -39,9 +38,9 @@ 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, EvaluateFuncWith, HandleFor, NodeFor} from './types.js';
|
import {ElementFor, HandleFor, NodeFor} from './types.js';
|
||||||
import {KeyInput} from './USKeyboardLayout.js';
|
import {KeyInput} from './USKeyboardLayout.js';
|
||||||
import {debugError, isString, withSourcePuppeteerURLIfNone} from './util.js';
|
import {debugError, isString} from './util.js';
|
||||||
|
|
||||||
const applyOffsetsToQuad = (
|
const applyOffsetsToQuad = (
|
||||||
quad: Point[],
|
quad: Point[],
|
||||||
@ -108,73 +107,17 @@ export class CDPElementHandle<
|
|||||||
override async $<Selector extends string>(
|
override async $<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<CDPElementHandle<NodeFor<Selector>> | null> {
|
): Promise<CDPElementHandle<NodeFor<Selector>> | null> {
|
||||||
const {updatedSelector, QueryHandler} =
|
return super.$(selector) as Promise<CDPElementHandle<
|
||||||
getQueryHandlerAndSelector(selector);
|
NodeFor<Selector>
|
||||||
return (await QueryHandler.queryOne(
|
> | null>;
|
||||||
this,
|
|
||||||
updatedSelector
|
|
||||||
)) as CDPElementHandle<NodeFor<Selector>> | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override async $$<Selector extends string>(
|
override async $$<Selector extends string>(
|
||||||
selector: Selector
|
selector: Selector
|
||||||
): Promise<Array<CDPElementHandle<NodeFor<Selector>>>> {
|
): Promise<Array<CDPElementHandle<NodeFor<Selector>>>> {
|
||||||
const {updatedSelector, QueryHandler} =
|
return super.$$(selector) as Promise<
|
||||||
getQueryHandlerAndSelector(selector);
|
Array<CDPElementHandle<NodeFor<Selector>>>
|
||||||
return AsyncIterableUtil.collect(
|
>;
|
||||||
QueryHandler.queryAll(this, updatedSelector)
|
|
||||||
) as Promise<Array<CDPElementHandle<NodeFor<Selector>>>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
override async $eval<
|
|
||||||
Selector extends string,
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFuncWith<NodeFor<Selector>, Params> = EvaluateFuncWith<
|
|
||||||
NodeFor<Selector>,
|
|
||||||
Params
|
|
||||||
>
|
|
||||||
>(
|
|
||||||
selector: Selector,
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<Awaited<ReturnType<Func>>> {
|
|
||||||
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
|
|
||||||
const elementHandle = await this.$(selector);
|
|
||||||
if (!elementHandle) {
|
|
||||||
throw new Error(
|
|
||||||
`Error: failed to find element matching selector "${selector}"`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const result = await elementHandle.evaluate(pageFunction, ...args);
|
|
||||||
await elementHandle.dispose();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
override async $$eval<
|
|
||||||
Selector extends string,
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFuncWith<
|
|
||||||
Array<NodeFor<Selector>>,
|
|
||||||
Params
|
|
||||||
> = EvaluateFuncWith<Array<NodeFor<Selector>>, Params>
|
|
||||||
>(
|
|
||||||
selector: Selector,
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<Awaited<ReturnType<Func>>> {
|
|
||||||
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
|
|
||||||
const results = await this.$$(selector);
|
|
||||||
const elements = await this.evaluateHandle((_, ...elements) => {
|
|
||||||
return elements;
|
|
||||||
}, ...results);
|
|
||||||
const [result] = await Promise.all([
|
|
||||||
elements.evaluate(pageFunction, ...args),
|
|
||||||
...results.map(results => {
|
|
||||||
return results.dispose();
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
await elements.dispose();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override async $x(
|
override async $x(
|
||||||
|
@ -14,26 +14,34 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ExecutionContext} from './ExecutionContext.js';
|
import {JSHandle} from '../api/JSHandle.js';
|
||||||
|
import PuppeteerUtil from '../injected/injected.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export class LazyArg<T> {
|
export interface PuppeteerUtilWrapper {
|
||||||
|
puppeteerUtil: Promise<JSHandle<PuppeteerUtil>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export class LazyArg<T, Context = PuppeteerUtilWrapper> {
|
||||||
static create = <T>(
|
static create = <T>(
|
||||||
get: (context: ExecutionContext) => Promise<T> | T
|
get: (context: PuppeteerUtilWrapper) => Promise<T> | T
|
||||||
): T => {
|
): T => {
|
||||||
// We don't want to introduce LazyArg to the type system, otherwise we would
|
// We don't want to introduce LazyArg to the type system, otherwise we would
|
||||||
// have to make it public.
|
// have to make it public.
|
||||||
return new LazyArg(get) as unknown as T;
|
return new LazyArg(get) as unknown as T;
|
||||||
};
|
};
|
||||||
|
|
||||||
#get: (context: ExecutionContext) => Promise<T> | T;
|
#get: (context: Context) => Promise<T> | T;
|
||||||
private constructor(get: (context: ExecutionContext) => Promise<T> | T) {
|
private constructor(get: (context: Context) => Promise<T> | T) {
|
||||||
this.#get = get;
|
this.#get = get;
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(context: ExecutionContext): Promise<T> {
|
async get(context: Context): Promise<T> {
|
||||||
return this.#get(context);
|
return this.#get(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,13 +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 {
|
import {BindingPayload, EvaluateFunc, HandleFor, NodeFor} from './types.js';
|
||||||
BindingPayload,
|
|
||||||
EvaluateFunc,
|
|
||||||
EvaluateFuncWith,
|
|
||||||
HandleFor,
|
|
||||||
NodeFor,
|
|
||||||
} from './types.js';
|
|
||||||
import {
|
import {
|
||||||
createClientError,
|
createClientError,
|
||||||
createJSHandle,
|
createJSHandle,
|
||||||
@ -521,18 +515,6 @@ export class CDPPage extends Page {
|
|||||||
return this.#timeoutSettings.timeout();
|
return this.#timeoutSettings.timeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
override async $<Selector extends string>(
|
|
||||||
selector: Selector
|
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
|
||||||
return this.mainFrame().$(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async $$<Selector extends string>(
|
|
||||||
selector: Selector
|
|
||||||
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
|
|
||||||
return this.mainFrame().$$(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async evaluateHandle<
|
override async evaluateHandle<
|
||||||
Params extends unknown[],
|
Params extends unknown[],
|
||||||
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
||||||
@ -563,38 +545,6 @@ export class CDPPage extends Page {
|
|||||||
return createJSHandle(context, response.objects) as HandleFor<Prototype[]>;
|
return createJSHandle(context, response.objects) as HandleFor<Prototype[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
override async $eval<
|
|
||||||
Selector extends string,
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFuncWith<NodeFor<Selector>, Params> = EvaluateFuncWith<
|
|
||||||
NodeFor<Selector>,
|
|
||||||
Params
|
|
||||||
>
|
|
||||||
>(
|
|
||||||
selector: Selector,
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<Awaited<ReturnType<Func>>> {
|
|
||||||
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
|
|
||||||
return this.mainFrame().$eval(selector, pageFunction, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async $$eval<
|
|
||||||
Selector extends string,
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFuncWith<
|
|
||||||
Array<NodeFor<Selector>>,
|
|
||||||
Params
|
|
||||||
> = EvaluateFuncWith<Array<NodeFor<Selector>>, Params>
|
|
||||||
>(
|
|
||||||
selector: Selector,
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<Awaited<ReturnType<Func>>> {
|
|
||||||
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
|
|
||||||
return this.mainFrame().$$eval(selector, pageFunction, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
override async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
override async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
|
||||||
return this.mainFrame().$x(expression);
|
return this.mainFrame().$x(expression);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
import {ElementHandle} from '../api/ElementHandle.js';
|
import {ElementHandle} from '../api/ElementHandle.js';
|
||||||
import type {Frame} from '../api/Frame.js';
|
import type {Frame} from '../api/Frame.js';
|
||||||
import type PuppeteerUtil from '../injected/injected.js';
|
import type PuppeteerUtil from '../injected/injected.js';
|
||||||
import {assert} from '../util/assert.js';
|
|
||||||
import {isErrorLike} from '../util/ErrorLike.js';
|
import {isErrorLike} from '../util/ErrorLike.js';
|
||||||
import {interpolateFunction, stringifyFunction} from '../util/Function.js';
|
import {interpolateFunction, stringifyFunction} from '../util/Function.js';
|
||||||
|
|
||||||
@ -108,8 +107,7 @@ export class QueryHandler {
|
|||||||
element: ElementHandle<Node>,
|
element: ElementHandle<Node>,
|
||||||
selector: string
|
selector: string
|
||||||
): AwaitableIterable<ElementHandle<Node>> {
|
): AwaitableIterable<ElementHandle<Node>> {
|
||||||
const world = element.executionContext()._world;
|
element.assertElementHasWorld();
|
||||||
assert(world);
|
|
||||||
const handle = await element.evaluateHandle(
|
const handle = await element.evaluateHandle(
|
||||||
this._querySelectorAll,
|
this._querySelectorAll,
|
||||||
selector,
|
selector,
|
||||||
@ -129,8 +127,7 @@ export class QueryHandler {
|
|||||||
element: ElementHandle<Node>,
|
element: ElementHandle<Node>,
|
||||||
selector: string
|
selector: string
|
||||||
): Promise<ElementHandle<Node> | null> {
|
): Promise<ElementHandle<Node> | null> {
|
||||||
const world = element.executionContext()._world;
|
element.assertElementHasWorld();
|
||||||
assert(world);
|
|
||||||
const result = await element.evaluateHandle(
|
const result = await element.evaluateHandle(
|
||||||
this._querySelector,
|
this._querySelector,
|
||||||
selector,
|
selector,
|
||||||
|
@ -2,11 +2,13 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
|||||||
import ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js';
|
import ProtocolMapping from 'devtools-protocol/types/protocol-mapping.js';
|
||||||
|
|
||||||
import {WaitForOptions} from '../../api/Page.js';
|
import {WaitForOptions} from '../../api/Page.js';
|
||||||
|
import PuppeteerUtil from '../../injected/injected.js';
|
||||||
import {assert} from '../../util/assert.js';
|
import {assert} from '../../util/assert.js';
|
||||||
import {stringifyFunction} from '../../util/Function.js';
|
import {stringifyFunction} from '../../util/Function.js';
|
||||||
import {ProtocolError, TimeoutError} from '../Errors.js';
|
import {ProtocolError, TimeoutError} from '../Errors.js';
|
||||||
import {EventEmitter} from '../EventEmitter.js';
|
import {EventEmitter} from '../EventEmitter.js';
|
||||||
import {PuppeteerLifeCycleEvent} from '../LifecycleWatcher.js';
|
import {PuppeteerLifeCycleEvent} from '../LifecycleWatcher.js';
|
||||||
|
import {scriptInjector} from '../ScriptInjector.js';
|
||||||
import {TimeoutSettings} from '../TimeoutSettings.js';
|
import {TimeoutSettings} from '../TimeoutSettings.js';
|
||||||
import {EvaluateFunc, HandleFor} from '../types.js';
|
import {EvaluateFunc, HandleFor} from '../types.js';
|
||||||
import {
|
import {
|
||||||
@ -69,6 +71,22 @@ export class BrowsingContext extends EventEmitter {
|
|||||||
this.#id = info.context;
|
this.#id = info.context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#puppeteerUtil?: Promise<JSHandle<PuppeteerUtil>>;
|
||||||
|
get puppeteerUtil(): Promise<JSHandle<PuppeteerUtil>> {
|
||||||
|
const promise = Promise.resolve() as Promise<unknown>;
|
||||||
|
scriptInjector.inject(script => {
|
||||||
|
if (this.#puppeteerUtil) {
|
||||||
|
void this.#puppeteerUtil.then(handle => {
|
||||||
|
void handle.dispose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.#puppeteerUtil = promise.then(() => {
|
||||||
|
return this.evaluateHandle(script) as Promise<JSHandle<PuppeteerUtil>>;
|
||||||
|
});
|
||||||
|
}, !this.#puppeteerUtil);
|
||||||
|
return this.#puppeteerUtil as Promise<JSHandle<PuppeteerUtil>>;
|
||||||
|
}
|
||||||
|
|
||||||
get url(): string {
|
get url(): string {
|
||||||
return this.#url;
|
return this.#url;
|
||||||
}
|
}
|
||||||
|
@ -47,4 +47,12 @@ export class ElementHandle<
|
|||||||
remoteValue(): Bidi.CommonDataTypes.RemoteValue {
|
remoteValue(): Bidi.CommonDataTypes.RemoteValue {
|
||||||
return this.handle.remoteValue();
|
return this.handle.remoteValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
override assertElementHasWorld(): asserts this {
|
||||||
|
// TODO: Should assert element has a Sandbox
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,21 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {ElementHandle} from '../../api/ElementHandle.js';
|
||||||
import {Frame as BaseFrame} from '../../api/Frame.js';
|
import {Frame as BaseFrame} from '../../api/Frame.js';
|
||||||
import {PuppeteerLifeCycleEvent} from '../LifecycleWatcher.js';
|
import {PuppeteerLifeCycleEvent} from '../LifecycleWatcher.js';
|
||||||
import {EvaluateFunc, HandleFor} from '../types.js';
|
import {EvaluateFunc, EvaluateFuncWith, HandleFor, NodeFor} from '../types.js';
|
||||||
|
import {withSourcePuppeteerURLIfNone} from '../util.js';
|
||||||
|
|
||||||
import {BrowsingContext} from './BrowsingContext.js';
|
import {BrowsingContext} from './BrowsingContext.js';
|
||||||
import {HTTPResponse} from './HTTPResponse.js';
|
import {HTTPResponse} from './HTTPResponse.js';
|
||||||
import {Page} from './Page.js';
|
import {Page} from './Page.js';
|
||||||
|
import {
|
||||||
|
MAIN_SANDBOX,
|
||||||
|
PUPPETEER_SANDBOX,
|
||||||
|
SandboxChart,
|
||||||
|
Sandbox,
|
||||||
|
} from './Sandbox.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puppeteer's Frame class could be viewed as a BiDi BrowsingContext implementation
|
* Puppeteer's Frame class could be viewed as a BiDi BrowsingContext implementation
|
||||||
@ -29,6 +37,7 @@ import {Page} from './Page.js';
|
|||||||
export class Frame extends BaseFrame {
|
export class Frame extends BaseFrame {
|
||||||
#page: Page;
|
#page: Page;
|
||||||
#context: BrowsingContext;
|
#context: BrowsingContext;
|
||||||
|
sandboxes: SandboxChart;
|
||||||
override _id: string;
|
override _id: string;
|
||||||
|
|
||||||
constructor(page: Page, context: BrowsingContext, parentId?: string | null) {
|
constructor(page: Page, context: BrowsingContext, parentId?: string | null) {
|
||||||
@ -37,6 +46,11 @@ export class Frame extends BaseFrame {
|
|||||||
this.#context = context;
|
this.#context = context;
|
||||||
this._id = this.#context.id;
|
this._id = this.#context.id;
|
||||||
this._parentId = parentId ?? undefined;
|
this._parentId = parentId ?? undefined;
|
||||||
|
|
||||||
|
this.sandboxes = {
|
||||||
|
[MAIN_SANDBOX]: new Sandbox(context),
|
||||||
|
[PUPPETEER_SANDBOX]: new Sandbox(context),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
override page(): Page {
|
override page(): Page {
|
||||||
@ -119,6 +133,50 @@ export class Frame extends BaseFrame {
|
|||||||
return this.#context;
|
return this.#context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override $<Selector extends string>(
|
||||||
|
selector: Selector
|
||||||
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
|
return this.sandboxes[MAIN_SANDBOX].$(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
override $$<Selector extends string>(
|
||||||
|
selector: Selector
|
||||||
|
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
|
||||||
|
return this.sandboxes[MAIN_SANDBOX].$$(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
override $eval<
|
||||||
|
Selector extends string,
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFuncWith<NodeFor<Selector>, Params> = EvaluateFuncWith<
|
||||||
|
NodeFor<Selector>,
|
||||||
|
Params
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
selector: Selector,
|
||||||
|
pageFunction: string | Func,
|
||||||
|
...args: Params
|
||||||
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
|
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
|
||||||
|
return this.sandboxes[MAIN_SANDBOX].$eval(selector, pageFunction, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
override $$eval<
|
||||||
|
Selector extends string,
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFuncWith<
|
||||||
|
Array<NodeFor<Selector>>,
|
||||||
|
Params
|
||||||
|
> = EvaluateFuncWith<Array<NodeFor<Selector>>, Params>
|
||||||
|
>(
|
||||||
|
selector: Selector,
|
||||||
|
pageFunction: string | Func,
|
||||||
|
...args: Params
|
||||||
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
|
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
|
||||||
|
return this.sandboxes[MAIN_SANDBOX].$$eval(selector, pageFunction, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this.#context.dispose();
|
this.#context.dispose();
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,14 @@ export class JSHandle<T = unknown> extends BaseJSHandle<T> {
|
|||||||
// TODO(lightning00blade): Either include return of depth Handles in RemoteValue
|
// TODO(lightning00blade): Either include return of depth Handles in RemoteValue
|
||||||
// or new BiDi command that returns array of remote value
|
// or new BiDi command that returns array of remote value
|
||||||
const keys = await this.evaluate(object => {
|
const keys = await this.evaluate(object => {
|
||||||
return Object.getOwnPropertyNames(object);
|
const enumerableKeys = [];
|
||||||
|
const descriptors = Object.getOwnPropertyDescriptors(object);
|
||||||
|
for (const key in descriptors) {
|
||||||
|
if (descriptors[key]?.enumerable) {
|
||||||
|
enumerableKeys.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return enumerableKeys;
|
||||||
});
|
});
|
||||||
const map: Map<string, BaseJSHandle> = new Map();
|
const map: Map<string, BaseJSHandle> = new Map();
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
|
115
packages/puppeteer-core/src/common/bidi/Sandbox.ts
Normal file
115
packages/puppeteer-core/src/common/bidi/Sandbox.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 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 {ElementHandle} from '../../api/ElementHandle.js';
|
||||||
|
import {withSourcePuppeteerURLIfNone} from '../common.js';
|
||||||
|
import {EvaluateFuncWith, NodeFor} from '../types.js';
|
||||||
|
|
||||||
|
import {BrowsingContext} from './BrowsingContext.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique key for {@link SandboxChart} to denote the default world.
|
||||||
|
* Realms are automatically created in the default sandbox.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export const MAIN_SANDBOX = Symbol('mainSandbox');
|
||||||
|
/**
|
||||||
|
* A unique key for {@link SandboxChart} to denote the puppeteer sandbox.
|
||||||
|
* This world contains all puppeteer-internal bindings/code.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export const PUPPETEER_SANDBOX = Symbol('puppeteerSandbox');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export interface SandboxChart {
|
||||||
|
[key: string]: Sandbox;
|
||||||
|
[MAIN_SANDBOX]: Sandbox;
|
||||||
|
[PUPPETEER_SANDBOX]: Sandbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export class Sandbox {
|
||||||
|
#document?: ElementHandle<Document>;
|
||||||
|
#context: BrowsingContext;
|
||||||
|
|
||||||
|
constructor(context: BrowsingContext) {
|
||||||
|
this.#context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
async document(): Promise<ElementHandle<Document>> {
|
||||||
|
if (this.#document) {
|
||||||
|
return this.#document;
|
||||||
|
}
|
||||||
|
this.#document = await this.#context.evaluateHandle(() => {
|
||||||
|
return document;
|
||||||
|
});
|
||||||
|
return this.#document;
|
||||||
|
}
|
||||||
|
|
||||||
|
async $<Selector extends string>(
|
||||||
|
selector: Selector
|
||||||
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
|
const document = await this.document();
|
||||||
|
return document.$(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
async $$<Selector extends string>(
|
||||||
|
selector: Selector
|
||||||
|
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
|
||||||
|
const document = await this.document();
|
||||||
|
return document.$$(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
async $eval<
|
||||||
|
Selector extends string,
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFuncWith<NodeFor<Selector>, Params> = EvaluateFuncWith<
|
||||||
|
NodeFor<Selector>,
|
||||||
|
Params
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
selector: Selector,
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
|
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
|
||||||
|
const document = await this.document();
|
||||||
|
return document.$eval(selector, pageFunction, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
async $$eval<
|
||||||
|
Selector extends string,
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFuncWith<
|
||||||
|
Array<NodeFor<Selector>>,
|
||||||
|
Params
|
||||||
|
> = EvaluateFuncWith<Array<NodeFor<Selector>>, Params>
|
||||||
|
>(
|
||||||
|
selector: Selector,
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
|
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
|
||||||
|
const document = await this.document();
|
||||||
|
return document.$$eval(selector, pageFunction, ...args);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
|
|
||||||
|
import {LazyArg} from '../LazyArg.js';
|
||||||
import {debugError, isDate, isPlainObject, isRegExp} from '../util.js';
|
import {debugError, isDate, isPlainObject, isRegExp} from '../util.js';
|
||||||
|
|
||||||
import {BrowsingContext} from './BrowsingContext.js';
|
import {BrowsingContext} from './BrowsingContext.js';
|
||||||
@ -141,11 +142,15 @@ export class BidiSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static serialize(
|
static async serialize(
|
||||||
arg: unknown,
|
arg: unknown,
|
||||||
context: BrowsingContext
|
context: BrowsingContext
|
||||||
): Bidi.CommonDataTypes.LocalValue | Bidi.CommonDataTypes.RemoteValue {
|
): Promise<
|
||||||
// TODO: See use case of LazyArgs
|
Bidi.CommonDataTypes.LocalValue | Bidi.CommonDataTypes.RemoteValue
|
||||||
|
> {
|
||||||
|
if (arg instanceof LazyArg) {
|
||||||
|
arg = await arg.get(context);
|
||||||
|
}
|
||||||
const objectHandle =
|
const objectHandle =
|
||||||
arg && (arg instanceof JSHandle || arg instanceof ElementHandle)
|
arg && (arg instanceof JSHandle || arg instanceof ElementHandle)
|
||||||
? arg
|
? arg
|
||||||
@ -205,6 +210,7 @@ export class BidiSerializer {
|
|||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'map':
|
case 'map':
|
||||||
return result.value.reduce((acc: Map<unknown, unknown>, tuple) => {
|
return result.value.reduce((acc: Map<unknown, unknown>, tuple) => {
|
||||||
const {key, value} = BidiSerializer.deserializeTuple(tuple);
|
const {key, value} = BidiSerializer.deserializeTuple(tuple);
|
||||||
|
@ -21,13 +21,13 @@
|
|||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluateOnNewDocument *",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluateOnNewDocument *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.removeScriptToEvaluateOnNewDocument *",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Page.removeScriptToEvaluateOnNewDocument *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[EventEmitter.spec] EventEmitter *",
|
"testIdPattern": "[EventEmitter.spec] EventEmitter *",
|
||||||
@ -51,25 +51,25 @@
|
|||||||
"testIdPattern": "[navigation.spec] navigation Frame.goto *",
|
"testIdPattern": "[navigation.spec] navigation Frame.goto *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation *",
|
"testIdPattern": "[navigation.spec] navigation Frame.waitForNavigation *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.goBack *",
|
"testIdPattern": "[navigation.spec] navigation Page.goBack *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation *",
|
"testIdPattern": "[navigation.spec] navigation Page.waitForNavigation *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[network.spec] network *",
|
"testIdPattern": "[network.spec] network *",
|
||||||
@ -87,7 +87,7 @@
|
|||||||
"testIdPattern": "[network.spec] network Page.authenticate *",
|
"testIdPattern": "[network.spec] network Page.authenticate *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[network.spec] network Page.setBypassServiceWorker *",
|
"testIdPattern": "[network.spec] network Page.setBypassServiceWorker *",
|
||||||
@ -201,7 +201,7 @@
|
|||||||
"testIdPattern": "[queryhandler.spec] *",
|
"testIdPattern": "[queryhandler.spec] *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL", "SKIP"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[accessibility.spec] *",
|
"testIdPattern": "[accessibility.spec] *",
|
||||||
@ -251,89 +251,41 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Frame.evaluate should have correct execution contexts",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Frame.evaluate should have different execution contexts",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Frame.evaluate should have different execution contexts",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should accept element handle as an argument",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should be able to throw a tricky error",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should evaluate in the page context",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should not throw an error when evaluation does a navigation",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should not throw an error when evaluation does a navigation",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should simulate a user gesture",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should simulate a user gesture",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw a nice error after a navigation",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw a nice error after a navigation",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw if elementHandles are from other frames",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw if elementHandles are from other frames",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw if underlying element was disposed",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw when evaluation triggers reload",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work from-inside an exposed function",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work from-inside an exposed function",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work right after framenavigated",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should work right after framenavigated",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluateOnNewDocument *",
|
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluateOnNewDocument *",
|
||||||
@ -495,7 +447,7 @@
|
|||||||
"testIdPattern": "[network.spec] network raw network headers Cross-origin set-cookie",
|
"testIdPattern": "[network.spec] network raw network headers Cross-origin set-cookie",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie navigation",
|
"testIdPattern": "[network.spec] network raw network headers Same-origin set-cookie navigation",
|
||||||
@ -569,30 +521,6 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["PASS"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[page.spec] Page Page.setContent should work with accents",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[page.spec] Page Page.setContent should work with emojis",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[page.spec] Page Page.setContent should work with newline",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[page.spec] Page Page.setContent should work with tricky content",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"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"],
|
||||||
@ -605,6 +533,36 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work with :hover",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[queryhandler.spec] Query handler tests Text selectors in Page should clear caches",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[requestinterception-experimental.spec] *",
|
"testIdPattern": "[requestinterception-experimental.spec] *",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -1577,12 +1535,6 @@
|
|||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["SKIP"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[network.spec] network Page.authenticate should work",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["firefox", "webDriverBiDi"],
|
|
||||||
"expectations": ["SKIP"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[network.spec] network Page.setExtraHTTPHeaders should work",
|
"testIdPattern": "[network.spec] network Page.setExtraHTTPHeaders should work",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -2137,18 +2089,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role",
|
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role",
|
||||||
"platforms": ["linux"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role",
|
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role",
|
||||||
"platforms": ["linux"],
|
|
||||||
"parameters": ["cdp", "firefox"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work with deep combinators",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["cdp", "firefox"],
|
"parameters": ["cdp", "firefox"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
@ -2536,5 +2482,11 @@
|
|||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["cdp", "chrome", "headless"],
|
"parameters": ["cdp", "chrome", "headless"],
|
||||||
"expectations": ["FAIL", "PASS"]
|
"expectations": ["FAIL", "PASS"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"testIdPattern": "[navigation.spec] navigation \"after each\" hook for \"should work with both domcontentloaded and load\"",
|
||||||
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
|
"parameters": ["webDriverBiDi"],
|
||||||
|
"expectations": ["FAIL"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
<div id="a">hello <button id="b">world</button>
|
<div id="a">hello <button id="b">world</button>
|
||||||
<span id="f"></span>
|
<span id="f"></span>
|
||||||
<div id="c">
|
<div id="c"></div>
|
||||||
<template shadowrootmode="open">
|
|
||||||
shadow dom
|
|
||||||
<div id="d">
|
|
||||||
<template shadowrootmode="open">
|
|
||||||
<a id="e">deep text</a>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const topShadow = document.querySelector('#c');
|
||||||
|
topShadow.attachShadow({ mode: "open" });
|
||||||
|
topShadow.shadowRoot.innerHTML = `shadow dom<div id="d"></div>`;
|
||||||
|
|
||||||
|
const innerShadow = topShadow.shadowRoot.querySelector('#d');
|
||||||
|
innerShadow.attachShadow({ mode: "open" });
|
||||||
|
innerShadow.shadowRoot.innerHTML = `<a id="e">deep text</a>`;
|
||||||
|
</script>
|
@ -17,7 +17,7 @@
|
|||||||
import {ServerResponse} from 'http';
|
import {ServerResponse} from 'http';
|
||||||
|
|
||||||
import expect from 'expect';
|
import expect from 'expect';
|
||||||
import {TimeoutError} from 'puppeteer';
|
import {Frame, TimeoutError} from 'puppeteer';
|
||||||
import {HTTPRequest} from 'puppeteer-core/internal/api/HTTPRequest.js';
|
import {HTTPRequest} from 'puppeteer-core/internal/api/HTTPRequest.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -595,18 +595,30 @@ describe('navigation', function () {
|
|||||||
server.setRoute('/one-style.css', (_req, res) => {
|
server.setRoute('/one-style.css', (_req, res) => {
|
||||||
return (response = res);
|
return (response = res);
|
||||||
});
|
});
|
||||||
const navigationPromise = page.goto(server.PREFIX + '/one-style.html');
|
let error: Error | undefined;
|
||||||
const domContentLoadedPromise = page.waitForNavigation({
|
|
||||||
waitUntil: 'domcontentloaded',
|
|
||||||
});
|
|
||||||
|
|
||||||
let bothFired = false;
|
let bothFired = false;
|
||||||
|
const navigationPromise = page
|
||||||
|
.goto(server.PREFIX + '/one-style.html')
|
||||||
|
.catch(_error => {
|
||||||
|
return (error = _error);
|
||||||
|
});
|
||||||
|
const domContentLoadedPromise = page
|
||||||
|
.waitForNavigation({
|
||||||
|
waitUntil: 'domcontentloaded',
|
||||||
|
})
|
||||||
|
.catch(_error => {
|
||||||
|
return (error = _error);
|
||||||
|
});
|
||||||
|
|
||||||
const bothFiredPromise = page
|
const bothFiredPromise = page
|
||||||
.waitForNavigation({
|
.waitForNavigation({
|
||||||
waitUntil: ['load', 'domcontentloaded'],
|
waitUntil: ['load', 'domcontentloaded'],
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return (bothFired = true);
|
return (bothFired = true);
|
||||||
|
})
|
||||||
|
.catch(_error => {
|
||||||
|
return (error = _error);
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.waitForRequest('/one-style.css').catch(() => {});
|
await server.waitForRequest('/one-style.css').catch(() => {});
|
||||||
@ -615,6 +627,7 @@ describe('navigation', function () {
|
|||||||
response.end();
|
response.end();
|
||||||
await bothFiredPromise;
|
await bothFiredPromise;
|
||||||
await navigationPromise;
|
await navigationPromise;
|
||||||
|
expect(error).toBeUndefined();
|
||||||
});
|
});
|
||||||
it('should work with clicking on anchor links', async () => {
|
it('should work with clicking on anchor links', async () => {
|
||||||
const {page, server} = getTestState();
|
const {page, server} = getTestState();
|
||||||
@ -690,19 +703,40 @@ describe('navigation', function () {
|
|||||||
expect(forwardResponse).toBe(null);
|
expect(forwardResponse).toBe(null);
|
||||||
expect(page.url()).toBe(server.PREFIX + '/second.html');
|
expect(page.url()).toBe(server.PREFIX + '/second.html');
|
||||||
});
|
});
|
||||||
it('should work when subframe issues window.stop()', async () => {
|
it('should work when subframe issues window.stop()', async function () {
|
||||||
const {page, server} = getTestState();
|
const {page, server} = getTestState();
|
||||||
|
|
||||||
server.setRoute('/frames/style.css', () => {});
|
server.setRoute('/frames/style.css', () => {});
|
||||||
|
let frame: Frame | undefined;
|
||||||
|
let timeout: NodeJS.Timeout | undefined;
|
||||||
|
const eventPromises = Promise.race([
|
||||||
|
Promise.all([
|
||||||
|
waitEvent(page, 'frameattached').then(_frame => {
|
||||||
|
return (frame = _frame);
|
||||||
|
}),
|
||||||
|
waitEvent(page, 'framenavigated', f => {
|
||||||
|
return f === frame;
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
new Promise((_, rej) => {
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
return rej(new Error('Timeout'));
|
||||||
|
}, this.timeout());
|
||||||
|
}),
|
||||||
|
]);
|
||||||
const navigationPromise = page.goto(
|
const navigationPromise = page.goto(
|
||||||
server.PREFIX + '/frames/one-frame.html'
|
server.PREFIX + '/frames/one-frame.html'
|
||||||
);
|
);
|
||||||
const frame = await waitEvent(page, 'frameattached');
|
try {
|
||||||
await waitEvent(page, 'framenavigated', f => {
|
await eventPromises;
|
||||||
return f === frame;
|
clearTimeout(timeout);
|
||||||
});
|
} catch (error) {
|
||||||
|
navigationPromise.catch(() => {});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
frame.evaluate(() => {
|
frame!.evaluate(() => {
|
||||||
return window.stop();
|
return window.stop();
|
||||||
}),
|
}),
|
||||||
navigationPromise,
|
navigationPromise,
|
||||||
|
Loading…
Reference in New Issue
Block a user