ferrum 0.7 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -71,23 +71,37 @@ 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")
77
+
78
+ unless @main_frame.id
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
85
+ end
86
+
76
87
  frame = @frames[frame_id] || Frame.new(frame_id, self)
77
- frame.execution_id = context_id
88
+ frame.set_execution_id(context_id)
89
+
90
+ # Set event because `execution_id` might raise NoExecutionContextError
91
+ @event.set if setting_up_main_frame
78
92
 
79
- @main_frame ||= frame
80
93
  @frames[frame_id] ||= frame
81
94
  end
82
95
 
83
96
  on("Runtime.executionContextDestroyed") do |params|
84
97
  execution_id = params["executionContextId"]
85
98
  frame = frames.find { |f| f.execution_id?(execution_id) }
86
- frame.execution_id = nil
99
+ frame.reset_execution_id
87
100
  end
88
101
 
89
102
  on("Runtime.executionContextsCleared") do
90
103
  @frames.delete_if { |_, f| !f.main? }
104
+ @main_frame.reset_execution_id
91
105
  end
92
106
  end
93
107
 
@@ -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
@@ -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
- save_file(path, data)
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
- data = command("Page.printToPDF", **options).fetch("data")
39
- return data if encoding == :base64
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
 
@@ -48,17 +64,39 @@ module Ferrum
48
64
 
49
65
  def document_size
50
66
  evaluate <<~JS
51
- [document.documentElement.offsetWidth,
52
- document.documentElement.offsetHeight]
67
+ [document.documentElement.scrollWidth,
68
+ document.documentElement.scrollHeight]
53
69
  JS
54
70
  end
55
71
 
56
72
  private
57
73
 
58
74
  def save_file(path, data)
59
- bin = Base64.decode64(data)
60
- return bin unless path
61
- File.open(path.to_s, "wb") { |f| f.write(bin) }
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, **_)
@@ -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
- command("Page.captureScreenshot", **options)
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
@@ -0,0 +1,38 @@
1
+ module Ferrum
2
+ class RGBA
3
+ def initialize(red, green, blue, alpha)
4
+ self.red = red
5
+ self.green = green
6
+ self.blue = blue
7
+ self.alpha = alpha
8
+
9
+ validate
10
+ end
11
+
12
+ def to_h
13
+ { r: red, g: green, b: blue, a: alpha }
14
+ end
15
+
16
+ private
17
+
18
+ attr_accessor :red, :green, :blue, :alpha
19
+
20
+ def validate
21
+ [red, green, blue].each(&method(:validate_color))
22
+ validate_alpha
23
+ end
24
+
25
+ def validate_color(value)
26
+ return if value && value.is_a?(Integer) && Range.new(0, 255).include?(value)
27
+
28
+ raise ArgumentError, "Wrong value of #{value} should be Integer from 0 to 255"
29
+ end
30
+
31
+ def validate_alpha
32
+ return if alpha && alpha.is_a?(Float) && Range.new(0.0, 1.0).include?(alpha)
33
+
34
+ raise ArgumentError,
35
+ "Wrong alpha value #{alpha} should be Float between 0.0 (fully transparent) and 1.0 (fully opaque)"
36
+ end
37
+ end
38
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ferrum
4
- VERSION = "0.7"
4
+ VERSION = "0.10.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ferrum
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.7'
4
+ version: 0.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Vorotilin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-28 00:00:00.000000000 Z
11
+ date: 2021-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: websocket-driver
@@ -64,28 +64,28 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '2.6'
67
+ version: '2.5'
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '2.6'
74
+ version: '2.5'
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: rake
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '12.3'
81
+ version: '13.0'
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '12.3'
88
+ version: '13.0'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: rspec
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -181,13 +181,15 @@ files:
181
181
  - README.md
182
182
  - lib/ferrum.rb
183
183
  - lib/ferrum/browser.rb
184
- - lib/ferrum/browser/chrome.rb
185
184
  - lib/ferrum/browser/client.rb
186
185
  - lib/ferrum/browser/command.rb
187
- - lib/ferrum/browser/firefox.rb
186
+ - lib/ferrum/browser/options/base.rb
187
+ - lib/ferrum/browser/options/chrome.rb
188
+ - lib/ferrum/browser/options/firefox.rb
188
189
  - lib/ferrum/browser/process.rb
189
190
  - lib/ferrum/browser/subscriber.rb
190
191
  - lib/ferrum/browser/web_socket.rb
192
+ - lib/ferrum/browser/xvfb.rb
191
193
  - lib/ferrum/context.rb
192
194
  - lib/ferrum/contexts.rb
193
195
  - lib/ferrum/cookies.rb
@@ -210,6 +212,7 @@ files:
210
212
  - lib/ferrum/page.rb
211
213
  - lib/ferrum/page/frames.rb
212
214
  - lib/ferrum/page/screenshot.rb
215
+ - lib/ferrum/rbga.rb
213
216
  - lib/ferrum/target.rb
214
217
  - lib/ferrum/version.rb
215
218
  homepage: https://github.com/route/ferrum
@@ -231,7 +234,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
234
  - !ruby/object:Gem::Version
232
235
  version: '0'
233
236
  requirements: []
234
- rubygems_version: 3.0.3
237
+ rubygems_version: 3.1.4
235
238
  signing_key:
236
239
  specification_version: 4
237
240
  summary: Ruby headless Chrome driver
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ferrum
4
- class Browser
5
- class Chrome < Command
6
- DEFAULT_OPTIONS = {
7
- "headless" => nil,
8
- "disable-gpu" => nil,
9
- "hide-scrollbars" => nil,
10
- "mute-audio" => nil,
11
- "enable-automation" => nil,
12
- "disable-web-security" => nil,
13
- "disable-session-crashed-bubble" => nil,
14
- "disable-breakpad" => nil,
15
- "disable-sync" => nil,
16
- "no-first-run" => nil,
17
- "use-mock-keychain" => nil,
18
- "keep-alive-for-test" => nil,
19
- "disable-popup-blocking" => nil,
20
- "disable-extensions" => nil,
21
- "disable-hang-monitor" => nil,
22
- "disable-features" => "site-per-process,TranslateUI",
23
- "disable-translate" => nil,
24
- "disable-background-networking" => nil,
25
- "enable-features" => "NetworkService,NetworkServiceInProcess",
26
- "disable-background-timer-throttling" => nil,
27
- "disable-backgrounding-occluded-windows" => nil,
28
- "disable-client-side-phishing-detection" => nil,
29
- "disable-default-apps" => nil,
30
- "disable-dev-shm-usage" => nil,
31
- "disable-ipc-flooding-protection" => nil,
32
- "disable-prompt-on-repost" => nil,
33
- "disable-renderer-backgrounding" => nil,
34
- "force-color-profile" => "srgb",
35
- "metrics-recording-only" => nil,
36
- "safebrowsing-disable-auto-update" => nil,
37
- "password-store" => "basic",
38
- # Note: --no-sandbox is not needed if you properly setup a user in the container.
39
- # https://github.com/ebidel/lighthouse-ci/blob/master/builder/Dockerfile#L35-L40
40
- # "no-sandbox" => nil,
41
- }.freeze
42
-
43
- MAC_BIN_PATH = [
44
- "/Applications/Chromium.app/Contents/MacOS/Chromium",
45
- "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
46
- ].freeze
47
- LINUX_BIN_PATH = %w[chromium google-chrome-unstable google-chrome-beta
48
- google-chrome chrome chromium-browser
49
- google-chrome-stable].freeze
50
-
51
- private
52
-
53
- def combine_flags
54
- # Doesn't work on MacOS, so we need to set it by CDP as well
55
- @flags.merge!("window-size" => options[:window_size].join(","))
56
-
57
- port = options.fetch(:port, BROWSER_PORT)
58
- @flags.merge!("remote-debugging-port" => port)
59
-
60
- host = options.fetch(:host, BROWSER_HOST)
61
- @flags.merge!("remote-debugging-address" => host)
62
-
63
- @flags.merge!("user-data-dir" => @user_data_dir)
64
-
65
- @flags = DEFAULT_OPTIONS.merge(@flags)
66
-
67
- unless options.fetch(:headless, true)
68
- @flags.delete("headless")
69
- @flags.delete("disable-gpu")
70
- end
71
-
72
- @flags.merge!(options.fetch(:browser_options, {}))
73
- end
74
- end
75
- end
76
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ferrum
4
- class Browser
5
- class Firefox < Command
6
- DEFAULT_OPTIONS = {
7
- "headless" => nil,
8
- }.freeze
9
-
10
- MAC_BIN_PATH = [
11
- "/Applications/Firefox.app/Contents/MacOS/firefox-bin"
12
- ].freeze
13
- LINUX_BIN_PATH = %w[firefox].freeze
14
-
15
- private
16
-
17
- def combine_flags
18
- port = options.fetch(:port, BROWSER_PORT)
19
- host = options.fetch(:host, BROWSER_HOST)
20
- @flags.merge!("remote-debugger" => "#{host}:#{port}")
21
-
22
- @flags.merge!("profile" => @user_data_dir)
23
-
24
- @flags = DEFAULT_OPTIONS.merge(@flags)
25
-
26
- unless options.fetch(:headless, true)
27
- @flags.delete("headless")
28
- end
29
-
30
- @flags.merge!(options.fetch(:browser_options, {}))
31
- end
32
- end
33
- end
34
- end