ferrum 0.14 → 0.15

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.
@@ -5,6 +5,9 @@ require "ferrum/rgba"
5
5
  module Ferrum
6
6
  class Page
7
7
  module Screenshot
8
+ FULL_WARNING = "Ignoring :selector or :area in #screenshot since full: true was given at %s"
9
+ AREA_WARNING = "Ignoring :area in #screenshot since selector: was given at %s"
10
+
8
11
  DEFAULT_PDF_OPTIONS = {
9
12
  landscape: false,
10
13
  paper_width: 8.5,
@@ -50,6 +53,9 @@ module Ferrum
50
53
  # @option opts [String] :selector
51
54
  # CSS selector for the given element.
52
55
  #
56
+ # @option opts [Hash] :area
57
+ # x, y, width, height to screenshot an area.
58
+ #
53
59
  # @option opts [Float] :scale
54
60
  # Zoom in/out.
55
61
  #
@@ -57,19 +63,19 @@ module Ferrum
57
63
  # Sets the background color.
58
64
  #
59
65
  # @example
60
- # browser.go_to("https://google.com/")
66
+ # page.go_to("https://google.com/")
61
67
  #
62
68
  # @example Save on the disk in PNG:
63
- # browser.screenshot(path: "google.png") # => 134660
69
+ # page.screenshot(path: "google.png") # => 134660
64
70
  #
65
71
  # @example Save on the disk in JPG:
66
- # browser.screenshot(path: "google.jpg") # => 30902
72
+ # page.screenshot(path: "google.jpg") # => 30902
67
73
  #
68
74
  # @example Save to Base64 the whole page not only viewport and reduce quality:
69
- # browser.screenshot(full: true, quality: 60) # "iVBORw0KGgoAAAANS...
75
+ # page.screenshot(full: true, quality: 60) # "iVBORw0KGgoAAAANS...
70
76
  #
71
77
  # @example Save with specific background color:
72
- # browser.screenshot(background_color: Ferrum::RGBA.new(0, 0, 0, 0.0))
78
+ # page.screenshot(background_color: Ferrum::RGBA.new(0, 0, 0, 0.0))
73
79
  #
74
80
  def screenshot(**opts)
75
81
  path, encoding = common_options(**opts)
@@ -113,9 +119,9 @@ module Ferrum
113
119
  # can pass.
114
120
  #
115
121
  # @example
116
- # browser.go_to("https://google.com/")
122
+ # page.go_to("https://google.com/")
117
123
  # # Save to disk as a PDF
118
- # browser.pdf(path: "google.pdf", paper_width: 1.0, paper_height: 1.0) # => true
124
+ # page.pdf(path: "google.pdf", paper_width: 1.0, paper_height: 1.0) # => true
119
125
  #
120
126
  def pdf(**opts)
121
127
  path, encoding = common_options(**opts)
@@ -131,8 +137,8 @@ module Ferrum
131
137
  # The path to save a file on the disk.
132
138
  #
133
139
  # @example
134
- # browser.go_to("https://google.com/")
135
- # browser.mhtml(path: "google.mhtml") # => 87742
140
+ # page.go_to("https://google.com/")
141
+ # page.mhtml(path: "google.mhtml") # => 87742
136
142
  #
137
143
  def mhtml(path: nil)
138
144
  data = command("Page.captureSnapshot", format: :mhtml).fetch("data")
@@ -198,7 +204,7 @@ module Ferrum
198
204
  screenshot_options.merge!(quality: quality) if quality
199
205
  screenshot_options.merge!(format: format)
200
206
 
201
- clip = area_options(options[:full], options[:selector], scale)
207
+ clip = area_options(options[:full], options[:selector], scale, options[:area])
202
208
  screenshot_options.merge!(clip: clip) if clip
203
209
 
204
210
  screenshot_options
@@ -214,29 +220,35 @@ module Ferrum
214
220
  [format, quality]
215
221
  end
216
222
 
217
- def area_options(full, selector, scale)
218
- message = "Ignoring :selector in #screenshot since full: true was given at #{caller(1..1).first}"
219
- warn(message) if full && selector
223
+ def area_options(full, selector, scale, area = nil)
224
+ warn(FULL_WARNING % caller(1..1).first) if full && (selector || area)
225
+ warn(AREA_WARNING % caller(1..1).first) if selector && area
220
226
 
221
227
  clip = if full
222
- width, height = document_size
223
- { x: 0, y: 0, width: width, height: height, scale: scale } if width.positive? && height.positive?
228
+ full_window_area || viewport_area
224
229
  elsif selector
225
- bounding_rect(selector).merge(scale: scale)
230
+ bounding_rect(selector)
231
+ elsif area
232
+ area
233
+ else
234
+ viewport_area
226
235
  end
227
236
 
228
- if scale != 1
229
- unless clip
230
- width, height = viewport_size
231
- clip = { x: 0, y: 0, width: width, height: height }
232
- end
233
-
234
- clip.merge!(scale: scale)
235
- end
237
+ clip.merge!(scale: scale)
236
238
 
237
239
  clip
238
240
  end
239
241
 
242
+ def full_window_area
243
+ width, height = document_size
244
+ { x: 0, y: 0, width: width, height: height } if width.positive? && height.positive?
245
+ end
246
+
247
+ def viewport_area
248
+ width, height = viewport_size
249
+ { x: 0, y: 0, width: width, height: height }
250
+ end
251
+
240
252
  def bounding_rect(selector)
241
253
  rect = evaluate_async(%(
242
254
  const rect = document
data/lib/ferrum/page.rb CHANGED
@@ -1,50 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "forwardable"
4
+ require "pathname"
4
5
  require "ferrum/mouse"
5
6
  require "ferrum/keyboard"
6
7
  require "ferrum/headers"
7
8
  require "ferrum/cookies"
8
9
  require "ferrum/dialog"
9
10
  require "ferrum/network"
11
+ require "ferrum/downloads"
10
12
  require "ferrum/page/frames"
11
13
  require "ferrum/page/screenshot"
12
14
  require "ferrum/page/animation"
13
15
  require "ferrum/page/tracing"
14
16
  require "ferrum/page/stream"
15
- require "ferrum/browser/client"
16
17
 
17
18
  module Ferrum
18
19
  class Page
19
20
  GOTO_WAIT = ENV.fetch("FERRUM_GOTO_WAIT", 0.1).to_f
20
21
 
21
- class Event < Concurrent::Event
22
- def iteration
23
- synchronize { @iteration }
24
- end
25
-
26
- def reset
27
- synchronize do
28
- @iteration += 1
29
- @set = false if @set
30
- @iteration
31
- end
32
- end
33
- end
34
-
35
22
  extend Forwardable
36
23
  delegate %i[at_css at_xpath css xpath
37
24
  current_url current_title url title body doctype content=
38
25
  execution_id execution_id! evaluate evaluate_on evaluate_async execute evaluate_func
39
26
  add_script_tag add_style_tag] => :main_frame
27
+ delegate %i[base_url default_user_agent timeout timeout=] => :@options
40
28
 
41
29
  include Animation
42
30
  include Screenshot
43
31
  include Frames
44
32
  include Stream
45
33
 
46
- attr_accessor :referrer, :timeout
47
- attr_reader :target_id, :browser, :event, :tracing
34
+ attr_accessor :referrer
35
+ attr_reader :context_id, :target_id, :event, :tracing
36
+
37
+ # Client connection.
38
+ #
39
+ # @return [Client]
40
+ attr_reader :client
48
41
 
49
42
  # Mouse object.
50
43
  #
@@ -71,55 +64,56 @@ module Ferrum
71
64
  # @return [Cookies]
72
65
  attr_reader :cookies
73
66
 
74
- def initialize(target_id, browser, proxy: nil)
67
+ # Downloads object.
68
+ #
69
+ # @return [Downloads]
70
+ attr_reader :downloads
71
+
72
+ def initialize(client, context_id:, target_id:, proxy: nil)
73
+ @client = client
74
+ @context_id = context_id
75
+ @target_id = target_id
76
+ @options = client.options
77
+
75
78
  @frames = Concurrent::Map.new
76
79
  @main_frame = Frame.new(nil, self)
77
- @browser = browser
78
- @target_id = target_id
79
- @timeout = @browser.timeout
80
- @event = Event.new.tap(&:set)
80
+ @event = Utils::Event.new.tap(&:set)
81
81
  self.proxy = proxy
82
82
 
83
- @client = Browser::Client.new(ws_url, self,
84
- logger: @browser.options.logger,
85
- ws_max_receive_size: @browser.options.ws_max_receive_size,
86
- id_starts_with: 1000)
87
-
88
83
  @mouse = Mouse.new(self)
89
84
  @keyboard = Keyboard.new(self)
90
85
  @headers = Headers.new(self)
91
86
  @cookies = Cookies.new(self)
92
87
  @network = Network.new(self)
93
88
  @tracing = Tracing.new(self)
89
+ @downloads = Downloads.new(self)
94
90
 
95
91
  subscribe
96
92
  prepare_page
97
93
  end
98
94
 
99
- def context
100
- @browser.contexts.find_by(target_id: target_id)
101
- end
102
-
103
95
  #
104
96
  # Navigates the page to a URL.
105
97
  #
106
98
  # @param [String, nil] url
107
99
  # The URL to navigate to. The url should include scheme unless you set
108
- # `{Browser#base_url = url}` when configuring driver.
100
+ # `{Browser#base_url = url}` when configuring.
109
101
  #
110
102
  # @example
111
- # browser.go_to("https://github.com/")
103
+ # page.go_to("https://github.com/")
112
104
  #
113
105
  def go_to(url = nil)
114
106
  options = { url: combine_url!(url) }
115
107
  options.merge!(referrer: referrer) if referrer
116
108
  response = command("Page.navigate", wait: GOTO_WAIT, **options)
117
- error_text = response["errorText"]
118
- raise StatusError.new(options[:url], "Request to #{options[:url]} failed (#{error_text})") if error_text
109
+ error_text = response["errorText"] # https://cs.chromium.org/chromium/src/net/base/net_error_list.h
110
+ if error_text && error_text != "net::ERR_ABORTED" # Request aborted due to user action or download
111
+ raise StatusError.new(options[:url], "Request to #{options[:url]} failed (#{error_text})")
112
+ end
119
113
 
120
114
  response["frameId"]
121
115
  rescue TimeoutError
122
- if @browser.options.pending_connection_errors
116
+ if @options.pending_connection_errors
123
117
  pendings = network.traffic.select(&:pending?).map(&:url).compact
124
118
  raise PendingConnectionsError.new(options[:url], pendings) unless pendings.empty?
125
119
  end
@@ -129,41 +123,76 @@ module Ferrum
129
123
 
130
124
  def close
131
125
  @headers.clear
132
- @browser.command("Target.closeTarget", targetId: @target_id)
133
- @client.close
126
+ client.command("Target.closeTarget", async: true, targetId: @target_id)
127
+ close_connection
128
+
129
+ true
130
+ end
131
+
132
+ def close_connection
133
+ client&.close
134
+ end
135
+
136
+ #
137
+ # Overrides device screen dimensions and emulates viewport according to parameters
138
+ #
139
+ # Read more [here](https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDeviceMetricsOverride).
140
+ #
141
+ # @param [Integer] width width value in pixels. 0 disables the override
142
+ #
143
+ # @param [Integer] height height value in pixels. 0 disables the override
144
+ #
145
+ # @param [Float] scale_factor device scale factor value. 0 disables the override
146
+ #
147
+ # @param [Boolean] mobile whether to emulate mobile device
148
+ #
149
+ def set_viewport(width:, height:, scale_factor: 0, mobile: false)
150
+ command(
151
+ "Emulation.setDeviceMetricsOverride",
152
+ slowmoable: true,
153
+ width: width,
154
+ height: height,
155
+ deviceScaleFactor: scale_factor,
156
+ mobile: mobile
157
+ )
134
158
  end
135
159
 
136
160
  def resize(width: nil, height: nil, fullscreen: false)
137
161
  if fullscreen
138
162
  width, height = document_size
139
- set_window_bounds(windowState: "fullscreen")
163
+ self.window_bounds = { window_state: "fullscreen" }
140
164
  else
141
- set_window_bounds(windowState: "normal")
142
- set_window_bounds(width: width, height: height)
165
+ self.window_bounds = { window_state: "normal" }
166
+ self.window_bounds = { width: width, height: height }
143
167
  end
144
168
 
145
- command("Emulation.setDeviceMetricsOverride", slowmoable: true,
146
- width: width,
147
- height: height,
148
- deviceScaleFactor: 0,
149
- mobile: false)
169
+ set_viewport(width: width, height: height)
150
170
  end
151
171
 
152
172
  #
153
- # The current position of the browser window.
173
+ # Disables JavaScript execution from the HTML source for the page.
174
+ #
175
+ # This doesn't prevent users evaluate JavaScript with Ferrum.
176
+ #
177
+ def disable_javascript
178
+ command("Emulation.setScriptExecutionDisabled", value: true)
179
+ end
180
+
181
+ #
182
+ # The current position of the window.
154
183
  #
155
184
  # @return [(Integer, Integer)]
156
- # The left, top coordinates of the browser window.
185
+ # The left, top coordinates of the window.
157
186
  #
158
187
  # @example
159
- # browser.position # => [10, 20]
188
+ # page.position # => [10, 20]
160
189
  #
161
190
  def position
162
- @browser.command("Browser.getWindowBounds", windowId: window_id).fetch("bounds").values_at("left", "top")
191
+ window_bounds.values_at("left", "top")
163
192
  end
164
193
 
165
194
  #
166
- # Sets the position of the browser window.
195
+ # Sets the position of the window.
167
196
  #
168
197
  # @param [Hash{Symbol => Object}] options
169
198
  #
@@ -174,20 +203,72 @@ module Ferrum
174
203
  # The number of pixels from the top of the screen.
175
204
  #
176
205
  # @example
177
- # browser.position = { left: 10, top: 20 }
206
+ # page.position = { left: 10, top: 20 }
178
207
  #
179
208
  def position=(options)
180
- @browser.command("Browser.setWindowBounds",
181
- windowId: window_id,
182
- bounds: { left: options[:left], top: options[:top] })
209
+ self.window_bounds = { left: options[:left], top: options[:top] }
210
+ end
211
+
212
+ # Sets the position of the window.
213
+ #
214
+ # @param [Hash{Symbol => Object}] bounds
215
+ #
216
+ # @option options [Integer] :left
217
+ # The number of pixels from the left-hand side of the screen.
218
+ #
219
+ # @option options [Integer] :top
220
+ # The number of pixels from the top of the screen.
221
+ #
222
+ # @option options [Integer] :width
223
+ # The window width in pixels.
224
+ #
225
+ # @option options [Integer] :height
226
+ # The window height in pixels.
227
+ #
228
+ # @option options [String] :window_state
229
+ # The window state. Default to normal. Allowed Values: normal, minimized, maximized, fullscreen
230
+ #
231
+ # @example
232
+ # page.window_bounds = { left: 10, top: 20, width: 1024, height: 768, window_state: "normal" }
233
+ #
234
+ def window_bounds=(bounds)
235
+ options = bounds.dup
236
+ window_state = options.delete(:window_state)
237
+ bounds = { windowState: window_state, **options }.compact
238
+
239
+ client.command("Browser.setWindowBounds", windowId: window_id, bounds: bounds)
240
+ end
241
+
242
+ #
243
+ # Current window bounds.
244
+ #
245
+ # @return [Hash{String => (Integer, String)}]
246
+ #
247
+ # @example
248
+ # page.window_bounds # => { "left": 0, "top": 1286, "width": 10, "height": 10, "windowState": "normal" }
249
+ #
250
+ def window_bounds
251
+ client.command("Browser.getWindowBounds", windowId: window_id).fetch("bounds")
252
+ end
253
+
254
+ #
255
+ # Current window id.
256
+ #
257
+ # @return [Integer]
258
+ #
259
+ # @example
260
+ # page.window_id # => 1
261
+ #
262
+ def window_id
263
+ client.command("Browser.getWindowForTarget", targetId: target_id)["windowId"]
183
264
  end
184
265
 
185
266
  #
186
267
  # Reloads the current page.
187
268
  #
188
269
  # @example
189
- # browser.go_to("https://github.com/")
190
- # browser.refresh
270
+ # page.go_to("https://github.com/")
271
+ # page.refresh
191
272
  #
192
273
  def refresh
193
274
  command("Page.reload", wait: timeout, slowmoable: true)
@@ -198,41 +279,41 @@ module Ferrum
198
279
  # Stop all navigations and loading pending resources on the page.
199
280
  #
200
281
  # @example
201
- # browser.go_to("https://github.com/")
202
- # browser.stop
282
+ # page.go_to("https://github.com/")
283
+ # page.stop
203
284
  #
204
285
  def stop
205
286
  command("Page.stopLoading", slowmoable: true)
206
287
  end
207
288
 
208
289
  #
209
- # Navigates to the previous URL in the browser's history.
290
+ # Navigates to the previous URL in the history.
210
291
  #
211
292
  # @example
212
- # browser.go_to("https://github.com/")
213
- # browser.at_xpath("//a").click
214
- # browser.back
293
+ # page.go_to("https://github.com/")
294
+ # page.at_xpath("//a").click
295
+ # page.back
215
296
  #
216
297
  def back
217
298
  history_navigate(delta: -1)
218
299
  end
219
300
 
220
301
  #
221
- # Navigates to the next URL in the browser's history.
302
+ # Navigates to the next URL in the history.
222
303
  #
223
304
  # @example
224
- # browser.go_to("https://github.com/")
225
- # browser.at_xpath("//a").click
226
- # browser.back
227
- # browser.forward
305
+ # page.go_to("https://github.com/")
306
+ # page.at_xpath("//a").click
307
+ # page.back
308
+ # page.forward
228
309
  #
229
310
  def forward
230
311
  history_navigate(delta: 1)
231
312
  end
232
313
 
233
- def wait_for_reload(sec = 1)
314
+ def wait_for_reload(timeout = 1)
234
315
  @event.reset if @event.set?
235
- @event.wait(sec)
316
+ @event.wait(timeout)
236
317
  @event.set
237
318
  end
238
319
 
@@ -244,29 +325,21 @@ module Ferrum
244
325
  # @return [Boolean]
245
326
  #
246
327
  # @example
247
- # browser.bypass_csp # => true
248
- # browser.go_to("https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md")
249
- # browser.refresh
250
- # browser.add_script_tag(content: "window.__injected = 42")
251
- # browser.evaluate("window.__injected") # => 42
328
+ # page.bypass_csp # => true
329
+ # page.go_to("https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md")
330
+ # page.refresh
331
+ # page.add_script_tag(content: "window.__injected = 42")
332
+ # page.evaluate("window.__injected") # => 42
252
333
  #
253
334
  def bypass_csp(enabled: true)
254
335
  command("Page.setBypassCSP", enabled: enabled)
255
336
  enabled
256
337
  end
257
338
 
258
- def window_id
259
- @browser.command("Browser.getWindowForTarget", targetId: @target_id)["windowId"]
260
- end
261
-
262
- def set_window_bounds(bounds = {})
263
- @browser.command("Browser.setWindowBounds", windowId: window_id, bounds: bounds)
264
- end
265
-
266
339
  def command(method, wait: 0, slowmoable: false, **params)
267
340
  iteration = @event.reset if wait.positive?
268
- sleep(@browser.options.slowmo) if slowmoable && @browser.options.slowmo.positive?
269
- result = @client.command(method, params)
341
+ sleep(@options.slowmo) if slowmoable && @options.slowmo.positive?
342
+ result = client.command(method, **params)
270
343
 
271
344
  if wait.positive?
272
345
  # Wait a bit after command and check if iteration has
@@ -284,30 +357,30 @@ module Ferrum
284
357
  def on(name, &block)
285
358
  case name
286
359
  when :dialog
287
- @client.on("Page.javascriptDialogOpening") do |params, index, total|
360
+ client.on("Page.javascriptDialogOpening") do |params, index, total|
288
361
  dialog = Dialog.new(self, params)
289
362
  block.call(dialog, index, total)
290
363
  end
291
364
  when :request
292
- @client.on("Fetch.requestPaused") do |params, index, total|
293
- request = Network::InterceptedRequest.new(self, params)
365
+ client.on("Fetch.requestPaused") do |params, index, total|
366
+ request = Network::InterceptedRequest.new(client, params)
294
367
  exchange = network.select(request.network_id).last
295
368
  exchange ||= network.build_exchange(request.network_id)
296
369
  exchange.intercepted_request = request
297
370
  block.call(request, index, total)
298
371
  end
299
372
  when :auth
300
- @client.on("Fetch.authRequired") do |params, index, total|
373
+ client.on("Fetch.authRequired") do |params, index, total|
301
374
  request = Network::AuthRequest.new(self, params)
302
375
  block.call(request, index, total)
303
376
  end
304
377
  else
305
- @client.on(name, &block)
378
+ client.on(name, &block)
306
379
  end
307
380
  end
308
381
 
309
382
  def subscribed?(event)
310
- @client.subscribed?(event)
383
+ client.subscribed?(event)
311
384
  end
312
385
 
313
386
  def use_proxy?
@@ -327,14 +400,15 @@ module Ferrum
327
400
  def subscribe
328
401
  frames_subscribe
329
402
  network.subscribe
403
+ downloads.subscribe
330
404
 
331
- if @browser.options.logger
405
+ if @options.logger
332
406
  on("Runtime.consoleAPICalled") do |params|
333
- params["args"].each { |r| @browser.options.logger.puts(r["value"]) }
407
+ params["args"].each { |r| @options.logger.puts(r["value"]) }
334
408
  end
335
409
  end
336
410
 
337
- if @browser.options.js_errors
411
+ if @options.js_errors
338
412
  on("Runtime.exceptionThrown") do |params|
339
413
  # FIXME: https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/
340
414
  Thread.main.raise JavaScriptError.new(
@@ -369,26 +443,14 @@ module Ferrum
369
443
  end
370
444
  end
371
445
 
372
- if @browser.options.save_path
373
- unless Pathname.new(@browser.options.save_path).absolute?
374
- raise Error, "supply absolute path for `:save_path` option"
375
- end
446
+ downloads.set_behavior(save_path: @options.save_path) if @options.save_path
376
447
 
377
- @browser.command("Browser.setDownloadBehavior",
378
- browserContextId: context.id,
379
- downloadPath: @browser.options.save_path,
380
- behavior: "allow", eventsEnabled: true)
381
- end
382
-
383
- @browser.extensions.each do |extension|
448
+ @options.extensions.each do |extension|
384
449
  command("Page.addScriptToEvaluateOnNewDocument", source: extension)
385
450
  end
386
451
 
387
452
  inject_extensions
388
453
 
389
- width, height = @browser.window_size
390
- resize(width: width, height: height)
391
-
392
454
  response = command("Page.getNavigationHistory")
393
455
  transition_type = response.dig("entries", 0, "transitionType")
394
456
  return if transition_type == "auto_toplevel"
@@ -402,7 +464,7 @@ module Ferrum
402
464
  end
403
465
 
404
466
  def inject_extensions
405
- @browser.extensions.each do |extension|
467
+ @options.extensions.each do |extension|
406
468
  # https://github.com/GoogleChrome/puppeteer/issues/1443
407
469
  # https://github.com/ChromeDevTools/devtools-protocol/issues/77
408
470
  # https://github.com/cyrus-and/chrome-remote-interface/issues/319
@@ -432,22 +494,18 @@ module Ferrum
432
494
  url = Addressable::URI.parse(url_or_path)
433
495
  nil_or_relative = url.nil? || url.relative?
434
496
 
435
- if nil_or_relative && !@browser.base_url
497
+ if nil_or_relative && !@options.base_url
436
498
  raise "Set :base_url browser's option or use absolute url in `go_to`, you passed: #{url_or_path}"
437
499
  end
438
500
 
439
- (nil_or_relative ? @browser.base_url.join(url.to_s) : url).to_s
440
- end
441
-
442
- def ws_url
443
- "ws://#{@browser.process.host}:#{@browser.process.port}/devtools/page/#{@target_id}"
501
+ (nil_or_relative ? @options.base_url.join(url.to_s) : url).to_s
444
502
  end
445
503
 
446
504
  def proxy=(options)
447
- @proxy_host = options&.[](:host) || @browser.options.proxy&.[](:host)
448
- @proxy_port = options&.[](:port) || @browser.options.proxy&.[](:port)
449
- @proxy_user = options&.[](:user) || @browser.options.proxy&.[](:user)
450
- @proxy_password = options&.[](:password) || @browser.options.proxy&.[](:password)
505
+ @proxy_host = options&.[](:host) || @options.proxy&.[](:host)
506
+ @proxy_port = options&.[](:port) || @options.proxy&.[](:port)
507
+ @proxy_user = options&.[](:user) || @options.proxy&.[](:user)
508
+ @proxy_password = options&.[](:password) || @options.proxy&.[](:password)
451
509
  end
452
510
  end
453
511
  end
data/lib/ferrum/proxy.rb CHANGED
@@ -52,7 +52,7 @@ module Ferrum
52
52
  end
53
53
 
54
54
  def stop
55
- @file&.unlink
55
+ @file&.close(true)
56
56
  @server.shutdown
57
57
  end
58
58