mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: make execution context frame-independent (#8845)
This commit is contained in:
parent
2f33237d04
commit
b49e742e30
@ -92,6 +92,13 @@ export class ElementHandle<
|
|||||||
return this.#frame.page();
|
return this.#frame.page();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
get frame(): Frame {
|
||||||
|
return this.#frame;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries the current element for an element matching the given selector.
|
* Queries the current element for an element matching the given selector.
|
||||||
*
|
*
|
||||||
@ -294,8 +301,7 @@ export class ElementHandle<
|
|||||||
selector: Selector,
|
selector: Selector,
|
||||||
options: Exclude<WaitForSelectorOptions, 'root'> = {}
|
options: Exclude<WaitForSelectorOptions, 'root'> = {}
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
const frame = this.executionContext().frame();
|
const frame = this.#frame;
|
||||||
assert(frame);
|
|
||||||
const adoptedRoot = await frame.worlds[PUPPETEER_WORLD].adoptHandle(this);
|
const adoptedRoot = await frame.worlds[PUPPETEER_WORLD].adoptHandle(this);
|
||||||
const handle = await frame.worlds[PUPPETEER_WORLD].waitForSelector(
|
const handle = await frame.worlds[PUPPETEER_WORLD].waitForSelector(
|
||||||
selector,
|
selector,
|
||||||
|
@ -15,9 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Protocol} from 'devtools-protocol';
|
import {Protocol} from 'devtools-protocol';
|
||||||
import {assert} from '../util/assert.js';
|
|
||||||
import {CDPSession} from './Connection.js';
|
import {CDPSession} from './Connection.js';
|
||||||
import {Frame} from './Frame.js';
|
|
||||||
import {IsolatedWorld} from './IsolatedWorld.js';
|
import {IsolatedWorld} from './IsolatedWorld.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
import {EvaluateFunc, HandleFor} from './types.js';
|
import {EvaluateFunc, HandleFor} from './types.js';
|
||||||
@ -88,18 +86,6 @@ export class ExecutionContext {
|
|||||||
this._contextName = contextPayload.name;
|
this._contextName = contextPayload.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns The frame associated with this execution context.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Not every execution context is associated with a frame. For example,
|
|
||||||
* {@link WebWorker | workers} have execution contexts that are not associated
|
|
||||||
* with frames.
|
|
||||||
*/
|
|
||||||
frame(): Frame | null {
|
|
||||||
return this._world ? this._world.frame() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the given function.
|
* Evaluates the given function.
|
||||||
*
|
*
|
||||||
@ -355,8 +341,10 @@ export class ExecutionContext {
|
|||||||
}
|
}
|
||||||
return {value: arg};
|
return {value: arg};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function rewriteError(error: Error): Protocol.Runtime.EvaluateResponse {
|
const rewriteError = (error: Error): Protocol.Runtime.EvaluateResponse => {
|
||||||
if (error.message.includes('Object reference chain is too long')) {
|
if (error.message.includes('Object reference chain is too long')) {
|
||||||
return {result: {type: 'undefined'}};
|
return {result: {type: 'undefined'}};
|
||||||
}
|
}
|
||||||
@ -373,43 +361,4 @@ export class ExecutionContext {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates through the JavaScript heap and finds all the objects with the
|
|
||||||
* given prototype.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* // Create a Map object
|
|
||||||
* await page.evaluate(() => (window.map = new Map()));
|
|
||||||
* // Get a handle to the Map object prototype
|
|
||||||
* const mapPrototype = await page.evaluateHandle(() => Map.prototype);
|
|
||||||
* // Query all map instances into an array
|
|
||||||
* const mapInstances = await page.queryObjects(mapPrototype);
|
|
||||||
* // Count amount of map objects in heap
|
|
||||||
* const count = await page.evaluate(maps => maps.length, mapInstances);
|
|
||||||
* await mapInstances.dispose();
|
|
||||||
* await mapPrototype.dispose();
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param prototypeHandle - a handle to the object prototype
|
|
||||||
* @returns A handle to an array of objects with the given prototype.
|
|
||||||
*/
|
|
||||||
async queryObjects<Prototype>(
|
|
||||||
prototypeHandle: JSHandle<Prototype>
|
|
||||||
): Promise<HandleFor<Prototype[]>> {
|
|
||||||
assert(!prototypeHandle.disposed, 'Prototype JSHandle is disposed!');
|
|
||||||
const remoteObject = prototypeHandle.remoteObject();
|
|
||||||
assert(
|
|
||||||
remoteObject.objectId,
|
|
||||||
'Prototype JSHandle must not be referencing primitive value'
|
|
||||||
);
|
|
||||||
const response = await this._client.send('Runtime.queryObjects', {
|
|
||||||
prototypeObjectId: remoteObject.objectId,
|
|
||||||
});
|
|
||||||
return createJSHandle(this, response.objects) as HandleFor<Prototype[]>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -25,7 +25,6 @@ import {ElementHandle} from './ElementHandle.js';
|
|||||||
import {TimeoutError} from './Errors.js';
|
import {TimeoutError} from './Errors.js';
|
||||||
import {CommonEventEmitter} from './EventEmitter.js';
|
import {CommonEventEmitter} from './EventEmitter.js';
|
||||||
import {ExecutionContext} from './ExecutionContext.js';
|
import {ExecutionContext} from './ExecutionContext.js';
|
||||||
import {Frame} from './Frame.js';
|
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -218,9 +217,8 @@ export function createJSHandle(
|
|||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
remoteObject: Protocol.Runtime.RemoteObject
|
remoteObject: Protocol.Runtime.RemoteObject
|
||||||
): JSHandle | ElementHandle<Node> {
|
): JSHandle | ElementHandle<Node> {
|
||||||
const frame = context.frame();
|
if (remoteObject.subtype === 'node' && context._world) {
|
||||||
if (remoteObject.subtype === 'node' && frame instanceof Frame) {
|
return new ElementHandle(context, remoteObject, context._world.frame());
|
||||||
return new ElementHandle(context, remoteObject, frame);
|
|
||||||
}
|
}
|
||||||
return new JSHandle(context, remoteObject);
|
return new JSHandle(context, remoteObject);
|
||||||
}
|
}
|
||||||
|
@ -334,7 +334,7 @@ describeChromeOnly('AriaQueryHandler', () => {
|
|||||||
await otherFrame!.evaluate(addElement, 'button');
|
await otherFrame!.evaluate(addElement, 'button');
|
||||||
await page.evaluate(addElement, 'button');
|
await page.evaluate(addElement, 'button');
|
||||||
const elementHandle = await watchdog;
|
const elementHandle = await watchdog;
|
||||||
expect(elementHandle!.executionContext().frame()).toBe(page.mainFrame());
|
expect(elementHandle!.frame).toBe(page.mainFrame());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run in specified frame', async () => {
|
it('should run in specified frame', async () => {
|
||||||
@ -350,7 +350,7 @@ describeChromeOnly('AriaQueryHandler', () => {
|
|||||||
await frame1!.evaluate(addElement, 'button');
|
await frame1!.evaluate(addElement, 'button');
|
||||||
await frame2!.evaluate(addElement, 'button');
|
await frame2!.evaluate(addElement, 'button');
|
||||||
const elementHandle = await waitForSelectorPromise;
|
const elementHandle = await waitForSelectorPromise;
|
||||||
expect(elementHandle!.executionContext().frame()).toBe(frame2);
|
expect(elementHandle!.frame).toBe(frame2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when frame is detached', async () => {
|
it('should throw when frame is detached', async () => {
|
||||||
|
@ -42,8 +42,8 @@ describe('Frame specs', function () {
|
|||||||
expect(context1).toBeTruthy();
|
expect(context1).toBeTruthy();
|
||||||
expect(context2).toBeTruthy();
|
expect(context2).toBeTruthy();
|
||||||
expect(context1 !== context2).toBeTruthy();
|
expect(context1 !== context2).toBeTruthy();
|
||||||
expect(context1.frame()).toBe(frame1);
|
expect(context1._world?.frame()).toBe(frame1);
|
||||||
expect(context2.frame()).toBe(frame2);
|
expect(context2._world?.frame()).toBe(frame2);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
context1.evaluate(() => {
|
context1.evaluate(() => {
|
||||||
|
@ -477,7 +477,7 @@ describe('waittask specs', function () {
|
|||||||
await otherFrame.evaluate(addElement, 'div');
|
await otherFrame.evaluate(addElement, 'div');
|
||||||
await page.evaluate(addElement, 'div');
|
await page.evaluate(addElement, 'div');
|
||||||
const eHandle = await watchdog;
|
const eHandle = await watchdog;
|
||||||
expect(eHandle?.executionContext().frame()).toBe(page.mainFrame());
|
expect(eHandle?.frame).toBe(page.mainFrame());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -492,7 +492,7 @@ describe('waittask specs', function () {
|
|||||||
await frame1.evaluate(addElement, 'div');
|
await frame1.evaluate(addElement, 'div');
|
||||||
await frame2.evaluate(addElement, 'div');
|
await frame2.evaluate(addElement, 'div');
|
||||||
const eHandle = await waitForSelectorPromise;
|
const eHandle = await waitForSelectorPromise;
|
||||||
expect(eHandle?.executionContext().frame()).toBe(frame2);
|
expect(eHandle?.frame).toBe(frame2);
|
||||||
});
|
});
|
||||||
|
|
||||||
itFailsFirefox('should throw when frame is detached', async () => {
|
itFailsFirefox('should throw when frame is detached', async () => {
|
||||||
@ -749,7 +749,7 @@ describe('waittask specs', function () {
|
|||||||
await frame1.evaluate(addElement, 'div');
|
await frame1.evaluate(addElement, 'div');
|
||||||
await frame2.evaluate(addElement, 'div');
|
await frame2.evaluate(addElement, 'div');
|
||||||
const eHandle = await waitForXPathPromise;
|
const eHandle = await waitForXPathPromise;
|
||||||
expect(eHandle?.executionContext().frame()).toBe(frame2);
|
expect(eHandle?.frame).toBe(frame2);
|
||||||
});
|
});
|
||||||
itFailsFirefox('should throw when frame is detached', async () => {
|
itFailsFirefox('should throw when frame is detached', async () => {
|
||||||
const {page, server} = getTestState();
|
const {page, server} = getTestState();
|
||||||
|
Loading…
Reference in New Issue
Block a user