ferrum 0.12 → 0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -22
- data/lib/ferrum/browser/client.rb +6 -5
- data/lib/ferrum/browser/command.rb +9 -6
- data/lib/ferrum/browser/options/base.rb +1 -4
- data/lib/ferrum/browser/options/chrome.rb +22 -10
- data/lib/ferrum/browser/options/firefox.rb +3 -6
- data/lib/ferrum/browser/options.rb +84 -0
- data/lib/ferrum/browser/process.rb +6 -7
- data/lib/ferrum/browser/version_info.rb +71 -0
- data/lib/ferrum/browser/web_socket.rb +1 -1
- data/lib/ferrum/browser/xvfb.rb +1 -1
- data/lib/ferrum/browser.rb +184 -64
- data/lib/ferrum/context.rb +3 -2
- data/lib/ferrum/contexts.rb +2 -2
- data/lib/ferrum/cookies/cookie.rb +183 -0
- data/lib/ferrum/cookies.rb +122 -49
- data/lib/ferrum/dialog.rb +30 -0
- data/lib/ferrum/frame/dom.rb +177 -0
- data/lib/ferrum/frame/runtime.rb +41 -61
- data/lib/ferrum/frame.rb +91 -3
- data/lib/ferrum/headers.rb +28 -0
- data/lib/ferrum/keyboard.rb +45 -2
- data/lib/ferrum/mouse.rb +84 -0
- data/lib/ferrum/network/exchange.rb +104 -5
- data/lib/ferrum/network/intercepted_request.rb +3 -12
- data/lib/ferrum/network/request.rb +58 -19
- data/lib/ferrum/network/request_params.rb +57 -0
- data/lib/ferrum/network/response.rb +106 -4
- data/lib/ferrum/network.rb +193 -8
- data/lib/ferrum/node.rb +21 -1
- data/lib/ferrum/page/animation.rb +16 -0
- data/lib/ferrum/page/frames.rb +66 -11
- data/lib/ferrum/page/screenshot.rb +97 -0
- data/lib/ferrum/page/tracing.rb +26 -0
- data/lib/ferrum/page.rb +158 -45
- data/lib/ferrum/proxy.rb +91 -2
- data/lib/ferrum/target.rb +6 -4
- data/lib/ferrum/version.rb +1 -1
- metadata +7 -101
data/lib/ferrum/cookies.rb
CHANGED
@@ -1,68 +1,119 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ferrum/cookies/cookie"
|
4
|
+
|
3
5
|
module Ferrum
|
4
6
|
class Cookies
|
5
|
-
|
6
|
-
attr_reader :attributes
|
7
|
-
|
8
|
-
def initialize(attributes)
|
9
|
-
@attributes = attributes
|
10
|
-
end
|
11
|
-
|
12
|
-
def name
|
13
|
-
@attributes["name"]
|
14
|
-
end
|
15
|
-
|
16
|
-
def value
|
17
|
-
@attributes["value"]
|
18
|
-
end
|
19
|
-
|
20
|
-
def domain
|
21
|
-
@attributes["domain"]
|
22
|
-
end
|
23
|
-
|
24
|
-
def path
|
25
|
-
@attributes["path"]
|
26
|
-
end
|
27
|
-
|
28
|
-
def samesite
|
29
|
-
@attributes["sameSite"]
|
30
|
-
end
|
31
|
-
|
32
|
-
def size
|
33
|
-
@attributes["size"]
|
34
|
-
end
|
7
|
+
include Enumerable
|
35
8
|
|
36
|
-
|
37
|
-
|
38
|
-
|
9
|
+
def initialize(page)
|
10
|
+
@page = page
|
11
|
+
end
|
39
12
|
|
40
|
-
|
41
|
-
|
42
|
-
|
13
|
+
#
|
14
|
+
# Enumerates over all cookies.
|
15
|
+
#
|
16
|
+
# @yield [cookie]
|
17
|
+
# The given block will be passed each cookie.
|
18
|
+
#
|
19
|
+
# @yieldparam [Cookie] cookie
|
20
|
+
# A cookie in the browser.
|
21
|
+
#
|
22
|
+
# @return [Enumerator]
|
23
|
+
# If no block is given, an Enumerator object will be returned.
|
24
|
+
#
|
25
|
+
def each
|
26
|
+
return enum_for(__method__) unless block_given?
|
43
27
|
|
44
|
-
|
45
|
-
@attributes["session"]
|
46
|
-
end
|
28
|
+
cookies = @page.command("Network.getAllCookies")["cookies"]
|
47
29
|
|
48
|
-
|
49
|
-
|
30
|
+
cookies.each do |c|
|
31
|
+
yield Cookie.new(c)
|
50
32
|
end
|
51
33
|
end
|
52
34
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
35
|
+
#
|
36
|
+
# Returns cookies hash.
|
37
|
+
#
|
38
|
+
# @return [Hash{String => Cookie}]
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# browser.cookies.all # => {
|
42
|
+
# # "NID" => #<Ferrum::Cookies::Cookie:0x0000558624b37a40 @attributes={
|
43
|
+
# # "name"=>"NID", "value"=>"...", "domain"=>".google.com", "path"=>"/",
|
44
|
+
# # "expires"=>1583211046.575681, "size"=>178, "httpOnly"=>true, "secure"=>false, "session"=>false
|
45
|
+
# # }>
|
46
|
+
# # }
|
47
|
+
#
|
57
48
|
def all
|
58
|
-
|
59
|
-
|
49
|
+
each.to_h do |cookie|
|
50
|
+
[cookie.name, cookie]
|
51
|
+
end
|
60
52
|
end
|
61
53
|
|
54
|
+
#
|
55
|
+
# Returns cookie.
|
56
|
+
#
|
57
|
+
# @param [String] name
|
58
|
+
# The cookie name to fetch.
|
59
|
+
#
|
60
|
+
# @return [Cookie, nil]
|
61
|
+
# The cookie with the matching name.
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# browser.cookies["NID"] # =>
|
65
|
+
# # <Ferrum::Cookies::Cookie:0x0000558624b67a88 @attributes={
|
66
|
+
# # "name"=>"NID", "value"=>"...", "domain"=>".google.com",
|
67
|
+
# # "path"=>"/", "expires"=>1583211046.575681, "size"=>178,
|
68
|
+
# # "httpOnly"=>true, "secure"=>false, "session"=>false
|
69
|
+
# # }>
|
70
|
+
#
|
62
71
|
def [](name)
|
63
|
-
|
72
|
+
find { |cookie| cookie.name == name }
|
64
73
|
end
|
65
74
|
|
75
|
+
#
|
76
|
+
# Sets a cookie.
|
77
|
+
#
|
78
|
+
# @param [Hash{Symbol => Object}, Cookie] options
|
79
|
+
#
|
80
|
+
# @option options [String] :name
|
81
|
+
# The cookie param name.
|
82
|
+
#
|
83
|
+
# @option options [String] :value
|
84
|
+
# The cookie param value.
|
85
|
+
#
|
86
|
+
# @option options [String] :domain
|
87
|
+
# The domain the cookie belongs to.
|
88
|
+
#
|
89
|
+
# @option options [String] :path
|
90
|
+
# The path that the cookie is bound to.
|
91
|
+
#
|
92
|
+
# @option options [Integer] :expires
|
93
|
+
# When the cookie will expire.
|
94
|
+
#
|
95
|
+
# @option options [Integer] :size
|
96
|
+
# The size of the cookie.
|
97
|
+
#
|
98
|
+
# @option options [Boolean] :httponly
|
99
|
+
# Specifies whether the cookie `HttpOnly`.
|
100
|
+
#
|
101
|
+
# @option options [Boolean] :secure
|
102
|
+
# Specifies whether the cookie is marked as `Secure`.
|
103
|
+
#
|
104
|
+
# @option options [String] :samesite
|
105
|
+
# Specifies whether the cookie is `SameSite`.
|
106
|
+
#
|
107
|
+
# @option options [Boolean] :session
|
108
|
+
# Specifies whether the cookie is a session cookie.
|
109
|
+
#
|
110
|
+
# @example
|
111
|
+
# browser.cookies.set(name: "stealth", value: "omg", domain: "google.com") # => true
|
112
|
+
#
|
113
|
+
# @example
|
114
|
+
# nid_cookie = browser.cookies["NID"] # => <Ferrum::Cookies::Cookie:0x0000558624b67a88>
|
115
|
+
# browser.cookies.set(nid_cookie) # => true
|
116
|
+
#
|
66
117
|
def set(options)
|
67
118
|
cookie = (
|
68
119
|
options.is_a?(Cookie) ? options.attributes : options
|
@@ -79,7 +130,21 @@ module Ferrum
|
|
79
130
|
@page.command("Network.setCookie", **cookie)["success"]
|
80
131
|
end
|
81
132
|
|
82
|
-
#
|
133
|
+
#
|
134
|
+
# Removes given cookie.
|
135
|
+
#
|
136
|
+
# @param [String] name
|
137
|
+
#
|
138
|
+
# @param [Hash{Symbol => Object}] options
|
139
|
+
# Additional keyword arguments.
|
140
|
+
#
|
141
|
+
# @option options [String] :domain
|
142
|
+
#
|
143
|
+
# @option options [String] :url
|
144
|
+
#
|
145
|
+
# @example
|
146
|
+
# browser.cookies.remove(name: "stealth", domain: "google.com") # => true
|
147
|
+
#
|
83
148
|
def remove(name:, **options)
|
84
149
|
raise "Specify :domain or :url option" if !options[:domain] && !options[:url] && !default_domain
|
85
150
|
|
@@ -91,6 +156,14 @@ module Ferrum
|
|
91
156
|
true
|
92
157
|
end
|
93
158
|
|
159
|
+
#
|
160
|
+
# Removes all cookies for current page.
|
161
|
+
#
|
162
|
+
# @return [true]
|
163
|
+
#
|
164
|
+
# @example
|
165
|
+
# browser.cookies.clear # => true
|
166
|
+
#
|
94
167
|
def clear
|
95
168
|
@page.command("Network.clearBrowserCookies")
|
96
169
|
true
|
data/lib/ferrum/dialog.rb
CHANGED
@@ -10,6 +10,22 @@ module Ferrum
|
|
10
10
|
@default_prompt = params["defaultPrompt"]
|
11
11
|
end
|
12
12
|
|
13
|
+
#
|
14
|
+
# Accept dialog with given text or default prompt if applicable
|
15
|
+
#
|
16
|
+
# @param [String, nil] prompt_text
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# browser = Ferrum::Browser.new
|
20
|
+
# browser.on(:dialog) do |dialog|
|
21
|
+
# if dialog.match?(/bla-bla/)
|
22
|
+
# dialog.accept
|
23
|
+
# else
|
24
|
+
# dialog.dismiss
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# browser.go_to("https://google.com")
|
28
|
+
#
|
13
29
|
def accept(prompt_text = nil)
|
14
30
|
options = { accept: true }
|
15
31
|
response = prompt_text || default_prompt
|
@@ -17,6 +33,20 @@ module Ferrum
|
|
17
33
|
@page.command("Page.handleJavaScriptDialog", slowmoable: true, **options)
|
18
34
|
end
|
19
35
|
|
36
|
+
#
|
37
|
+
# Dismiss dialog.
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# browser = Ferrum::Browser.new
|
41
|
+
# browser.on(:dialog) do |dialog|
|
42
|
+
# if dialog.match?(/bla-bla/)
|
43
|
+
# dialog.accept
|
44
|
+
# else
|
45
|
+
# dialog.dismiss
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
# browser.go_to("https://google.com")
|
49
|
+
#
|
20
50
|
def dismiss
|
21
51
|
@page.command("Page.handleJavaScriptDialog", slowmoable: true, accept: false)
|
22
52
|
end
|
data/lib/ferrum/frame/dom.rb
CHANGED
@@ -20,10 +20,59 @@
|
|
20
20
|
module Ferrum
|
21
21
|
class Frame
|
22
22
|
module DOM
|
23
|
+
SCRIPT_SRC_TAG = <<~JS
|
24
|
+
const script = document.createElement("script");
|
25
|
+
script.src = arguments[0];
|
26
|
+
script.type = arguments[1];
|
27
|
+
script.onload = arguments[2];
|
28
|
+
document.head.appendChild(script);
|
29
|
+
JS
|
30
|
+
SCRIPT_TEXT_TAG = <<~JS
|
31
|
+
const script = document.createElement("script");
|
32
|
+
script.text = arguments[0];
|
33
|
+
script.type = arguments[1];
|
34
|
+
document.head.appendChild(script);
|
35
|
+
arguments[2]();
|
36
|
+
JS
|
37
|
+
STYLE_TAG = <<~JS
|
38
|
+
const style = document.createElement("style");
|
39
|
+
style.type = "text/css";
|
40
|
+
style.appendChild(document.createTextNode(arguments[0]));
|
41
|
+
document.head.appendChild(style);
|
42
|
+
arguments[1]();
|
43
|
+
JS
|
44
|
+
LINK_TAG = <<~JS
|
45
|
+
const link = document.createElement("link");
|
46
|
+
link.rel = "stylesheet";
|
47
|
+
link.href = arguments[0];
|
48
|
+
link.onload = arguments[1];
|
49
|
+
document.head.appendChild(link);
|
50
|
+
JS
|
51
|
+
|
52
|
+
#
|
53
|
+
# Returns current top window `location href`.
|
54
|
+
#
|
55
|
+
# @return [String]
|
56
|
+
# The window's current URL.
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# browser.go_to("https://google.com/")
|
60
|
+
# browser.current_url # => "https://www.google.com/"
|
61
|
+
#
|
23
62
|
def current_url
|
24
63
|
evaluate("window.top.location.href")
|
25
64
|
end
|
26
65
|
|
66
|
+
#
|
67
|
+
# Returns current top window title.
|
68
|
+
#
|
69
|
+
# @return [String]
|
70
|
+
# The window's current title.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# browser.go_to("https://google.com/")
|
74
|
+
# browser.current_title # => "Google"
|
75
|
+
#
|
27
76
|
def current_title
|
28
77
|
evaluate("window.top.document.title")
|
29
78
|
end
|
@@ -32,10 +81,36 @@ module Ferrum
|
|
32
81
|
evaluate("document.doctype && new XMLSerializer().serializeToString(document.doctype)")
|
33
82
|
end
|
34
83
|
|
84
|
+
#
|
85
|
+
# Returns current page's html.
|
86
|
+
#
|
87
|
+
# @return [String]
|
88
|
+
# The HTML source of the current page.
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# browser.go_to("https://google.com/")
|
92
|
+
# browser.body # => '<html itemscope="" itemtype="http://schema.org/WebPage" lang="ru"><head>...
|
93
|
+
#
|
35
94
|
def body
|
36
95
|
evaluate("document.documentElement.outerHTML")
|
37
96
|
end
|
38
97
|
|
98
|
+
#
|
99
|
+
# Finds nodes by using a XPath selector.
|
100
|
+
#
|
101
|
+
# @param [String] selector
|
102
|
+
# The XPath selector.
|
103
|
+
#
|
104
|
+
# @param [Node, nil] within
|
105
|
+
# The parent node to search within.
|
106
|
+
#
|
107
|
+
# @return [Array<Node>]
|
108
|
+
# The matching nodes.
|
109
|
+
#
|
110
|
+
# @example
|
111
|
+
# browser.go_to("https://github.com/")
|
112
|
+
# browser.xpath("//a[@aria-label='Issues you created']") # => [Node]
|
113
|
+
#
|
39
114
|
def xpath(selector, within: nil)
|
40
115
|
expr = <<~JS
|
41
116
|
function(selector, within) {
|
@@ -54,6 +129,22 @@ module Ferrum
|
|
54
129
|
evaluate_func(expr, selector, within)
|
55
130
|
end
|
56
131
|
|
132
|
+
#
|
133
|
+
# Finds a node by using a XPath selector.
|
134
|
+
#
|
135
|
+
# @param [String] selector
|
136
|
+
# The XPath selector.
|
137
|
+
#
|
138
|
+
# @param [Node, nil] within
|
139
|
+
# The parent node to search within.
|
140
|
+
#
|
141
|
+
# @return [Node, nil]
|
142
|
+
# The matching node.
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# browser.go_to("https://github.com/")
|
146
|
+
# browser.at_xpath("//a[@aria-label='Issues you created']") # => Node
|
147
|
+
#
|
57
148
|
def at_xpath(selector, within: nil)
|
58
149
|
expr = <<~JS
|
59
150
|
function(selector, within) {
|
@@ -65,6 +156,22 @@ module Ferrum
|
|
65
156
|
evaluate_func(expr, selector, within)
|
66
157
|
end
|
67
158
|
|
159
|
+
#
|
160
|
+
# Finds nodes by using a CSS path selector.
|
161
|
+
#
|
162
|
+
# @param [String] selector
|
163
|
+
# The CSS path selector.
|
164
|
+
#
|
165
|
+
# @param [Node, nil] within
|
166
|
+
# The parent node to search within.
|
167
|
+
#
|
168
|
+
# @return [Array<Node>]
|
169
|
+
# The matching nodes.
|
170
|
+
#
|
171
|
+
# @example
|
172
|
+
# browser.go_to("https://github.com/")
|
173
|
+
# browser.css("a[aria-label='Issues you created']") # => [Node]
|
174
|
+
#
|
68
175
|
def css(selector, within: nil)
|
69
176
|
expr = <<~JS
|
70
177
|
function(selector, within) {
|
@@ -76,6 +183,22 @@ module Ferrum
|
|
76
183
|
evaluate_func(expr, selector, within)
|
77
184
|
end
|
78
185
|
|
186
|
+
#
|
187
|
+
# Finds a node by using a CSS path selector.
|
188
|
+
#
|
189
|
+
# @param [String] selector
|
190
|
+
# The CSS path selector.
|
191
|
+
#
|
192
|
+
# @param [Node, nil] within
|
193
|
+
# The parent node to search within.
|
194
|
+
#
|
195
|
+
# @return [Node, nil]
|
196
|
+
# The matching node.
|
197
|
+
#
|
198
|
+
# @example
|
199
|
+
# browser.go_to("https://github.com/")
|
200
|
+
# browser.at_css("a[aria-label='Issues you created']") # => Node
|
201
|
+
#
|
79
202
|
def at_css(selector, within: nil)
|
80
203
|
expr = <<~JS
|
81
204
|
function(selector, within) {
|
@@ -86,6 +209,60 @@ module Ferrum
|
|
86
209
|
|
87
210
|
evaluate_func(expr, selector, within)
|
88
211
|
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# Adds a `<script>` tag to the document.
|
215
|
+
#
|
216
|
+
# @param [String, nil] url
|
217
|
+
#
|
218
|
+
# @param [String, nil] path
|
219
|
+
#
|
220
|
+
# @param [String, nil] content
|
221
|
+
#
|
222
|
+
# @param [String] type
|
223
|
+
#
|
224
|
+
# @example
|
225
|
+
# browser.add_script_tag(url: "http://example.com/stylesheet.css") # => true
|
226
|
+
#
|
227
|
+
def add_script_tag(url: nil, path: nil, content: nil, type: "text/javascript")
|
228
|
+
expr, *args = if url
|
229
|
+
[SCRIPT_SRC_TAG, url, type]
|
230
|
+
elsif path || content
|
231
|
+
if path
|
232
|
+
content = File.read(path)
|
233
|
+
content += "\n//# sourceURL=#{path}"
|
234
|
+
end
|
235
|
+
[SCRIPT_TEXT_TAG, content, type]
|
236
|
+
end
|
237
|
+
|
238
|
+
evaluate_async(expr, @page.timeout, *args)
|
239
|
+
end
|
240
|
+
|
241
|
+
#
|
242
|
+
# Adds a `<style>` tag to the document.
|
243
|
+
#
|
244
|
+
# @param [String, nil] url
|
245
|
+
#
|
246
|
+
# @param [String, nil] path
|
247
|
+
#
|
248
|
+
# @param [String, nil] content
|
249
|
+
#
|
250
|
+
# @example
|
251
|
+
# browser.add_style_tag(content: "h1 { font-size: 40px; }") # => true
|
252
|
+
#
|
253
|
+
def add_style_tag(url: nil, path: nil, content: nil)
|
254
|
+
expr, *args = if url
|
255
|
+
[LINK_TAG, url]
|
256
|
+
elsif path || content
|
257
|
+
if path
|
258
|
+
content = File.read(path)
|
259
|
+
content += "\n//# sourceURL=#{path}"
|
260
|
+
end
|
261
|
+
[STYLE_TAG, content]
|
262
|
+
end
|
263
|
+
|
264
|
+
evaluate_async(expr, @page.timeout, *args)
|
265
|
+
end
|
89
266
|
end
|
90
267
|
end
|
91
268
|
end
|
data/lib/ferrum/frame/runtime.rb
CHANGED
@@ -16,40 +16,38 @@ module Ferrum
|
|
16
16
|
INTERMITTENT_ATTEMPTS = ENV.fetch("FERRUM_INTERMITTENT_ATTEMPTS", 6).to_i
|
17
17
|
INTERMITTENT_SLEEP = ENV.fetch("FERRUM_INTERMITTENT_SLEEP", 0.1).to_f
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
arguments[2]();
|
32
|
-
JS
|
33
|
-
STYLE_TAG = <<~JS
|
34
|
-
const style = document.createElement("style");
|
35
|
-
style.type = "text/css";
|
36
|
-
style.appendChild(document.createTextNode(arguments[0]));
|
37
|
-
document.head.appendChild(style);
|
38
|
-
arguments[1]();
|
39
|
-
JS
|
40
|
-
LINK_TAG = <<~JS
|
41
|
-
const link = document.createElement("link");
|
42
|
-
link.rel = "stylesheet";
|
43
|
-
link.href = arguments[0];
|
44
|
-
link.onload = arguments[1];
|
45
|
-
document.head.appendChild(link);
|
46
|
-
JS
|
47
|
-
|
19
|
+
#
|
20
|
+
# Evaluate and return result for given JS expression.
|
21
|
+
#
|
22
|
+
# @param [String] expression
|
23
|
+
# The JavaScript to evaluate.
|
24
|
+
#
|
25
|
+
# @param [Array] args
|
26
|
+
# Additional arguments to pass to the JavaScript code.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# browser.evaluate("[window.scrollX, window.scrollY]")
|
30
|
+
#
|
48
31
|
def evaluate(expression, *args)
|
49
32
|
expression = format("function() { return %s }", expression)
|
50
33
|
call(expression: expression, arguments: args)
|
51
34
|
end
|
52
35
|
|
36
|
+
#
|
37
|
+
# Evaluate asynchronous expression and return result.
|
38
|
+
#
|
39
|
+
# @param [String] expression
|
40
|
+
# The JavaScript to evaluate.
|
41
|
+
#
|
42
|
+
# @param [Integer] wait
|
43
|
+
# How long we should wait for Promise to resolve or reject.
|
44
|
+
#
|
45
|
+
# @param [Array] args
|
46
|
+
# Additional arguments to pass to the JavaScript code.
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# browser.evaluate_async(%(arguments[0]({foo: "bar"})), 5) # => { "foo" => "bar" }
|
50
|
+
#
|
53
51
|
def evaluate_async(expression, wait, *args)
|
54
52
|
template = <<~JS
|
55
53
|
function() {
|
@@ -70,6 +68,18 @@ module Ferrum
|
|
70
68
|
call(expression: expression, arguments: args, awaitPromise: true)
|
71
69
|
end
|
72
70
|
|
71
|
+
#
|
72
|
+
# Execute expression. Doesn't return the result.
|
73
|
+
#
|
74
|
+
# @param [String] expression
|
75
|
+
# The JavaScript to evaluate.
|
76
|
+
#
|
77
|
+
# @param [Array] args
|
78
|
+
# Additional arguments to pass to the JavaScript code.
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# browser.execute(%(1 + 1)) # => true
|
82
|
+
#
|
73
83
|
def execute(expression, *args)
|
74
84
|
expression = format("function() { %s }", expression)
|
75
85
|
call(expression: expression, arguments: args, handle: false, returnByValue: true)
|
@@ -87,42 +97,12 @@ module Ferrum
|
|
87
97
|
call(expression: expression, on: node, wait: wait, **options)
|
88
98
|
end
|
89
99
|
|
90
|
-
def add_script_tag(url: nil, path: nil, content: nil, type: "text/javascript")
|
91
|
-
expr, *args = if url
|
92
|
-
[SCRIPT_SRC_TAG, url, type]
|
93
|
-
elsif path || content
|
94
|
-
if path
|
95
|
-
content = File.read(path)
|
96
|
-
content += "\n//# sourceURL=#{path}"
|
97
|
-
end
|
98
|
-
[SCRIPT_TEXT_TAG, content, type]
|
99
|
-
end
|
100
|
-
|
101
|
-
evaluate_async(expr, @page.timeout, *args)
|
102
|
-
end
|
103
|
-
|
104
|
-
def add_style_tag(url: nil, path: nil, content: nil)
|
105
|
-
expr, *args = if url
|
106
|
-
[LINK_TAG, url]
|
107
|
-
elsif path || content
|
108
|
-
if path
|
109
|
-
content = File.read(path)
|
110
|
-
content += "\n//# sourceURL=#{path}"
|
111
|
-
end
|
112
|
-
[STYLE_TAG, content]
|
113
|
-
end
|
114
|
-
|
115
|
-
evaluate_async(expr, @page.timeout, *args)
|
116
|
-
end
|
117
|
-
|
118
100
|
private
|
119
101
|
|
120
102
|
def call(expression:, arguments: [], on: nil, wait: 0, handle: true, **options)
|
121
103
|
errors = [NodeNotFoundError, NoExecutionContextError]
|
122
|
-
sleep = INTERMITTENT_SLEEP
|
123
|
-
attempts = INTERMITTENT_ATTEMPTS
|
124
104
|
|
125
|
-
Utils::Attempt.with_retry(errors: errors, max:
|
105
|
+
Utils::Attempt.with_retry(errors: errors, max: INTERMITTENT_ATTEMPTS, wait: INTERMITTENT_SLEEP) do
|
126
106
|
params = options.dup
|
127
107
|
|
128
108
|
if on
|
@@ -132,7 +112,7 @@ module Ferrum
|
|
132
112
|
end
|
133
113
|
|
134
114
|
if params[:executionContextId].nil? && params[:objectId].nil?
|
135
|
-
params = params.merge(executionContextId: execution_id)
|
115
|
+
params = params.merge(executionContextId: execution_id!)
|
136
116
|
end
|
137
117
|
|
138
118
|
response = @page.command("Runtime.callFunctionOn",
|