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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
get frame(): Frame {
|
||||
return this.#frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the current element for an element matching the given selector.
|
||||
*
|
||||
@ -294,8 +301,7 @@ export class ElementHandle<
|
||||
selector: Selector,
|
||||
options: Exclude<WaitForSelectorOptions, 'root'> = {}
|
||||
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||
const frame = this.executionContext().frame();
|
||||
assert(frame);
|
||||
const frame = this.#frame;
|
||||
const adoptedRoot = await frame.worlds[PUPPETEER_WORLD].adoptHandle(this);
|
||||
const handle = await frame.worlds[PUPPETEER_WORLD].waitForSelector(
|
||||
selector,
|
||||
|
@ -15,9 +15,7 @@
|
||||
*/
|
||||
|
||||
import {Protocol} from 'devtools-protocol';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {CDPSession} from './Connection.js';
|
||||
import {Frame} from './Frame.js';
|
||||
import {IsolatedWorld} from './IsolatedWorld.js';
|
||||
import {JSHandle} from './JSHandle.js';
|
||||
import {EvaluateFunc, HandleFor} from './types.js';
|
||||
@ -88,18 +86,6 @@ export class ExecutionContext {
|
||||
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.
|
||||
*
|
||||
@ -355,61 +341,24 @@ export class ExecutionContext {
|
||||
}
|
||||
return {value: arg};
|
||||
}
|
||||
|
||||
function rewriteError(error: Error): Protocol.Runtime.EvaluateResponse {
|
||||
if (error.message.includes('Object reference chain is too long')) {
|
||||
return {result: {type: 'undefined'}};
|
||||
}
|
||||
if (error.message.includes("Object couldn't be returned by value")) {
|
||||
return {result: {type: 'undefined'}};
|
||||
}
|
||||
|
||||
if (
|
||||
error.message.endsWith('Cannot find context with specified id') ||
|
||||
error.message.endsWith('Inspected target navigated or closed')
|
||||
) {
|
||||
throw new Error(
|
||||
'Execution context was destroyed, most likely because of a navigation.'
|
||||
);
|
||||
}
|
||||
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[]>;
|
||||
}
|
||||
}
|
||||
|
||||
const rewriteError = (error: Error): Protocol.Runtime.EvaluateResponse => {
|
||||
if (error.message.includes('Object reference chain is too long')) {
|
||||
return {result: {type: 'undefined'}};
|
||||
}
|
||||
if (error.message.includes("Object couldn't be returned by value")) {
|
||||
return {result: {type: 'undefined'}};
|
||||
}
|
||||
|
||||
if (
|
||||
error.message.endsWith('Cannot find context with specified id') ||
|
||||
error.message.endsWith('Inspected target navigated or closed')
|
||||
) {
|
||||
throw new Error(
|
||||
'Execution context was destroyed, most likely because of a navigation.'
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
};
|
||||
|
@ -25,7 +25,6 @@ import {ElementHandle} from './ElementHandle.js';
|
||||
import {TimeoutError} from './Errors.js';
|
||||
import {CommonEventEmitter} from './EventEmitter.js';
|
||||
import {ExecutionContext} from './ExecutionContext.js';
|
||||
import {Frame} from './Frame.js';
|
||||
import {JSHandle} from './JSHandle.js';
|
||||
|
||||
/**
|
||||
@ -218,9 +217,8 @@ export function createJSHandle(
|
||||
context: ExecutionContext,
|
||||
remoteObject: Protocol.Runtime.RemoteObject
|
||||
): JSHandle | ElementHandle<Node> {
|
||||
const frame = context.frame();
|
||||
if (remoteObject.subtype === 'node' && frame instanceof Frame) {
|
||||
return new ElementHandle(context, remoteObject, frame);
|
||||
if (remoteObject.subtype === 'node' && context._world) {
|
||||
return new ElementHandle(context, remoteObject, context._world.frame());
|
||||
}
|
||||
return new JSHandle(context, remoteObject);
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ describeChromeOnly('AriaQueryHandler', () => {
|
||||
await otherFrame!.evaluate(addElement, 'button');
|
||||
await page.evaluate(addElement, 'button');
|
||||
const elementHandle = await watchdog;
|
||||
expect(elementHandle!.executionContext().frame()).toBe(page.mainFrame());
|
||||
expect(elementHandle!.frame).toBe(page.mainFrame());
|
||||
});
|
||||
|
||||
it('should run in specified frame', async () => {
|
||||
@ -350,7 +350,7 @@ describeChromeOnly('AriaQueryHandler', () => {
|
||||
await frame1!.evaluate(addElement, 'button');
|
||||
await frame2!.evaluate(addElement, 'button');
|
||||
const elementHandle = await waitForSelectorPromise;
|
||||
expect(elementHandle!.executionContext().frame()).toBe(frame2);
|
||||
expect(elementHandle!.frame).toBe(frame2);
|
||||
});
|
||||
|
||||
it('should throw when frame is detached', async () => {
|
||||
|
@ -42,8 +42,8 @@ describe('Frame specs', function () {
|
||||
expect(context1).toBeTruthy();
|
||||
expect(context2).toBeTruthy();
|
||||
expect(context1 !== context2).toBeTruthy();
|
||||
expect(context1.frame()).toBe(frame1);
|
||||
expect(context2.frame()).toBe(frame2);
|
||||
expect(context1._world?.frame()).toBe(frame1);
|
||||
expect(context2._world?.frame()).toBe(frame2);
|
||||
|
||||
await Promise.all([
|
||||
context1.evaluate(() => {
|
||||
|
@ -477,7 +477,7 @@ describe('waittask specs', function () {
|
||||
await otherFrame.evaluate(addElement, 'div');
|
||||
await page.evaluate(addElement, 'div');
|
||||
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 frame2.evaluate(addElement, 'div');
|
||||
const eHandle = await waitForSelectorPromise;
|
||||
expect(eHandle?.executionContext().frame()).toBe(frame2);
|
||||
expect(eHandle?.frame).toBe(frame2);
|
||||
});
|
||||
|
||||
itFailsFirefox('should throw when frame is detached', async () => {
|
||||
@ -749,7 +749,7 @@ describe('waittask specs', function () {
|
||||
await frame1.evaluate(addElement, 'div');
|
||||
await frame2.evaluate(addElement, 'div');
|
||||
const eHandle = await waitForXPathPromise;
|
||||
expect(eHandle?.executionContext().frame()).toBe(frame2);
|
||||
expect(eHandle?.frame).toBe(frame2);
|
||||
});
|
||||
itFailsFirefox('should throw when frame is detached', async () => {
|
||||
const {page, server} = getTestState();
|
||||
|
Loading…
Reference in New Issue
Block a user