Module: Ferrum::Frame::Runtime

Included in:
Ferrum::Frame, Worker
Defined in:
lib/ferrum/frame/runtime.rb

Overview

Evaluates and executes JavaScript in a frame's execution context via Runtime.callFunctionOn, converting arguments and return values between Ruby and JS, and resolving object/array/node results (including cyclic ones, via CyclicObject) into Ruby equivalents.

Constant Summary collapse

INTERMITTENT_ATTEMPTS =
ENV.fetch("FERRUM_INTERMITTENT_ATTEMPTS", 6).to_i
INTERMITTENT_SLEEP =
ENV.fetch("FERRUM_INTERMITTENT_SLEEP", 0.1).to_f

Instance Method Summary collapse

Instance Method Details

#evaluate(expression, *args) ⇒ Object

Evaluate and return result for given JS expression.

Examples:

browser.evaluate("[window.scrollX, window.scrollY]")

Parameters:

  • expression (String)

    The JavaScript to evaluate.

  • args (Array)

    Additional arguments to pass to the JavaScript code.



46
47
48
49
# File 'lib/ferrum/frame/runtime.rb', line 46

def evaluate(expression, *args)
  expression = format("function() { return %s }", expression)
  call(expression: expression, arguments: args)
end

#evaluate_async(expression, wait, *args) ⇒ Object

Evaluate asynchronous expression and return result.

Examples:

browser.evaluate_async(%(arguments[0]({foo: "bar"})), 5) # => { "foo" => "bar" }

Parameters:

  • expression (String)

    The JavaScript to evaluate.

  • wait (Integer)

    How long we should wait for Promise to resolve or reject.

  • args (Array)

    Additional arguments to pass to the JavaScript code.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/ferrum/frame/runtime.rb', line 66

def evaluate_async(expression, wait, *args)
  template = "    function() {\n      return new Promise((__f, __r) => {\n        try {\n          arguments[arguments.length] = r => __f(r);\n          arguments.length = arguments.length + 1;\n          setTimeout(() => __r(new Error(\"timed out promise\")), %s);\n          %s\n        } catch(error) {\n          __r(error);\n        }\n      });\n    }\n  JS\n\n  expression = format(template, wait * 1000, expression)\n  call(expression: expression, arguments: args, awaitPromise: true)\nend\n"

#evaluate_func(expression, *args, on: nil) ⇒ Object

Evaluates a raw JS function declaration (unlike #evaluate, which wraps the given expression in one), optionally on a specific remote object instead of the frame's global execution context.

Parameters:

  • expression (String)

    A JS function declaration, e.g. "function(a, b) { return a + b }".

  • args (Array)

    Arguments to pass to the function.

  • on (Node, nil) (defaults to: nil)

    Remote object to invoke the function on.



118
119
120
# File 'lib/ferrum/frame/runtime.rb', line 118

def evaluate_func(expression, *args, on: nil)
  call(expression: expression, arguments: args, on: on)
end

#evaluate_on(node:, expression:, by_value: true, wait: 0) ⇒ Object

Evaluates an expression against a given node's remote object (+this+ refers to the node), returning the raw JS value rather than resolving it to a Node/Hash/Array.

Parameters:

  • node (Node)

    The node to evaluate the expression on.

  • expression (String)

    The JavaScript to evaluate.

  • by_value (Boolean) (defaults to: true)

    Whether to return the plain JS value instead of a handle.

  • wait (Integer) (defaults to: 0)

    Passed through to the underlying Runtime.callFunctionOn command.



139
140
141
142
143
144
# File 'lib/ferrum/frame/runtime.rb', line 139

def evaluate_on(node:, expression:, by_value: true, wait: 0)
  options = { handle: true }
  expression = format("function() { return %s }", expression)
  options = { handle: false, returnByValue: true } if by_value
  call(expression: expression, on: node, wait: wait, **options)
end

#execute(expression, *args) ⇒ Object

Execute expression. Doesn't return the result.

Examples:

browser.execute(%(1 + 1)) # => true

Parameters:

  • expression (String)

    The JavaScript to evaluate.

  • args (Array)

    Additional arguments to pass to the JavaScript code.



98
99
100
101
102
# File 'lib/ferrum/frame/runtime.rb', line 98

def execute(expression, *args)
  expression = format("function() { %s }", expression)
  call(expression: expression, arguments: args, handle: false, returnByValue: true)
  true
end