ferrum 0.8 → 0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +200 -75
- data/lib/ferrum.rb +36 -8
- data/lib/ferrum/browser.rb +12 -5
- data/lib/ferrum/browser/client.rb +6 -0
- data/lib/ferrum/browser/command.rb +26 -25
- data/lib/ferrum/browser/options/base.rb +46 -0
- data/lib/ferrum/browser/options/chrome.rb +74 -0
- data/lib/ferrum/browser/options/firefox.rb +34 -0
- data/lib/ferrum/browser/process.rb +23 -11
- data/lib/ferrum/browser/subscriber.rb +5 -1
- data/lib/ferrum/browser/web_socket.rb +17 -1
- data/lib/ferrum/browser/xvfb.rb +37 -0
- data/lib/ferrum/context.rb +10 -6
- data/lib/ferrum/contexts.rb +4 -2
- data/lib/ferrum/frame.rb +1 -0
- data/lib/ferrum/frame/dom.rb +30 -30
- data/lib/ferrum/frame/runtime.rb +62 -63
- data/lib/ferrum/network.rb +23 -6
- data/lib/ferrum/network/error.rb +8 -15
- data/lib/ferrum/network/intercepted_request.rb +1 -1
- data/lib/ferrum/node.rb +61 -17
- data/lib/ferrum/page.rb +40 -13
- data/lib/ferrum/page/animation.rb +16 -0
- data/lib/ferrum/page/frames.rb +10 -2
- data/lib/ferrum/page/screenshot.rb +64 -12
- data/lib/ferrum/rbga.rb +38 -0
- data/lib/ferrum/version.rb +1 -1
- metadata +19 -10
- data/lib/ferrum/browser/chrome.rb +0 -76
- data/lib/ferrum/browser/firefox.rb +0 -34
data/lib/ferrum/network.rb
CHANGED
@@ -83,19 +83,21 @@ module Ferrum
|
|
83
83
|
@page.command("Fetch.enable", handleAuthRequests: true, patterns: [pattern])
|
84
84
|
end
|
85
85
|
|
86
|
-
def authorize(user:, password:, type: :server)
|
86
|
+
def authorize(user:, password:, type: :server, &block)
|
87
87
|
unless AUTHORIZE_TYPE.include?(type)
|
88
88
|
raise ArgumentError, ":type should be in #{AUTHORIZE_TYPE}"
|
89
89
|
end
|
90
90
|
|
91
|
+
if !block_given? && !@page.subscribed?("Fetch.requestPaused")
|
92
|
+
raise ArgumentError, "Block is missing, call `authorize(...) { |r| r.continue } or subscribe to `on(:request)` events before calling it"
|
93
|
+
end
|
94
|
+
|
91
95
|
@authorized_ids ||= {}
|
92
96
|
@authorized_ids[type] ||= []
|
93
97
|
|
94
98
|
intercept
|
95
99
|
|
96
|
-
@page.on(:request)
|
97
|
-
request.continue
|
98
|
-
end
|
100
|
+
@page.on(:request, &block)
|
99
101
|
|
100
102
|
@page.on(:auth) do |request, index, total|
|
101
103
|
if request.auth_challenge?(type)
|
@@ -157,12 +159,27 @@ module Ferrum
|
|
157
159
|
end
|
158
160
|
end
|
159
161
|
|
162
|
+
@page.on("Network.loadingFailed") do |params|
|
163
|
+
exchange = select(params["requestId"]).last
|
164
|
+
exchange.error ||= Network::Error.new
|
165
|
+
|
166
|
+
exchange.error.id = params["requestId"]
|
167
|
+
exchange.error.type = params["type"]
|
168
|
+
exchange.error.error_text = params["errorText"]
|
169
|
+
exchange.error.monotonic_time = params["timestamp"]
|
170
|
+
exchange.error.canceled = params["canceled"]
|
171
|
+
end
|
172
|
+
|
160
173
|
@page.on("Log.entryAdded") do |params|
|
161
174
|
entry = params["entry"] || {}
|
162
175
|
if entry["source"] == "network" && entry["level"] == "error"
|
163
176
|
exchange = select(entry["networkRequestId"]).last
|
164
|
-
error
|
165
|
-
|
177
|
+
exchange.error ||= Network::Error.new
|
178
|
+
|
179
|
+
exchange.error.id = entry["networkRequestId"]
|
180
|
+
exchange.error.url = entry["url"]
|
181
|
+
exchange.error.description = entry["text"]
|
182
|
+
exchange.error.timestamp = entry["timestamp"]
|
166
183
|
end
|
167
184
|
end
|
168
185
|
end
|
data/lib/ferrum/network/error.rb
CHANGED
@@ -3,24 +3,17 @@
|
|
3
3
|
module Ferrum
|
4
4
|
class Network
|
5
5
|
class Error
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def id
|
11
|
-
@data["networkRequestId"]
|
12
|
-
end
|
13
|
-
|
14
|
-
def url
|
15
|
-
@data["url"]
|
16
|
-
end
|
6
|
+
attr_writer :canceled
|
7
|
+
attr_reader :time, :timestamp
|
8
|
+
attr_accessor :id, :url, :type, :error_text, :monotonic_time, :description
|
17
9
|
|
18
|
-
def
|
19
|
-
@
|
10
|
+
def canceled?
|
11
|
+
@canceled
|
20
12
|
end
|
21
13
|
|
22
|
-
def
|
23
|
-
@
|
14
|
+
def timestamp=(value)
|
15
|
+
@timestamp = value
|
16
|
+
@time = Time.strptime((value / 1000).to_s, "%s")
|
24
17
|
end
|
25
18
|
end
|
26
19
|
end
|
@@ -39,7 +39,7 @@ module Ferrum
|
|
39
39
|
requestId: request_id,
|
40
40
|
responseHeaders: header_array(headers),
|
41
41
|
})
|
42
|
-
options = options.merge(body: Base64.
|
42
|
+
options = options.merge(body: Base64.strict_encode64(options.fetch(:body, ""))) if has_body
|
43
43
|
|
44
44
|
@status = :responded
|
45
45
|
@page.command("Fetch.fulfillRequest", **options)
|
data/lib/ferrum/node.rb
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
module Ferrum
|
4
4
|
class Node
|
5
|
+
MOVING_WAIT_DELAY = ENV.fetch("FERRUM_NODE_MOVING_WAIT", 0.01).to_f
|
6
|
+
MOVING_WAIT_ATTEMPTS = ENV.fetch("FERRUM_NODE_MOVING_ATTEMPTS", 50).to_i
|
7
|
+
|
5
8
|
attr_reader :page, :target_id, :node_id, :description, :tag_name
|
6
9
|
|
7
10
|
def initialize(frame, target_id, node_id, description)
|
@@ -27,6 +30,26 @@ module Ferrum
|
|
27
30
|
tap { page.command("DOM.focus", slowmoable: true, nodeId: node_id) }
|
28
31
|
end
|
29
32
|
|
33
|
+
def focusable?
|
34
|
+
focus
|
35
|
+
true
|
36
|
+
rescue BrowserError => e
|
37
|
+
e.message == "Element is not focusable" ? false : raise
|
38
|
+
end
|
39
|
+
|
40
|
+
def wait_for_stop_moving(delay: MOVING_WAIT_DELAY, attempts: MOVING_WAIT_ATTEMPTS)
|
41
|
+
Ferrum.with_attempts(errors: NodeMovingError, max: attempts, wait: 0) do
|
42
|
+
previous, current = get_content_quads_with(delay: delay)
|
43
|
+
raise NodeMovingError.new(self, previous, current) if previous != current
|
44
|
+
current
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def moving?(delay: MOVING_WAIT_DELAY)
|
49
|
+
previous, current = get_content_quads_with(delay: delay)
|
50
|
+
previous == current
|
51
|
+
end
|
52
|
+
|
30
53
|
def blur
|
31
54
|
tap { evaluate("this.blur()") }
|
32
55
|
end
|
@@ -121,16 +144,45 @@ module Ferrum
|
|
121
144
|
end
|
122
145
|
|
123
146
|
def find_position(x: nil, y: nil, position: :top)
|
124
|
-
|
125
|
-
|
147
|
+
points = wait_for_stop_moving.map { |q| to_points(q) }.first
|
148
|
+
get_position(points, x, y, position)
|
149
|
+
rescue CoordinatesNotFoundError
|
150
|
+
x, y = get_bounding_rect_coordinates
|
151
|
+
raise if x == 0 && y == 0
|
152
|
+
[x, y]
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def get_bounding_rect_coordinates
|
158
|
+
evaluate <<~JS
|
159
|
+
[this.getBoundingClientRect().left + window.pageXOffset + (this.offsetWidth / 2),
|
160
|
+
this.getBoundingClientRect().top + window.pageYOffset + (this.offsetHeight / 2)]
|
161
|
+
JS
|
162
|
+
end
|
163
|
+
|
164
|
+
def get_content_quads
|
165
|
+
quads = page.command("DOM.getContentQuads", nodeId: node_id)["quads"]
|
166
|
+
raise CoordinatesNotFoundError, "Node is either not visible or not an HTMLElement" if quads.size == 0
|
167
|
+
quads
|
168
|
+
end
|
169
|
+
|
170
|
+
def get_content_quads_with(delay: MOVING_WAIT_DELAY)
|
171
|
+
previous = get_content_quads
|
172
|
+
sleep(delay)
|
173
|
+
current = get_content_quads
|
174
|
+
[previous, current]
|
175
|
+
end
|
176
|
+
|
177
|
+
def get_position(points, offset_x, offset_y, position)
|
126
178
|
x = y = nil
|
127
179
|
|
128
180
|
if offset_x && offset_y && position == :top
|
129
|
-
point =
|
181
|
+
point = points.first
|
130
182
|
x = point[:x] + offset_x.to_i
|
131
183
|
y = point[:y] + offset_y.to_i
|
132
184
|
else
|
133
|
-
x, y =
|
185
|
+
x, y = points.inject([0, 0]) do |memo, point|
|
134
186
|
[memo[0] + point[:x],
|
135
187
|
memo[1] + point[:y]]
|
136
188
|
end
|
@@ -147,19 +199,11 @@ module Ferrum
|
|
147
199
|
[x, y]
|
148
200
|
end
|
149
201
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
# FIXME: Case when a few quads returned
|
157
|
-
result["quads"].map do |quad|
|
158
|
-
[{x: quad[0], y: quad[1]},
|
159
|
-
{x: quad[2], y: quad[3]},
|
160
|
-
{x: quad[4], y: quad[5]},
|
161
|
-
{x: quad[6], y: quad[7]}]
|
162
|
-
end.first
|
202
|
+
def to_points(quad)
|
203
|
+
[{x: quad[0], y: quad[1]},
|
204
|
+
{x: quad[2], y: quad[3]},
|
205
|
+
{x: quad[4], y: quad[5]},
|
206
|
+
{x: quad[6], y: quad[7]}]
|
163
207
|
end
|
164
208
|
end
|
165
209
|
end
|
data/lib/ferrum/page.rb
CHANGED
@@ -9,6 +9,7 @@ require "ferrum/dialog"
|
|
9
9
|
require "ferrum/network"
|
10
10
|
require "ferrum/page/frames"
|
11
11
|
require "ferrum/page/screenshot"
|
12
|
+
require "ferrum/page/animation"
|
12
13
|
require "ferrum/browser/client"
|
13
14
|
|
14
15
|
module Ferrum
|
@@ -32,10 +33,10 @@ module Ferrum
|
|
32
33
|
extend Forwardable
|
33
34
|
delegate %i[at_css at_xpath css xpath
|
34
35
|
current_url current_title url title body doctype set_content
|
35
|
-
execution_id evaluate evaluate_on evaluate_async execute
|
36
|
+
execution_id evaluate evaluate_on evaluate_async execute evaluate_func
|
36
37
|
add_script_tag add_style_tag] => :main_frame
|
37
38
|
|
38
|
-
include Frames, Screenshot
|
39
|
+
include Frames, Screenshot, Animation
|
39
40
|
|
40
41
|
attr_accessor :referrer
|
41
42
|
attr_reader :target_id, :browser,
|
@@ -44,7 +45,7 @@ module Ferrum
|
|
44
45
|
|
45
46
|
def initialize(target_id, browser)
|
46
47
|
@frames = {}
|
47
|
-
@main_frame = Frame.new(nil, self)
|
48
|
+
@main_frame = Frame.new(nil, self)
|
48
49
|
@target_id, @browser = target_id, browser
|
49
50
|
@event = Event.new.tap(&:set)
|
50
51
|
|
@@ -65,7 +66,7 @@ module Ferrum
|
|
65
66
|
@browser.timeout
|
66
67
|
end
|
67
68
|
|
68
|
-
def
|
69
|
+
def go_to(url = nil)
|
69
70
|
options = { url: combine_url!(url) }
|
70
71
|
options.merge!(referrer: referrer) if referrer
|
71
72
|
response = command("Page.navigate", wait: GOTO_WAIT, **options)
|
@@ -78,9 +79,12 @@ module Ferrum
|
|
78
79
|
end
|
79
80
|
response["frameId"]
|
80
81
|
rescue TimeoutError
|
81
|
-
|
82
|
-
|
82
|
+
if @browser.pending_connection_errors
|
83
|
+
pendings = network.traffic.select(&:pending?).map { |e| e.request.url }
|
84
|
+
raise PendingConnectionsError.new(options[:url], pendings) unless pendings.empty?
|
85
|
+
end
|
83
86
|
end
|
87
|
+
alias goto go_to
|
84
88
|
|
85
89
|
def close
|
86
90
|
@headers.clear
|
@@ -89,15 +93,12 @@ module Ferrum
|
|
89
93
|
end
|
90
94
|
|
91
95
|
def resize(width: nil, height: nil, fullscreen: false)
|
92
|
-
result = @browser.command("Browser.getWindowForTarget", targetId: @target_id)
|
93
|
-
@window_id, @bounds = result.values_at("windowId", "bounds")
|
94
|
-
|
95
96
|
if fullscreen
|
96
97
|
width, height = document_size
|
97
|
-
|
98
|
+
set_window_bounds(windowState: "fullscreen")
|
98
99
|
else
|
99
|
-
|
100
|
-
|
100
|
+
set_window_bounds(windowState: "normal")
|
101
|
+
set_window_bounds(width: width, height: height)
|
101
102
|
end
|
102
103
|
|
103
104
|
command("Emulation.setDeviceMetricsOverride", slowmoable: true,
|
@@ -108,6 +109,14 @@ module Ferrum
|
|
108
109
|
fitWindow: false)
|
109
110
|
end
|
110
111
|
|
112
|
+
def position
|
113
|
+
@browser.command("Browser.getWindowBounds", windowId: window_id).fetch("bounds").values_at("left", "top")
|
114
|
+
end
|
115
|
+
|
116
|
+
def position=(left:, top:)
|
117
|
+
@browser.command("Browser.setWindowBounds", windowId: window_id, bounds: { left: left, top: top })
|
118
|
+
end
|
119
|
+
|
111
120
|
def refresh
|
112
121
|
command("Page.reload", wait: timeout, slowmoable: true)
|
113
122
|
end
|
@@ -125,12 +134,26 @@ module Ferrum
|
|
125
134
|
history_navigate(delta: 1)
|
126
135
|
end
|
127
136
|
|
137
|
+
def wait_for_reload(sec = 1)
|
138
|
+
@event.reset if @event.set?
|
139
|
+
@event.wait(sec)
|
140
|
+
@event.set
|
141
|
+
end
|
142
|
+
|
128
143
|
def bypass_csp(value = true)
|
129
144
|
enabled = !!value
|
130
145
|
command("Page.setBypassCSP", enabled: enabled)
|
131
146
|
enabled
|
132
147
|
end
|
133
148
|
|
149
|
+
def window_id
|
150
|
+
@browser.command("Browser.getWindowForTarget", targetId: @target_id)["windowId"]
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_window_bounds(bounds = {})
|
154
|
+
@browser.command("Browser.setWindowBounds", windowId: window_id, bounds: bounds)
|
155
|
+
end
|
156
|
+
|
134
157
|
def command(method, wait: 0, slowmoable: false, **params)
|
135
158
|
iteration = @event.reset if wait > 0
|
136
159
|
sleep(@browser.slowmo) if slowmoable && @browser.slowmo > 0
|
@@ -173,6 +196,10 @@ module Ferrum
|
|
173
196
|
end
|
174
197
|
end
|
175
198
|
|
199
|
+
def subscribed?(event)
|
200
|
+
@client.subscribed?(event)
|
201
|
+
end
|
202
|
+
|
176
203
|
private
|
177
204
|
|
178
205
|
def subscribe
|
@@ -255,7 +282,7 @@ module Ferrum
|
|
255
282
|
nil_or_relative = url.nil? || url.relative?
|
256
283
|
|
257
284
|
if nil_or_relative && !@browser.base_url
|
258
|
-
raise "Set :base_url browser's option or use absolute url in `
|
285
|
+
raise "Set :base_url browser's option or use absolute url in `go_to`, you passed: #{url_or_path}"
|
259
286
|
end
|
260
287
|
|
261
288
|
(nil_or_relative ? @browser.base_url.join(url.to_s) : url).to_s
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ferrum
|
4
|
+
class Page
|
5
|
+
module Animation
|
6
|
+
def playback_rate
|
7
|
+
command("Animation.getPlaybackRate")["playbackRate"]
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def playback_rate=(value)
|
12
|
+
command("Animation.setPlaybackRate", playbackRate: value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/ferrum/page/frames.rb
CHANGED
@@ -71,17 +71,25 @@ module Ferrum
|
|
71
71
|
end
|
72
72
|
|
73
73
|
on("Runtime.executionContextCreated") do |params|
|
74
|
+
setting_up_main_frame = false
|
74
75
|
context_id = params.dig("context", "id")
|
75
76
|
frame_id = params.dig("context", "auxData", "frameId")
|
76
77
|
|
77
78
|
unless @main_frame.id
|
78
|
-
|
79
|
-
|
79
|
+
root_frame = command("Page.getFrameTree").dig("frameTree", "frame", "id")
|
80
|
+
if frame_id == root_frame
|
81
|
+
setting_up_main_frame = true
|
82
|
+
@main_frame.id = frame_id
|
83
|
+
@frames[frame_id] = @main_frame
|
84
|
+
end
|
80
85
|
end
|
81
86
|
|
82
87
|
frame = @frames[frame_id] || Frame.new(frame_id, self)
|
83
88
|
frame.set_execution_id(context_id)
|
84
89
|
|
90
|
+
# Set event because `execution_id` might raise NoExecutionContextError
|
91
|
+
@event.set if setting_up_main_frame
|
92
|
+
|
85
93
|
@frames[frame_id] ||= frame
|
86
94
|
end
|
87
95
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ferrum/rbga"
|
4
|
+
|
3
5
|
module Ferrum
|
4
6
|
class Page
|
5
7
|
module Screenshot
|
@@ -10,7 +12,7 @@ module Ferrum
|
|
10
12
|
scale: 1.0
|
11
13
|
}.freeze
|
12
14
|
|
13
|
-
|
15
|
+
PAPER_FORMATS = {
|
14
16
|
letter: { width: 8.50, height: 11.00 },
|
15
17
|
legal: { width: 8.50, height: 14.00 },
|
16
18
|
tabloid: { width: 11.00, height: 17.00 },
|
@@ -24,19 +26,33 @@ module Ferrum
|
|
24
26
|
A6: { width: 4.13, height: 5.83 },
|
25
27
|
}.freeze
|
26
28
|
|
29
|
+
STREAM_CHUNK = 128 * 1024
|
30
|
+
|
27
31
|
def screenshot(**opts)
|
28
32
|
path, encoding = common_options(**opts)
|
29
33
|
options = screenshot_options(path, **opts)
|
30
|
-
data = capture_screenshot(options, opts[:full])
|
34
|
+
data = capture_screenshot(options, opts[:full], opts[:background_color])
|
31
35
|
return data if encoding == :base64
|
32
|
-
|
36
|
+
|
37
|
+
bin = Base64.decode64(data)
|
38
|
+
save_file(path, bin)
|
33
39
|
end
|
34
40
|
|
35
41
|
def pdf(**opts)
|
36
42
|
path, encoding = common_options(**opts)
|
37
|
-
options = pdf_options(**opts)
|
38
|
-
|
39
|
-
|
43
|
+
options = pdf_options(**opts).merge(transferMode: "ReturnAsStream")
|
44
|
+
handle = command("Page.printToPDF", **options).fetch("stream")
|
45
|
+
|
46
|
+
if path
|
47
|
+
stream_to_file(handle, path: path)
|
48
|
+
else
|
49
|
+
stream_to_memory(handle, encoding: encoding)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def mhtml(path: nil)
|
54
|
+
data = command("Page.captureSnapshot", format: :mhtml).fetch("data")
|
55
|
+
return data if path.nil?
|
40
56
|
save_file(path, data)
|
41
57
|
end
|
42
58
|
|
@@ -56,9 +72,31 @@ module Ferrum
|
|
56
72
|
private
|
57
73
|
|
58
74
|
def save_file(path, data)
|
59
|
-
|
60
|
-
|
61
|
-
|
75
|
+
return data unless path
|
76
|
+
File.open(path.to_s, "wb") { |f| f.write(data) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def stream_to_file(handle, path:)
|
80
|
+
File.open(path, "wb") { |f| stream_to(handle, f) }
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def stream_to_memory(handle, encoding:)
|
85
|
+
data = String.new("") # Mutable string has << and compatible to File
|
86
|
+
stream_to(handle, data)
|
87
|
+
encoding == :base64 ? Base64.encode64(data) : data
|
88
|
+
end
|
89
|
+
|
90
|
+
def stream_to(handle, output)
|
91
|
+
loop do
|
92
|
+
result = command("IO.read", handle: handle, size: STREAM_CHUNK)
|
93
|
+
|
94
|
+
data_chunk = result["data"]
|
95
|
+
data_chunk = Base64.decode64(data_chunk) if result["base64Encoded"]
|
96
|
+
output << data_chunk
|
97
|
+
|
98
|
+
break if result["eof"]
|
99
|
+
end
|
62
100
|
end
|
63
101
|
|
64
102
|
def common_options(encoding: :base64, path: nil, **_)
|
@@ -76,7 +114,7 @@ module Ferrum
|
|
76
114
|
raise ArgumentError, "Specify :format or :paper_width, :paper_height"
|
77
115
|
end
|
78
116
|
|
79
|
-
dimension =
|
117
|
+
dimension = PAPER_FORMATS.fetch(format)
|
80
118
|
options.merge!(paper_width: dimension[:width],
|
81
119
|
paper_height: dimension[:height])
|
82
120
|
end
|
@@ -134,9 +172,11 @@ module Ferrum
|
|
134
172
|
option.to_s.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.to_sym
|
135
173
|
end
|
136
174
|
|
137
|
-
def capture_screenshot(options, full)
|
175
|
+
def capture_screenshot(options, full, background_color)
|
138
176
|
maybe_resize_fullscreen(full) do
|
139
|
-
|
177
|
+
with_background_color(background_color) do
|
178
|
+
command("Page.captureScreenshot", **options)
|
179
|
+
end
|
140
180
|
end.fetch("data")
|
141
181
|
end
|
142
182
|
|
@@ -150,6 +190,18 @@ module Ferrum
|
|
150
190
|
ensure
|
151
191
|
resize(width: width, height: height) if full
|
152
192
|
end
|
193
|
+
|
194
|
+
def with_background_color(color)
|
195
|
+
if color
|
196
|
+
raise ArgumentError, "Accept Ferrum::RGBA class only" unless color.is_a?(RGBA)
|
197
|
+
|
198
|
+
command("Emulation.setDefaultBackgroundColorOverride", color: color.to_h)
|
199
|
+
end
|
200
|
+
|
201
|
+
yield
|
202
|
+
ensure
|
203
|
+
command("Emulation.setDefaultBackgroundColorOverride") if color
|
204
|
+
end
|
153
205
|
end
|
154
206
|
end
|
155
207
|
end
|