Module: Ferrum::Frame::Runtime

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

Constant Summary collapse

INTERMITTENT_ATTEMPTS =
ENV.fetch("FERRUM_INTERMITTENT_ATTEMPTS", 6).to_i
INTERMITTENT_SLEEP =
ENV.fetch("FERRUM_INTERMITTENT_SLEEP", 0.1).to_f
EXECUTE_OPTIONS =
{
  returnByValue: true,
  functionDeclaration: %(function() { %s })
}.freeze
DEFAULT_OPTIONS =
{
  functionDeclaration: %(function() { return %s })
}.freeze
EVALUATE_ASYNC_OPTIONS =
{
  awaitPromise: true,
  functionDeclaration: %(
    function() {
     return new Promise((__resolve, __reject) => {
       try {
         arguments[arguments.length] = r => __resolve(r);
         arguments.length = arguments.length + 1;
         setTimeout(() => __reject(new Error("timed out promise")), %s);
         %s
       } catch(error) {
         __reject(error);
       }
     });
    }
  )
}.freeze
SCRIPT_SRC_TAG =
"const script = document.createElement(\"script\");\nscript.src = arguments[0];\nscript.type = arguments[1];\nscript.onload = arguments[2];\ndocument.head.appendChild(script);\n"
SCRIPT_TEXT_TAG =
"const script = document.createElement(\"script\");\nscript.text = arguments[0];\nscript.type = arguments[1];\ndocument.head.appendChild(script);\narguments[2]();\n"
STYLE_TAG =
"const style = document.createElement(\"style\");\nstyle.type = \"text/css\";\nstyle.appendChild(document.createTextNode(arguments[0]));\ndocument.head.appendChild(style);\narguments[1]();\n"
"const link = document.createElement(\"link\");\nlink.rel = \"stylesheet\";\nlink.href = arguments[0];\nlink.onload = arguments[1];\ndocument.head.appendChild(link);\n"

Instance Method Summary collapse

Instance Method Details

#add_script_tag(url: nil, path: nil, content: nil, type: "text/javascript") ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ferrum/frame/runtime.rb', line 99

def add_script_tag(url: nil, path: nil, content: nil, type: "text/javascript")
  expr, *args = if url
                  [SCRIPT_SRC_TAG, url, type]
                elsif path || content
                  if path
                    content = File.read(path)
                    content += "\n//# sourceURL=#{path}"
                  end
                  [SCRIPT_TEXT_TAG, content, type]
                end

  evaluate_async(expr, @page.timeout, *args)
end

#add_style_tag(url: nil, path: nil, content: nil) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/ferrum/frame/runtime.rb', line 113

def add_style_tag(url: nil, path: nil, content: nil)
  expr, *args = if url
                  [LINK_TAG, url]
                elsif path || content
                  if path
                    content = File.read(path)
                    content += "\n//# sourceURL=#{path}"
                  end
                  [STYLE_TAG, content]
                end

  evaluate_async(expr, @page.timeout, *args)
end

#evaluate(expression, *args) ⇒ Object



65
66
67
# File 'lib/ferrum/frame/runtime.rb', line 65

def evaluate(expression, *args)
  call(*args, expression: expression)
end

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



69
70
71
# File 'lib/ferrum/frame/runtime.rb', line 69

def evaluate_async(expression, wait_time, *args)
  call(*args, expression: expression, wait_time: wait_time * 1000, **EVALUATE_ASYNC_OPTIONS)
end

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



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/ferrum/frame/runtime.rb', line 78

def evaluate_on(node:, expression:, by_value: true, wait: 0)
  errors = [NodeNotFoundError, NoExecutionContextError]
  attempts, sleep = INTERMITTENT_ATTEMPTS, INTERMITTENT_SLEEP

  Ferrum.with_attempts(errors: errors, max: attempts, wait: sleep) do
    response = @page.command("DOM.resolveNode", nodeId: node.node_id)
    object_id = response.dig("object", "objectId")
    options = DEFAULT_OPTIONS.merge(objectId: object_id)
    options[:functionDeclaration] = options[:functionDeclaration] % expression
    options.merge!(returnByValue: by_value)

    response = @page.command("Runtime.callFunctionOn",
                             wait: wait, slowmoable: true,
                             **options)
    handle_error(response)
    response = response["result"]

    by_value ? response.dig("value") : handle_response(response)
  end
end

#execute(expression, *args) ⇒ Object



73
74
75
76
# File 'lib/ferrum/frame/runtime.rb', line 73

def execute(expression, *args)
  call(*args, expression: expression, handle: false, **EXECUTE_OPTIONS)
  true
end