mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	fix(waitForFunction): process isFunction auto-detection (#5312)
This commit is contained in:
		
							parent
							
								
									17986773f8
								
							
						
					
					
						commit
						c2b8718bae
					
				@ -1019,13 +1019,25 @@ export class Frame extends EventEmitter {
 | 
				
			|||||||
  async _waitForFunctionExpression<R>(expression: string, isFunction: boolean | undefined, arg: any, options: types.WaitForFunctionOptions = {}): Promise<js.SmartHandle<R>> {
 | 
					  async _waitForFunctionExpression<R>(expression: string, isFunction: boolean | undefined, arg: any, options: types.WaitForFunctionOptions = {}): Promise<js.SmartHandle<R>> {
 | 
				
			||||||
    if (typeof options.pollingInterval === 'number')
 | 
					    if (typeof options.pollingInterval === 'number')
 | 
				
			||||||
      assert(options.pollingInterval > 0, 'Cannot poll with non-positive interval: ' + options.pollingInterval);
 | 
					      assert(options.pollingInterval > 0, 'Cannot poll with non-positive interval: ' + options.pollingInterval);
 | 
				
			||||||
    const predicateBody = isFunction ? 'return (' + expression + ')(arg)' :  'return (' + expression + ')';
 | 
					    expression = js.normalizeEvaluationExpression(expression, isFunction);
 | 
				
			||||||
    const task: dom.SchedulableTask<R> = injectedScript => injectedScript.evaluateHandle((injectedScript, { predicateBody, polling, arg }) => {
 | 
					    const task: dom.SchedulableTask<R> = injectedScript => injectedScript.evaluateHandle((injectedScript, { expression, isFunction, polling, arg }) => {
 | 
				
			||||||
      const innerPredicate = new Function('arg', predicateBody) as (arg: any) => R;
 | 
					      const predicate = (arg: any): R => {
 | 
				
			||||||
 | 
					        let result = self.eval(expression);
 | 
				
			||||||
 | 
					        if (isFunction === true) {
 | 
				
			||||||
 | 
					          result = result(arg);
 | 
				
			||||||
 | 
					        } else if (isFunction === false) {
 | 
				
			||||||
 | 
					          result = result;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          // auto detect.
 | 
				
			||||||
 | 
					          if (typeof result === 'function')
 | 
				
			||||||
 | 
					            result = result(arg);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
      if (typeof polling !== 'number')
 | 
					      if (typeof polling !== 'number')
 | 
				
			||||||
        return injectedScript.pollRaf((progress, continuePolling) => innerPredicate(arg) || continuePolling);
 | 
					        return injectedScript.pollRaf((progress, continuePolling) => predicate(arg) || continuePolling);
 | 
				
			||||||
      return injectedScript.pollInterval(polling, (progress, continuePolling) => innerPredicate(arg) || continuePolling);
 | 
					      return injectedScript.pollInterval(polling, (progress, continuePolling) => predicate(arg) || continuePolling);
 | 
				
			||||||
    }, { predicateBody, polling: options.pollingInterval, arg });
 | 
					    }, { expression, isFunction, polling: options.pollingInterval, arg });
 | 
				
			||||||
    return runAbortableTask(
 | 
					    return runAbortableTask(
 | 
				
			||||||
        progress => this._scheduleRerunnableHandleTask(progress, 'main', task),
 | 
					        progress => this._scheduleRerunnableHandleTask(progress, 'main', task),
 | 
				
			||||||
        this._page._timeoutSettings.timeout(options));
 | 
					        this._page._timeoutSettings.timeout(options));
 | 
				
			||||||
 | 
				
			|||||||
@ -21,9 +21,6 @@ export default class UtilityScript {
 | 
				
			|||||||
    const args = argsAndHandles.slice(0, argCount);
 | 
					    const args = argsAndHandles.slice(0, argCount);
 | 
				
			||||||
    const handles = argsAndHandles.slice(argCount);
 | 
					    const handles = argsAndHandles.slice(argCount);
 | 
				
			||||||
    const parameters = args.map(a => parseEvaluationResultValue(a, handles));
 | 
					    const parameters = args.map(a => parseEvaluationResultValue(a, handles));
 | 
				
			||||||
    expression = expression.trim();
 | 
					 | 
				
			||||||
    if (/^(async)?\s*function(\s|\()/.test(expression))
 | 
					 | 
				
			||||||
      expression = '(' + expression + ')';
 | 
					 | 
				
			||||||
    let result = global.eval(expression);
 | 
					    let result = global.eval(expression);
 | 
				
			||||||
    if (isFunction === true) {
 | 
					    if (isFunction === true) {
 | 
				
			||||||
      result = result(...parameters);
 | 
					      result = result(...parameters);
 | 
				
			||||||
 | 
				
			|||||||
@ -175,26 +175,7 @@ export async function evaluate(context: ExecutionContext, returnByValue: boolean
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export async function evaluateExpression(context: ExecutionContext, returnByValue: boolean, expression: string, isFunction: boolean | undefined, ...args: any[]): Promise<any> {
 | 
					export async function evaluateExpression(context: ExecutionContext, returnByValue: boolean, expression: string, isFunction: boolean | undefined, ...args: any[]): Promise<any> {
 | 
				
			||||||
  const utilityScript = await context.utilityScript();
 | 
					  const utilityScript = await context.utilityScript();
 | 
				
			||||||
 | 
					  expression = normalizeEvaluationExpression(expression, isFunction);
 | 
				
			||||||
  if (isFunction) {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      new Function('(' + expression + ')');
 | 
					 | 
				
			||||||
    } catch (e1) {
 | 
					 | 
				
			||||||
      // This means we might have a function shorthand. Try another
 | 
					 | 
				
			||||||
      // time prefixing 'function '.
 | 
					 | 
				
			||||||
      if (expression.startsWith('async '))
 | 
					 | 
				
			||||||
        expression = 'async function ' + expression.substring('async '.length);
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        expression = 'function ' + expression;
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        new Function('(' + expression  + ')');
 | 
					 | 
				
			||||||
      } catch (e2) {
 | 
					 | 
				
			||||||
        // We tried hard to serialize, but there's a weird beast here.
 | 
					 | 
				
			||||||
        throw new Error('Passed function is not well-serializable!');
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handles: (Promise<JSHandle>)[] = [];
 | 
					  const handles: (Promise<JSHandle>)[] = [];
 | 
				
			||||||
  const toDispose: Promise<JSHandle>[] = [];
 | 
					  const toDispose: Promise<JSHandle>[] = [];
 | 
				
			||||||
  const pushHandle = (handle: Promise<JSHandle>): number => {
 | 
					  const pushHandle = (handle: Promise<JSHandle>): number => {
 | 
				
			||||||
@ -245,3 +226,30 @@ export function parseUnserializableValue(unserializableValue: string): any {
 | 
				
			|||||||
  if (unserializableValue === '-0')
 | 
					  if (unserializableValue === '-0')
 | 
				
			||||||
    return -0;
 | 
					    return -0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function normalizeEvaluationExpression(expression: string, isFunction: boolean | undefined): string {
 | 
				
			||||||
 | 
					  expression = expression.trim();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (isFunction) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      new Function('(' + expression + ')');
 | 
				
			||||||
 | 
					    } catch (e1) {
 | 
				
			||||||
 | 
					      // This means we might have a function shorthand. Try another
 | 
				
			||||||
 | 
					      // time prefixing 'function '.
 | 
				
			||||||
 | 
					      if (expression.startsWith('async '))
 | 
				
			||||||
 | 
					        expression = 'async function ' + expression.substring('async '.length);
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        expression = 'function ' + expression;
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        new Function('(' + expression  + ')');
 | 
				
			||||||
 | 
					      } catch (e2) {
 | 
				
			||||||
 | 
					        // We tried hard to serialize, but there's a weird beast here.
 | 
				
			||||||
 | 
					        throw new Error('Passed function is not well-serializable!');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (/^(async)?\s*function(\s|\()/.test(expression))
 | 
				
			||||||
 | 
					    expression = '(' + expression + ')';
 | 
				
			||||||
 | 
					  return expression;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user