ferrum 0.12 → 0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -22
  3. data/lib/ferrum/browser/client.rb +6 -5
  4. data/lib/ferrum/browser/command.rb +9 -6
  5. data/lib/ferrum/browser/options/base.rb +1 -4
  6. data/lib/ferrum/browser/options/chrome.rb +22 -10
  7. data/lib/ferrum/browser/options/firefox.rb +3 -6
  8. data/lib/ferrum/browser/options.rb +84 -0
  9. data/lib/ferrum/browser/process.rb +6 -7
  10. data/lib/ferrum/browser/version_info.rb +71 -0
  11. data/lib/ferrum/browser/web_socket.rb +1 -1
  12. data/lib/ferrum/browser/xvfb.rb +1 -1
  13. data/lib/ferrum/browser.rb +184 -64
  14. data/lib/ferrum/context.rb +3 -2
  15. data/lib/ferrum/contexts.rb +2 -2
  16. data/lib/ferrum/cookies/cookie.rb +183 -0
  17. data/lib/ferrum/cookies.rb +122 -49
  18. data/lib/ferrum/dialog.rb +30 -0
  19. data/lib/ferrum/frame/dom.rb +177 -0
  20. data/lib/ferrum/frame/runtime.rb +41 -61
  21. data/lib/ferrum/frame.rb +91 -3
  22. data/lib/ferrum/headers.rb +28 -0
  23. data/lib/ferrum/keyboard.rb +45 -2
  24. data/lib/ferrum/mouse.rb +84 -0
  25. data/lib/ferrum/network/exchange.rb +104 -5
  26. data/lib/ferrum/network/intercepted_request.rb +3 -12
  27. data/lib/ferrum/network/request.rb +58 -19
  28. data/lib/ferrum/network/request_params.rb +57 -0
  29. data/lib/ferrum/network/response.rb +106 -4
  30. data/lib/ferrum/network.rb +193 -8
  31. data/lib/ferrum/node.rb +21 -1
  32. data/lib/ferrum/page/animation.rb +16 -0
  33. data/lib/ferrum/page/frames.rb +66 -11
  34. data/lib/ferrum/page/screenshot.rb +97 -0
  35. data/lib/ferrum/page/tracing.rb +26 -0
  36. data/lib/ferrum/page.rb +158 -45
  37. data/lib/ferrum/proxy.rb +91 -2
  38. data/lib/ferrum/target.rb +6 -4
  39. data/lib/ferrum/version.rb +1 -1
  40. metadata +7 -101
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e4ca57662283c8c6b917aa3e2f1f06b154cb66ffdd8522756f55e09be84a423
4
- data.tar.gz: 50d37d615399fe481634154d619d55872ee13b0cace511a1b147da38454247b5
3
+ metadata.gz: 6cbef2f4caac663a8b39afc37b94e46f00c9471cdaea36a1781dcfa99488a546
4
+ data.tar.gz: 58d8f68e84138b71de15ac33368d4cd4f8992db4ab7f321a3e3f03530968502b
5
5
  SHA512:
6
- metadata.gz: 9cc514740ae8041b61a184bdeee0a44ce26b276f36af0358c6a00524f8e13b6db9ddda48acf5781c4122acaa4980579cf06053ffb420c2013e0b44177eab2571
7
- data.tar.gz: cc00b6d3cb440db600241156354dcd92a6bf67c0402b9e2881f32ea507549d80f69b51011bb246baf9faf95f33e5596933ce569cd9b03f41c7cc066d215b6073
6
+ metadata.gz: a621c8e99fe1ec5e183ad54681da4a6bf09105fc66477c37b76b59cb1842f679ac679690514de1829fbbe18af4b81e0e01a64b564a48db9c49af151fc5b64e51
7
+ data.tar.gz: cc3089d1b9a81d43e8dbeb356b0d677d5377bc1d1d4667e0da9f389034e044ef0497ced614b39812cff53dd70930ec1f66e473f2a30a7edad825dd3424df7e54
data/README.md CHANGED
@@ -134,6 +134,7 @@ In docker as root you must pass the no-sandbox browser option:
134
134
  Ferrum::Browser.new(browser_options: { 'no-sandbox': nil })
135
135
  ```
136
136
 
137
+ It has also been reported that the Chrome process repeatedly crashes when running inside a Docker container on an M1 Mac preventing Ferrum from working. Ferrum should work as expected when deployed to a Docker container on a non-M1 Mac.
137
138
 
138
139
  ## Customization
139
140
 
@@ -144,7 +145,8 @@ Ferrum::Browser.new(options)
144
145
  ```
145
146
 
146
147
  * options `Hash`
147
- * `:headless` (Boolean) - Set browser as headless or not, `true` by default.
148
+ * `:headless` (String | Boolean) - Set browser as headless or not, `true` by default. You can set `"new"` to support
149
+ [new headless mode](https://developer.chrome.com/articles/new-headless/).
148
150
  * `:xvfb` (Boolean) - Run browser in a virtual framebuffer, `false` by default.
149
151
  * `:window_size` (Array) - The dimensions of the browser window in which to
150
152
  test, expressed as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
@@ -154,7 +156,7 @@ Ferrum::Browser.new(options)
154
156
  * `:logger` (Object responding to `puts`) - When present, debug output is
155
157
  written to this object.
156
158
  * `:slowmo` (Integer | Float) - Set a delay in seconds to wait before sending command.
157
- Usefull companion of headless option, so that you have time to see changes.
159
+ Useful companion of headless option, so that you have time to see changes.
158
160
  * `:timeout` (Numeric) - The number of seconds we'll wait for a response when
159
161
  communicating with browser. Default is 5.
160
162
  * `:js_errors` (Boolean) - When true, JavaScript errors get re-raised in Ruby.
@@ -595,47 +597,49 @@ Activates offline mode for a page.
595
597
 
596
598
  ```ruby
597
599
  browser.network.offline_mode
598
- browser.go_to("https://github.com/") # => Ferrum::StatusError (Request to https://github.com/ failed to reach server, check DNS and server status)
600
+ browser.go_to("https://github.com/") # => Ferrum::StatusError (Request to https://github.com/ failed(net::ERR_INTERNET_DISCONNECTED))
599
601
  ```
600
602
 
603
+ #### cache(disable: `Boolean`)
604
+
605
+ Toggles ignoring cache for each request. If true, cache will not be used.
606
+
607
+ ```ruby
608
+ browser.network.cache(disable: true)
609
+ ```
601
610
 
602
611
  ## Proxy
603
612
 
604
- You can set a proxy with the `proxy` option.
613
+ You can set a proxy with a `:proxy` option:
614
+
615
+ ```ruby
616
+ browser = Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", user: "user", password: "pa$$" })
617
+ ```
618
+
619
+ `:bypass` can specify semi-colon-separated list of hosts for which proxy shouldn't be used:
605
620
 
606
621
  ```ruby
607
- browser = Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800" })
608
- browser = Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", user: "user", pasword: "pa$$" })
622
+ browser = Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", bypass: "*.google.com;*foo.com" })
609
623
  ```
610
624
 
611
- Chrome Devtools Protocol does not support changing proxies after the browser is launched. If you want to change proxies, you must restart your browser, which may not be convenient. There is a workaround. Ferrum provides a wrapper for a proxy server that can rotate proxies. We can run a proxy in the same process and rotate proxies inside this proxy server:
625
+ In general passing a proxy option when instantiating a browser results in a browser running with proxy command line
626
+ flags, so that it affects all pages and contexts. You can create a page in a new context which can use its own proxy
627
+ settings:
612
628
 
613
629
  ```ruby
614
- browser = Ferrum::Browser.new(proxy: { server: true })
630
+ browser = Ferrum::Browser.new
615
631
 
616
- browser.proxy_server.rotate(host: "x.x.x.x", port: 31337, user: "user", password: "password")
617
- browser.create_page(new_context: true) do |page|
632
+ browser.create_page(proxy: { host: "x.x.x.x", port: 31337, user: "user", password: "password" }) do |page|
618
633
  page.go_to("https://api.ipify.org?format=json")
619
634
  page.body # => "x.x.x.x"
620
635
  end
621
636
 
622
- browser.proxy_server.rotate(host: "y.y.y.y", port: 31337, user: "user", password: "password")
623
- browser.create_page(new_context: true) do |page|
637
+ browser.create_page(proxy: { host: "y.y.y.y", port: 31337, user: "user", password: "password" }) do |page|
624
638
  page.go_to("https://api.ipify.org?format=json")
625
639
  page.body # => "y.y.y.y"
626
640
  end
627
641
  ```
628
642
 
629
- Make sure to create page in the new context, because Chrome doesn't break the connection with the proxy for `CONNECT`
630
- requests even if you close the page.
631
-
632
- You can specify semi-colon-separated list of hosts for which proxy shouldn't be used:
633
-
634
- ```ruby
635
- browser = Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", bypass: "*.google.com;*foo.com" })
636
- browser = Ferrum::Browser.new(proxy: { server: true, bypass: "*.google.com;*foo.com" })
637
- ```
638
-
639
643
 
640
644
  ### Mouse
641
645
 
@@ -1133,6 +1137,8 @@ frame.at_css("//a[text() = 'Log in']") # => Node
1133
1137
  #### evaluate
1134
1138
  #### selected : `Array<Node>`
1135
1139
  #### select
1140
+ #### scroll_into_view
1141
+ #### in_viewport?(of: `Node | nil`) : `Boolean`
1136
1142
 
1137
1143
  (chainable) Selects options by passed attribute.
1138
1144
 
@@ -8,11 +8,11 @@ module Ferrum
8
8
  class Client
9
9
  INTERRUPTIONS = %w[Fetch.requestPaused Fetch.authRequired].freeze
10
10
 
11
- def initialize(browser, ws_url, id_starts_with: 0)
12
- @browser = browser
11
+ def initialize(ws_url, connectable, logger: nil, ws_max_receive_size: nil, id_starts_with: 0)
12
+ @connectable = connectable
13
13
  @command_id = id_starts_with
14
14
  @pendings = Concurrent::Hash.new
15
- @ws = WebSocket.new(ws_url, @browser.ws_max_receive_size, @browser.logger)
15
+ @ws = WebSocket.new(ws_url, ws_max_receive_size, logger)
16
16
  @subscriber, @interrupter = Subscriber.build(2)
17
17
 
18
18
  @thread = Thread.new do
@@ -39,7 +39,7 @@ module Ferrum
39
39
  message = build_message(method, params)
40
40
  @pendings[message[:id]] = pending
41
41
  @ws.send_message(message)
42
- data = pending.value!(@browser.timeout)
42
+ data = pending.value!(@connectable.timeout)
43
43
  @pendings.delete(message[:id])
44
44
 
45
45
  raise DeadBrowserError if data.nil? && @ws.messages.closed?
@@ -84,7 +84,8 @@ module Ferrum
84
84
  case error["message"]
85
85
  # Node has disappeared while we were trying to get it
86
86
  when "No node with given id found",
87
- "Could not find node with given id"
87
+ "Could not find node with given id",
88
+ "Inspected target navigated or closed"
88
89
  raise NodeNotFoundError, error
89
90
  # Context is lost, page is reloading
90
91
  when "Cannot find context with specified id"
@@ -10,7 +10,7 @@ module Ferrum
10
10
  # Currently only these browsers support CDP:
11
11
  # https://github.com/cyrus-and/chrome-remote-interface#implementations
12
12
  def self.build(options, user_data_dir)
13
- defaults = case options[:browser_name]
13
+ defaults = case options.browser_name
14
14
  when :firefox
15
15
  Options::Firefox.options
16
16
  when :chrome, :opera, :edge, nil
@@ -29,14 +29,18 @@ module Ferrum
29
29
  @defaults = defaults
30
30
  @options = options
31
31
  @user_data_dir = user_data_dir
32
- @path = options[:browser_path] || ENV.fetch("BROWSER_PATH", nil) || defaults.detect_path
32
+ @path = options.browser_path || ENV.fetch("BROWSER_PATH", nil) || defaults.detect_path
33
33
  raise BinaryNotFoundError, NOT_FOUND unless @path
34
34
 
35
35
  merge_options
36
36
  end
37
37
 
38
38
  def xvfb?
39
- !!options[:xvfb]
39
+ !!options.xvfb
40
+ end
41
+
42
+ def headless_new?
43
+ @flags["headless"] == "new"
40
44
  end
41
45
 
42
46
  def to_a
@@ -47,9 +51,8 @@ module Ferrum
47
51
 
48
52
  def merge_options
49
53
  @flags = defaults.merge_required(@flags, options, @user_data_dir)
50
- @flags = defaults.merge_default(@flags, options) unless options[:ignore_default_browser_options]
51
-
52
- @flags.merge!(options.fetch(:browser_options, {}))
54
+ @flags = defaults.merge_default(@flags, options) unless options.ignore_default_browser_options
55
+ @flags.merge!(options.browser_options)
53
56
  end
54
57
  end
55
58
  end
@@ -4,11 +4,8 @@ require "singleton"
4
4
 
5
5
  module Ferrum
6
6
  class Browser
7
- module Options
7
+ class Options
8
8
  class Base
9
- BROWSER_HOST = "127.0.0.1"
10
- BROWSER_PORT = "0"
11
-
12
9
  include Singleton
13
10
 
14
11
  def self.options
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Ferrum
4
4
  class Browser
5
- module Options
5
+ class Options
6
6
  class Chrome < Base
7
7
  DEFAULT_OPTIONS = {
8
8
  "headless" => nil,
@@ -19,8 +19,9 @@ module Ferrum
19
19
  "keep-alive-for-test" => nil,
20
20
  "disable-popup-blocking" => nil,
21
21
  "disable-extensions" => nil,
22
+ "disable-component-extensions-with-background-pages" => nil,
22
23
  "disable-hang-monitor" => nil,
23
- "disable-features" => "site-per-process,TranslateUI",
24
+ "disable-features" => "site-per-process,IsolateOrigins,TranslateUI",
24
25
  "disable-translate" => nil,
25
26
  "disable-background-networking" => nil,
26
27
  "enable-features" => "NetworkService,NetworkServiceInProcess",
@@ -32,6 +33,7 @@ module Ferrum
32
33
  "disable-ipc-flooding-protection" => nil,
33
34
  "disable-prompt-on-repost" => nil,
34
35
  "disable-renderer-backgrounding" => nil,
36
+ "disable-site-isolation-trials" => nil,
35
37
  "force-color-profile" => "srgb",
36
38
  "metrics-recording-only" => nil,
37
39
  "safebrowsing-disable-auto-update" => nil,
@@ -59,17 +61,27 @@ module Ferrum
59
61
  }.freeze
60
62
 
61
63
  def merge_required(flags, options, user_data_dir)
62
- port = options.fetch(:port, BROWSER_PORT)
63
- host = options.fetch(:host, BROWSER_HOST)
64
- flags.merge("remote-debugging-port" => port,
65
- "remote-debugging-address" => host,
66
- # Doesn't work on MacOS, so we need to set it by CDP
67
- "window-size" => options[:window_size]&.join(","),
68
- "user-data-dir" => user_data_dir)
64
+ flags = flags.merge("remote-debugging-port" => options.port,
65
+ "remote-debugging-address" => options.host,
66
+ # Doesn't work on MacOS, so we need to set it by CDP
67
+ "window-size" => options.window_size&.join(","),
68
+ "user-data-dir" => user_data_dir)
69
+
70
+ if options.proxy
71
+ flags.merge!("proxy-server" => "#{options.proxy[:host]}:#{options.proxy[:port]}")
72
+ flags.merge!("proxy-bypass-list" => options.proxy[:bypass]) if options.proxy[:bypass]
73
+ end
74
+
75
+ flags
69
76
  end
70
77
 
71
78
  def merge_default(flags, options)
72
- defaults = except("headless", "disable-gpu") unless options.fetch(:headless, true)
79
+ defaults = case options.headless
80
+ when false
81
+ except("headless", "disable-gpu")
82
+ when "new"
83
+ except("headless").merge("headless" => "new")
84
+ end
73
85
 
74
86
  defaults ||= DEFAULT_OPTIONS
75
87
  defaults.merge(flags)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Ferrum
4
4
  class Browser
5
- module Options
5
+ class Options
6
6
  class Firefox < Base
7
7
  DEFAULT_OPTIONS = {
8
8
  "headless" => nil
@@ -23,14 +23,11 @@ module Ferrum
23
23
  }.freeze
24
24
 
25
25
  def merge_required(flags, options, user_data_dir)
26
- port = options.fetch(:port, BROWSER_PORT)
27
- host = options.fetch(:host, BROWSER_HOST)
28
- flags.merge("remote-debugger" => "#{host}:#{port}",
29
- "profile" => user_data_dir)
26
+ flags.merge("remote-debugger" => "#{options.host}:#{options.port}", "profile" => user_data_dir)
30
27
  end
31
28
 
32
29
  def merge_default(flags, options)
33
- defaults = except("headless") unless options.fetch(:headless, true)
30
+ defaults = except("headless") unless options.headless
34
31
 
35
32
  defaults ||= DEFAULT_OPTIONS
36
33
  defaults.merge(flags)
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ferrum
4
+ class Browser
5
+ class Options
6
+ HEADLESS = true
7
+ BROWSER_PORT = "0"
8
+ BROWSER_HOST = "127.0.0.1"
9
+ WINDOW_SIZE = [1024, 768].freeze
10
+ BASE_URL_SCHEMA = %w[http https].freeze
11
+ DEFAULT_TIMEOUT = ENV.fetch("FERRUM_DEFAULT_TIMEOUT", 5).to_i
12
+ PROCESS_TIMEOUT = ENV.fetch("FERRUM_PROCESS_TIMEOUT", 10).to_i
13
+ DEBUG_MODE = !ENV.fetch("FERRUM_DEBUG", nil).nil?
14
+
15
+ attr_reader :window_size, :timeout, :logger, :ws_max_receive_size,
16
+ :js_errors, :base_url, :slowmo, :pending_connection_errors,
17
+ :url, :env, :process_timeout, :browser_name, :browser_path,
18
+ :save_path, :extensions, :proxy, :port, :host, :headless,
19
+ :ignore_default_browser_options, :browser_options, :xvfb
20
+
21
+ def initialize(options = nil)
22
+ @options = Hash(options&.dup)
23
+ @port = @options.fetch(:port, BROWSER_PORT)
24
+ @host = @options.fetch(:host, BROWSER_HOST)
25
+ @timeout = @options.fetch(:timeout, DEFAULT_TIMEOUT)
26
+ @window_size = @options.fetch(:window_size, WINDOW_SIZE)
27
+ @js_errors = @options.fetch(:js_errors, false)
28
+ @headless = @options.fetch(:headless, HEADLESS)
29
+ @pending_connection_errors = @options.fetch(:pending_connection_errors, true)
30
+ @process_timeout = @options.fetch(:process_timeout, PROCESS_TIMEOUT)
31
+ @browser_options = @options.fetch(:browser_options, {})
32
+ @slowmo = @options[:slowmo].to_f
33
+
34
+ @ws_max_receive_size, @env, @browser_name, @browser_path,
35
+ @save_path, @extensions, @ignore_default_browser_options, @xvfb = @options.values_at(
36
+ :ws_max_receive_size, :env, :browser_name, :browser_path, :save_path, :extensions,
37
+ :ignore_default_browser_options, :xvfb
38
+ )
39
+
40
+ @options[:window_size] = @window_size
41
+ @proxy = parse_proxy(@options[:proxy])
42
+ @logger = parse_logger(@options[:logger])
43
+ @base_url = parse_base_url(@options[:base_url]) if @options[:base_url]
44
+ @url = @options[:url].to_s if @options[:url]
45
+
46
+ @options.freeze
47
+ @browser_options.freeze
48
+ end
49
+
50
+ def to_h
51
+ @options
52
+ end
53
+
54
+ def parse_base_url(value)
55
+ parsed = Addressable::URI.parse(value)
56
+ unless BASE_URL_SCHEMA.include?(parsed&.normalized_scheme)
57
+ raise ArgumentError, "`base_url` should be absolute and include schema: #{BASE_URL_SCHEMA.join(' | ')}"
58
+ end
59
+
60
+ parsed
61
+ end
62
+
63
+ def parse_proxy(options)
64
+ return unless options
65
+
66
+ raise ArgumentError, "proxy options must be a Hash" unless options.is_a?(Hash)
67
+
68
+ if options[:host].nil? && options[:port].nil?
69
+ raise ArgumentError, "proxy options must be a Hash with at least :host | :port"
70
+ end
71
+
72
+ options
73
+ end
74
+
75
+ private
76
+
77
+ def parse_logger(logger)
78
+ return logger if logger
79
+
80
+ !logger && DEBUG_MODE ? $stdout.tap { |s| s.sync = true } : logger
81
+ end
82
+ end
83
+ end
84
+ end
@@ -15,7 +15,6 @@ module Ferrum
15
15
  class Process
16
16
  KILL_TIMEOUT = 2
17
17
  WAIT_KILLED = 0.05
18
- PROCESS_TIMEOUT = ENV.fetch("FERRUM_PROCESS_TIMEOUT", 10).to_i
19
18
 
20
19
  attr_reader :host, :port, :ws_url, :pid, :command,
21
20
  :default_user_agent, :browser_version, :protocol_version,
@@ -63,17 +62,17 @@ module Ferrum
63
62
  def initialize(options)
64
63
  @pid = @xvfb = @user_data_dir = nil
65
64
 
66
- if options[:url]
67
- url = URI.join(options[:url].to_s, "/json/version")
65
+ if options.url
66
+ url = URI.join(options.url, "/json/version")
68
67
  response = JSON.parse(::Net::HTTP.get(url))
69
68
  self.ws_url = response["webSocketDebuggerUrl"]
70
69
  parse_browser_versions
71
70
  return
72
71
  end
73
72
 
74
- @logger = options[:logger]
75
- @process_timeout = options.fetch(:process_timeout, PROCESS_TIMEOUT)
76
- @env = Hash(options[:env])
73
+ @logger = options.logger
74
+ @process_timeout = options.process_timeout
75
+ @env = Hash(options.env)
77
76
 
78
77
  tmpdir = Dir.mktmpdir("ferrum_user_data_dir_")
79
78
  ObjectSpace.define_finalizer(self, self.class.directory_remover(tmpdir))
@@ -138,7 +137,7 @@ module Ferrum
138
137
  output = ""
139
138
  start = Utils::ElapsedTime.monotonic_time
140
139
  max_time = start + timeout
141
- regexp = %r{DevTools listening on (ws://.*)}
140
+ regexp = %r{DevTools listening on (ws://.*[a-zA-Z0-9-]{36})}
142
141
  while (now = Utils::ElapsedTime.monotonic_time) < max_time
143
142
  begin
144
143
  output += read_io.read_nonblock(512)
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ferrum
4
+ class Browser
5
+ #
6
+ # The browser's version information returned by [Browser.getVersion].
7
+ #
8
+ # [Browser.getVersion]: https://chromedevtools.github.io/devtools-protocol/1-3/Browser/#method-getVersion
9
+ #
10
+ # @since 0.13
11
+ #
12
+ class VersionInfo
13
+ #
14
+ # Initializes the browser's version information.
15
+ #
16
+ # @param [Hash{String => Object}] properties
17
+ # The object properties returned by [Browser.getVersion](https://chromedevtools.github.io/devtools-protocol/1-3/Browser/#method-getVersion).
18
+ #
19
+ # @api private
20
+ #
21
+ def initialize(properties)
22
+ @properties = properties
23
+ end
24
+
25
+ #
26
+ # The Chrome DevTools protocol version.
27
+ #
28
+ # @return [String]
29
+ #
30
+ def protocol_version
31
+ @properties["protocolVersion"]
32
+ end
33
+
34
+ #
35
+ # The Chrome version.
36
+ #
37
+ # @return [String]
38
+ #
39
+ def product
40
+ @properties["product"]
41
+ end
42
+
43
+ #
44
+ # The Chrome revision properties.
45
+ #
46
+ # @return [String]
47
+ #
48
+ def revision
49
+ @properties["revision"]
50
+ end
51
+
52
+ #
53
+ # The Chrome `User-Agent` string.
54
+ #
55
+ # @return [String]
56
+ #
57
+ def user_agent
58
+ @properties["userAgent"]
59
+ end
60
+
61
+ #
62
+ # The JavaScript engine version.
63
+ #
64
+ # @return [String]
65
+ #
66
+ def js_version
67
+ @properties["jsVersion"]
68
+ end
69
+ end
70
+ end
71
+ end
@@ -7,7 +7,7 @@ require "websocket/driver"
7
7
  module Ferrum
8
8
  class Browser
9
9
  class WebSocket
10
- WEBSOCKET_BUG_SLEEP = 0.01
10
+ WEBSOCKET_BUG_SLEEP = 0.05
11
11
  SKIP_LOGGING_SCREENSHOTS = !ENV["FERRUM_LOGGING_SCREENSHOTS"]
12
12
 
13
13
  attr_reader :url, :messages
@@ -16,7 +16,7 @@ module Ferrum
16
16
  @path = Binary.find("Xvfb")
17
17
  raise BinaryNotFoundError, NOT_FOUND unless @path
18
18
 
19
- @screen_size = "#{options.fetch(:window_size, [1024, 768]).join('x')}x24"
19
+ @screen_size = "#{options.window_size.join('x')}x24"
20
20
  @display_id = (Time.now.to_f * 1000).to_i % 100_000_000
21
21
  end
22
22