chore: expose utility script to inner evaluates (#19147)
This commit is contained in:
parent
89bdaf2441
commit
5ac426b3d5
|
|
@ -187,6 +187,12 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
|
|||
return parseResult(result.value);
|
||||
}
|
||||
|
||||
async _evaluateExposeUtilityScript<R, Arg>(pageFunction: structs.PageFunction<Arg, R>, arg?: Arg): Promise<R> {
|
||||
assertMaxArguments(arguments.length, 2);
|
||||
const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', exposeUtilityScript: true, arg: serializeArgument(arg) });
|
||||
return parseResult(result.value);
|
||||
}
|
||||
|
||||
async $(selector: string, options?: { strict?: boolean }): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
||||
const result = await this._channel.querySelector({ selector, ...options });
|
||||
return ElementHandle.fromNullable(result.element) as ElementHandle<SVGElement | HTMLElement> | null;
|
||||
|
|
|
|||
|
|
@ -1295,6 +1295,7 @@ scheme.FrameDispatchEventResult = tOptional(tObject({}));
|
|||
scheme.FrameEvaluateExpressionParams = tObject({
|
||||
expression: tString,
|
||||
isFunction: tOptional(tBoolean),
|
||||
exposeUtilityScript: tOptional(tBoolean),
|
||||
arg: tType('SerializedArgument'),
|
||||
});
|
||||
scheme.FrameEvaluateExpressionResult = tObject({
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ export class FrameDispatcher extends Dispatcher<Frame, channels.FrameChannel, Pa
|
|||
}
|
||||
|
||||
async evaluateExpression(params: channels.FrameEvaluateExpressionParams, metadata: CallMetadata): Promise<channels.FrameEvaluateExpressionResult> {
|
||||
return { value: serializeResult(await this._frame.evaluateExpressionAndWaitForSignals(params.expression, params.isFunction, parseArgument(params.arg), 'main')) };
|
||||
return { value: serializeResult(await this._frame.evaluateExpressionAndWaitForSignals(params.expression, { isFunction: params.isFunction, exposeUtilityScript: params.exposeUtilityScript }, parseArgument(params.arg), 'main')) };
|
||||
}
|
||||
|
||||
async evaluateExpressionHandle(params: channels.FrameEvaluateExpressionHandleParams, metadata: CallMetadata): Promise<channels.FrameEvaluateExpressionHandleResult> {
|
||||
|
|
|
|||
|
|
@ -71,19 +71,19 @@ export class FrameExecutionContext extends js.ExecutionContext {
|
|||
return js.evaluate(this, false /* returnByValue */, pageFunction, arg);
|
||||
}
|
||||
|
||||
async evaluateExpression(expression: string, isFunction: boolean | undefined, arg?: any): Promise<any> {
|
||||
return js.evaluateExpression(this, true /* returnByValue */, expression, isFunction, arg);
|
||||
async evaluateExpression(expression: string, options: { isFunction?: boolean, exposeUtilityScript?: boolean }, arg?: any): Promise<any> {
|
||||
return js.evaluateExpression(this, expression, { ...options, returnByValue: true }, arg);
|
||||
}
|
||||
|
||||
async evaluateExpressionAndWaitForSignals(expression: string, isFunction: boolean | undefined, arg?: any): Promise<any> {
|
||||
async evaluateExpressionAndWaitForSignals(expression: string, options: { isFunction?: boolean, exposeUtilityScript?: boolean }, arg?: any): Promise<any> {
|
||||
return await this.frame._page._frameManager.waitForSignalsCreatedBy(null, false /* noWaitFor */, async () => {
|
||||
return this.evaluateExpression(expression, isFunction, arg);
|
||||
return this.evaluateExpression(expression, options, arg);
|
||||
});
|
||||
}
|
||||
|
||||
async evaluateExpressionHandleAndWaitForSignals(expression: string, isFunction: boolean | undefined, arg: any): Promise<any> {
|
||||
async evaluateExpressionHandleAndWaitForSignals(expression: string, options: { isFunction?: boolean, exposeUtilityScript?: boolean }, arg: any): Promise<any> {
|
||||
return await this.frame._page._frameManager.waitForSignalsCreatedBy(null, false /* noWaitFor */, async () => {
|
||||
return js.evaluateExpression(this, false /* returnByValue */, expression, isFunction, arg);
|
||||
return js.evaluateExpression(this, expression, { ...options, returnByValue: false }, arg);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -595,12 +595,12 @@ export class Frame extends SdkObject {
|
|||
});
|
||||
}
|
||||
|
||||
nonStallingEvaluateInExistingContext(expression: string, isFunction: boolean|undefined, world: types.World): Promise<any> {
|
||||
nonStallingEvaluateInExistingContext(expression: string, isFunction: boolean | undefined, world: types.World): Promise<any> {
|
||||
return this.raceAgainstEvaluationStallingEvents(() => {
|
||||
const context = this._contextData.get(world)?.context;
|
||||
if (!context)
|
||||
throw new Error('Frame does not yet have the execution context');
|
||||
return context.evaluateExpression(expression, isFunction);
|
||||
return context.evaluateExpression(expression, { isFunction });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -763,19 +763,19 @@ export class Frame extends SdkObject {
|
|||
|
||||
async evaluateExpressionHandleAndWaitForSignals(expression: string, isFunction: boolean | undefined, arg: any, world: types.World = 'main'): Promise<any> {
|
||||
const context = await this._context(world);
|
||||
const handle = await context.evaluateExpressionHandleAndWaitForSignals(expression, isFunction, arg);
|
||||
const handle = await context.evaluateExpressionHandleAndWaitForSignals(expression, { isFunction }, arg);
|
||||
return handle;
|
||||
}
|
||||
|
||||
async evaluateExpression(expression: string, isFunction: boolean | undefined, arg: any, world: types.World = 'main'): Promise<any> {
|
||||
const context = await this._context(world);
|
||||
const value = await context.evaluateExpression(expression, isFunction, arg);
|
||||
const value = await context.evaluateExpression(expression, { isFunction }, arg);
|
||||
return value;
|
||||
}
|
||||
|
||||
async evaluateExpressionAndWaitForSignals(expression: string, isFunction: boolean | undefined, arg: any, world: types.World = 'main'): Promise<any> {
|
||||
async evaluateExpressionAndWaitForSignals(expression: string, options: { isFunction?: boolean, exposeUtilityScript?: boolean }, arg: any, world: types.World = 'main'): Promise<any> {
|
||||
const context = await this._context(world);
|
||||
const value = await context.evaluateExpressionAndWaitForSignals(expression, isFunction, arg);
|
||||
const value = await context.evaluateExpressionAndWaitForSignals(expression, options, arg);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,16 @@
|
|||
import { serializeAsCallArgument, parseEvaluationResultValue } from '../isomorphic/utilityScriptSerializers';
|
||||
|
||||
export class UtilityScript {
|
||||
evaluate(isFunction: boolean | undefined, returnByValue: boolean, expression: string, argCount: number, ...argsAndHandles: any[]) {
|
||||
serializeAsCallArgument = serializeAsCallArgument;
|
||||
parseEvaluationResultValue = parseEvaluationResultValue;
|
||||
|
||||
evaluate(isFunction: boolean | undefined, returnByValue: boolean, exposeUtilityScript: boolean | undefined, expression: string, argCount: number, ...argsAndHandles: any[]) {
|
||||
const args = argsAndHandles.slice(0, argCount);
|
||||
const handles = argsAndHandles.slice(argCount);
|
||||
const parameters = args.map(a => parseEvaluationResultValue(a, handles));
|
||||
if (exposeUtilityScript)
|
||||
parameters.unshift(this);
|
||||
|
||||
let result = globalThis.eval(expression);
|
||||
if (isFunction === true) {
|
||||
result = result(...parameters);
|
||||
|
|
|
|||
|
|
@ -226,12 +226,12 @@ export class JSHandle<T = any> extends SdkObject {
|
|||
}
|
||||
|
||||
export async function evaluate(context: ExecutionContext, returnByValue: boolean, pageFunction: Function | string, ...args: any[]): Promise<any> {
|
||||
return evaluateExpression(context, returnByValue, String(pageFunction), typeof pageFunction === 'function', ...args);
|
||||
return evaluateExpression(context, String(pageFunction), { returnByValue, isFunction: typeof pageFunction === 'function' }, ...args);
|
||||
}
|
||||
|
||||
export async function evaluateExpression(context: ExecutionContext, returnByValue: boolean, expression: string, isFunction: boolean | undefined, ...args: any[]): Promise<any> {
|
||||
export async function evaluateExpression(context: ExecutionContext, expression: string, options: { returnByValue?: boolean, isFunction?: boolean, exposeUtilityScript?: boolean }, ...args: any[]): Promise<any> {
|
||||
const utilityScript = await context.utilityScript();
|
||||
expression = normalizeEvaluationExpression(expression, isFunction);
|
||||
expression = normalizeEvaluationExpression(expression, options.isFunction);
|
||||
const handles: (Promise<JSHandle>)[] = [];
|
||||
const toDispose: Promise<JSHandle>[] = [];
|
||||
const pushHandle = (handle: Promise<JSHandle>): number => {
|
||||
|
|
@ -262,18 +262,18 @@ export async function evaluateExpression(context: ExecutionContext, returnByValu
|
|||
}
|
||||
|
||||
// See UtilityScript for arguments.
|
||||
const utilityScriptValues = [isFunction, returnByValue, expression, args.length, ...args];
|
||||
const utilityScriptValues = [options.isFunction, options.returnByValue, options.exposeUtilityScript, expression, args.length, ...args];
|
||||
|
||||
const script = `(utilityScript, ...args) => utilityScript.evaluate(...args)`;
|
||||
try {
|
||||
return await context.evaluateWithArguments(script, returnByValue, utilityScript, utilityScriptValues, utilityScriptObjectIds);
|
||||
return await context.evaluateWithArguments(script, options.returnByValue || false, utilityScript, utilityScriptValues, utilityScriptObjectIds);
|
||||
} finally {
|
||||
toDispose.map(handlePromise => handlePromise.then(handle => handle.dispose()));
|
||||
}
|
||||
}
|
||||
|
||||
export async function evaluateExpressionAndWaitForSignals(context: ExecutionContext, returnByValue: boolean, expression: string, isFunction?: boolean, ...args: any[]): Promise<any> {
|
||||
return await context.waitForSignalsCreatedBy(() => evaluateExpression(context, returnByValue, expression, isFunction, ...args));
|
||||
export async function evaluateExpressionAndWaitForSignals(context: ExecutionContext, returnByValue: boolean, expression: string, isFunction: boolean | undefined, ...args: any[]): Promise<any> {
|
||||
return await context.waitForSignalsCreatedBy(() => evaluateExpression(context, expression, { returnByValue, isFunction }, ...args));
|
||||
}
|
||||
|
||||
export function parseUnserializableValue(unserializableValue: string): any {
|
||||
|
|
|
|||
|
|
@ -724,11 +724,11 @@ export class Worker extends SdkObject {
|
|||
}
|
||||
|
||||
async evaluateExpression(expression: string, isFunction: boolean | undefined, arg: any): Promise<any> {
|
||||
return js.evaluateExpression(await this._executionContextPromise, true /* returnByValue */, expression, isFunction, arg);
|
||||
return js.evaluateExpression(await this._executionContextPromise, expression, { returnByValue: true, isFunction }, arg);
|
||||
}
|
||||
|
||||
async evaluateExpressionHandle(expression: string, isFunction: boolean | undefined, arg: any): Promise<any> {
|
||||
return js.evaluateExpression(await this._executionContextPromise, false /* returnByValue */, expression, isFunction, arg);
|
||||
return js.evaluateExpression(await this._executionContextPromise, expression, { returnByValue: false, isFunction }, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2392,10 +2392,12 @@ export type FrameDispatchEventResult = void;
|
|||
export type FrameEvaluateExpressionParams = {
|
||||
expression: string,
|
||||
isFunction?: boolean,
|
||||
exposeUtilityScript?: boolean,
|
||||
arg: SerializedArgument,
|
||||
};
|
||||
export type FrameEvaluateExpressionOptions = {
|
||||
isFunction?: boolean,
|
||||
exposeUtilityScript?: boolean,
|
||||
};
|
||||
export type FrameEvaluateExpressionResult = {
|
||||
value: SerializedValue,
|
||||
|
|
|
|||
|
|
@ -1739,6 +1739,7 @@ Frame:
|
|||
parameters:
|
||||
expression: string
|
||||
isFunction: boolean?
|
||||
exposeUtilityScript: boolean?
|
||||
arg: SerializedArgument
|
||||
returns:
|
||||
value: SerializedValue
|
||||
|
|
|
|||
|
|
@ -702,3 +702,13 @@ it('should work with overridden globalThis.Window/Document/Node', async ({ page,
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('should expose utilityScript', async ({ page }) => {
|
||||
const result = await (page.mainFrame() as any)._evaluateExposeUtilityScript((utilityScript, { a }) => {
|
||||
return { utils: 'parseEvaluationResultValue' in utilityScript, a };
|
||||
}, { a: 42 });
|
||||
expect(result).toEqual({
|
||||
a: 42,
|
||||
utils: true,
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue