ferrum 0.10.2 → 0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2256dbc8ed2c2fca2e3209c13e29009c69b4c2ccf328e8a73ade73ed69c89f0
4
- data.tar.gz: 8d5604f8d4f8120b699ec3e341c37f77f25e90a794d3206660ecc0465b22e7b1
3
+ metadata.gz: c953c12b582e6d81031c8daa598f25d4f8b2dba8e6d736f227b2e8c461a83d41
4
+ data.tar.gz: 229fe35bc81a133eff2628e1b3e0e0d31d733da2b277e0dbe70c9699e80e2a15
5
5
  SHA512:
6
- metadata.gz: 7aa18fd5a01f387c27ade8ecdf6aa30df8118f4e90badddc242ed979e5be49c890036049f284555a937ccc79699bcbc954d62c077f45ff0770d9eeeec255a6ea
7
- data.tar.gz: 25c4cc92e59a297a344cf85301a21c3f9e634f25ea685eb6c9d2f4ea1896fcba2898dc5f4cfcc8f3af358001a0e451034bb79bf24981e16a17a51cdd3f07d6a3
6
+ metadata.gz: 1f48e9fac5bfbcf9959d855b1b7c7259f97d845e812f3fce6fa59dc6a3e6b5147cced16167c2a3603e964978a9d3b1e4e5b4f2c7b5b686454acaa47d1aadf6d3
7
+ data.tar.gz: aa9f267ea80365e636e8b047bc87e6d5fe6761814cbd1b59b3d14bc3350ccdd9e2199718ba57c774abdf5bc089ef000cdbd55d03d7dbd6158cee4c975ee9d9e0
data/README.md CHANGED
@@ -49,6 +49,8 @@ Web design by [Evrone](https://evrone.com/), what else
49
49
  * [Frames](https://github.com/rubycdp/ferrum#frames)
50
50
  * [Frame](https://github.com/rubycdp/ferrum#frame)
51
51
  * [Dialog](https://github.com/rubycdp/ferrum#dialog)
52
+ * [Animation](https://github.com/rubycdp/ferrum#animation)
53
+ * [Node](https://github.com/rubycdp/ferrum#node)
52
54
  * [Thread safety](https://github.com/rubycdp/ferrum#thread-safety)
53
55
  * [Development](https://github.com/rubycdp/ferrum#development)
54
56
  * [Contributing](https://github.com/rubycdp/ferrum#contributing)
@@ -234,6 +236,25 @@ browser.go_to("https://github.com/")
234
236
  browser.stop
235
237
  ```
236
238
 
239
+ #### position = \*\*options
240
+
241
+ Set the position for the browser window
242
+
243
+ * options `Hash`
244
+ * :left `Integer`
245
+ * :top `Integer`
246
+
247
+ ```ruby
248
+ browser.position = { left: 10, top: 20 }
249
+ ```
250
+
251
+ #### position : `Array<Integer>`
252
+
253
+ Get the position for the browser window
254
+
255
+ ```ruby
256
+ browser.position # => [10, 20]
257
+ ```
237
258
 
238
259
  ## Finders
239
260
 
@@ -740,6 +761,20 @@ simple value.
740
761
  browser.execute(%(1 + 1)) # => true
741
762
  ```
742
763
 
764
+ #### evaluate_on_new_document(expression)
765
+
766
+ Evaluate JavaScript to modify things before a page load
767
+
768
+ * expression `String` should be valid JavaScript
769
+
770
+ ```ruby
771
+ browser.evaluate_on_new_document <<~JS
772
+ Object.defineProperty(navigator, "languages", {
773
+ get: function() { return ["tlh"]; }
774
+ });
775
+ JS
776
+ ```
777
+
743
778
  #### add_script_tag(\*\*options) : `Boolean`
744
779
 
745
780
  * options `Hash`
@@ -946,6 +981,55 @@ browser.go_to("https://google.com")
946
981
  ```
947
982
 
948
983
 
984
+ ## Animation
985
+
986
+ You can slow down or speed up CSS animations.
987
+
988
+ #### playback_rate : `Integer`
989
+
990
+ Returns playback rate for CSS animations, defaults to `1`.
991
+
992
+
993
+ #### playback_rate = value
994
+
995
+ Sets playback rate of CSS animations
996
+
997
+ * value `Integer`
998
+
999
+ ```ruby
1000
+ browser = Ferrum::Browser.new
1001
+ browser.playback_rate = 2000
1002
+ browser.go_to("https://google.com")
1003
+ browser.playback_rate # => 2000
1004
+ ```
1005
+
1006
+
1007
+ ## Node
1008
+
1009
+ #### node? : `Boolean`
1010
+ #### frame_id
1011
+ #### frame
1012
+ #### focus
1013
+ #### focusable?
1014
+ #### moving? : `Boolean`
1015
+ #### wait_for_stop_moving
1016
+ #### blur
1017
+ #### type
1018
+ #### click
1019
+ #### hover
1020
+ #### select_file
1021
+ #### at_xpath
1022
+ #### at_css
1023
+ #### xpath
1024
+ #### css
1025
+ #### text
1026
+ #### inner_text
1027
+ #### value
1028
+ #### property
1029
+ #### attribute
1030
+ #### evaluate
1031
+
1032
+
949
1033
  ## Thread safety ##
950
1034
 
951
1035
  Ferrum is fully thread-safe. You can create one browser or a few as you wish and
data/lib/ferrum.rb CHANGED
@@ -57,7 +57,7 @@ module Ferrum
57
57
  end
58
58
  end
59
59
 
60
- class NodeIsMovingError < Error
60
+ class NodeMovingError < Error
61
61
  def initialize(node, prev, current)
62
62
  @node, @prev, @current = node, prev, current
63
63
  super(message)
@@ -70,6 +70,12 @@ module Ferrum
70
70
  end
71
71
  end
72
72
 
73
+ class CoordinatesNotFoundError < Error
74
+ def initialize(message = "Could not compute content quads")
75
+ super
76
+ end
77
+ end
78
+
73
79
  class BrowserError < Error
74
80
  attr_reader :response
75
81
 
@@ -26,7 +26,8 @@ module Ferrum
26
26
  frames frame_by main_frame
27
27
  evaluate evaluate_on evaluate_async execute evaluate_func
28
28
  add_script_tag add_style_tag bypass_csp
29
- on goto] => :page
29
+ on goto position position=
30
+ playback_rate playback_rate=] => :page
30
31
  delegate %i[default_user_agent] => :process
31
32
 
32
33
  attr_reader :client, :process, :contexts, :logger, :js_errors, :pending_connection_errors,
@@ -77,6 +78,10 @@ module Ferrum
77
78
  end
78
79
  end
79
80
 
81
+ def evaluate_on_new_document(expression)
82
+ extensions << expression
83
+ end
84
+
80
85
  def timeout
81
86
  @timeout || DEFAULT_TIMEOUT
82
87
  end
@@ -90,6 +90,8 @@ module Ferrum
90
90
  raise NoExecutionContextError.new(error)
91
91
  when "No target with given id found"
92
92
  raise NoSuchPageError
93
+ when /Could not compute content quads/
94
+ raise CoordinatesNotFoundError
93
95
  else
94
96
  raise BrowserError.new(error)
95
97
  end
@@ -36,6 +36,7 @@ module Ferrum
36
36
  "metrics-recording-only" => nil,
37
37
  "safebrowsing-disable-auto-update" => nil,
38
38
  "password-store" => "basic",
39
+ "no-startup-window" => nil,
39
40
  # Note: --no-sandbox is not needed if you properly setup a user in the container.
40
41
  # https://github.com/ebidel/lighthouse-ci/blob/master/builder/Dockerfile#L35-L40
41
42
  # "no-sandbox" => nil,
@@ -10,7 +10,7 @@ module Ferrum
10
10
 
11
11
  def initialize(browser, contexts, id)
12
12
  @browser, @contexts, @id = browser, contexts, id
13
- @targets = Concurrent::Hash.new
13
+ @targets = Concurrent::Map.new
14
14
  @pendings = Concurrent::MVar.new
15
15
  end
16
16
 
@@ -47,14 +47,14 @@ module Ferrum
47
47
  url: "about:blank")
48
48
  target = @pendings.take(@browser.timeout)
49
49
  raise NoSuchTargetError unless target.is_a?(Target)
50
- @targets[target.id] = target
50
+ @targets.put_if_absent(target.id, target)
51
51
  target
52
52
  end
53
53
 
54
54
  def add_target(params)
55
55
  target = Target.new(@browser, params)
56
56
  if target.window?
57
- @targets[target.id] = target
57
+ @targets.put_if_absent(target.id, target)
58
58
  else
59
59
  @pendings.put(target, @browser.timeout)
60
60
  end
@@ -72,6 +72,10 @@ module Ferrum
72
72
  @contexts.dispose(@id)
73
73
  end
74
74
 
75
+ def has_target?(target_id)
76
+ !!@targets[target_id]
77
+ end
78
+
75
79
  def inspect
76
80
  %(#<#{self.class} @id=#{@id.inspect} @targets=#{@targets.inspect} @default_target=#{@default_target.inspect}>)
77
81
  end
@@ -7,7 +7,7 @@ module Ferrum
7
7
  attr_reader :contexts
8
8
 
9
9
  def initialize(browser)
10
- @contexts = Concurrent::Hash.new
10
+ @contexts = Concurrent::Map.new
11
11
  @browser = browser
12
12
  subscribe
13
13
  discover
@@ -18,7 +18,9 @@ module Ferrum
18
18
  end
19
19
 
20
20
  def find_by(target_id:)
21
- @contexts.find { |_, c| c.targets.keys.include?(target_id) }&.last
21
+ context = nil
22
+ @contexts.each_value { |c| context = c if c.has_target?(target_id) }
23
+ context
22
24
  end
23
25
 
24
26
  def create
data/lib/ferrum/node.rb CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Ferrum
4
4
  class Node
5
- MOVING_WAIT = ENV.fetch("FERRUM_NODE_MOVING_WAIT", 0.01).to_f
6
- MOVING_ATTEMPTS = ENV.fetch("FERRUM_NODE_MOVING_ATTEMPTS", 50).to_i
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
7
 
8
8
  attr_reader :page, :target_id, :node_id, :description, :tag_name
9
9
 
@@ -30,6 +30,26 @@ module Ferrum
30
30
  tap { page.command("DOM.focus", slowmoable: true, nodeId: node_id) }
31
31
  end
32
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
+
33
53
  def blur
34
54
  tap { evaluate("this.blur()") }
35
55
  end
@@ -124,44 +144,36 @@ module Ferrum
124
144
  end
125
145
 
126
146
  def find_position(x: nil, y: nil, position: :top)
127
- prev = get_content_quads
128
-
129
- # FIXME: Case when a few quads returned
130
- points = Ferrum.with_attempts(errors: NodeIsMovingError, max: MOVING_ATTEMPTS, wait: 0) do
131
- sleep(MOVING_WAIT)
132
- current = get_content_quads
133
-
134
- if current != prev
135
- error = NodeIsMovingError.new(self, prev, current)
136
- prev = current
137
- raise(error)
138
- end
139
-
140
- current
141
- end.map { |q| to_points(q) }.first
142
-
147
+ points = wait_for_stop_moving.map { |q| to_points(q) }.first
143
148
  get_position(points, x, y, position)
144
- rescue Ferrum::BrowserError => e
145
- return raise unless e.message&.include?("Could not compute content quads")
146
-
147
- find_position_via_js
149
+ rescue CoordinatesNotFoundError
150
+ x, y = get_bounding_rect_coordinates
151
+ raise if x == 0 && y == 0
152
+ [x, y]
148
153
  end
149
154
 
150
155
  private
151
156
 
152
- def find_position_via_js
153
- [
154
- evaluate("this.getBoundingClientRect().left + window.pageXOffset + (this.offsetWidth / 2)"), # x
155
- evaluate("this.getBoundingClientRect().top + window.pageYOffset + (this.offsetHeight / 2)") # y
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
157
162
  end
158
163
 
159
164
  def get_content_quads
160
165
  quads = page.command("DOM.getContentQuads", nodeId: node_id)["quads"]
161
- raise "Node is either not visible or not an HTMLElement" if quads.size == 0
166
+ raise CoordinatesNotFoundError, "Node is either not visible or not an HTMLElement" if quads.size == 0
162
167
  quads
163
168
  end
164
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
+
165
177
  def get_position(points, offset_x, offset_y, position)
166
178
  x = y = nil
167
179
 
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
@@ -35,7 +36,7 @@ module Ferrum
35
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,
@@ -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
@@ -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
@@ -12,7 +12,7 @@ module Ferrum
12
12
  scale: 1.0
13
13
  }.freeze
14
14
 
15
- PAPEP_FORMATS = {
15
+ PAPER_FORMATS = {
16
16
  letter: { width: 8.50, height: 11.00 },
17
17
  legal: { width: 8.50, height: 14.00 },
18
18
  tabloid: { width: 11.00, height: 17.00 },
@@ -114,7 +114,7 @@ module Ferrum
114
114
  raise ArgumentError, "Specify :format or :paper_width, :paper_height"
115
115
  end
116
116
 
117
- dimension = PAPEP_FORMATS.fetch(format)
117
+ dimension = PAPER_FORMATS.fetch(format)
118
118
  options.merge!(paper_width: dimension[:width],
119
119
  paper_height: dimension[:height])
120
120
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ferrum
4
- VERSION = "0.10.2"
4
+ VERSION = "0.11"
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.10.2
4
+ version: '0.11'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Vorotilin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-24 00:00:00.000000000 Z
11
+ date: 2021-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: websocket-driver
@@ -210,6 +210,7 @@ files:
210
210
  - lib/ferrum/network/response.rb
211
211
  - lib/ferrum/node.rb
212
212
  - lib/ferrum/page.rb
213
+ - lib/ferrum/page/animation.rb
213
214
  - lib/ferrum/page/frames.rb
214
215
  - lib/ferrum/page/screenshot.rb
215
216
  - lib/ferrum/rbga.rb
@@ -218,7 +219,12 @@ files:
218
219
  homepage: https://github.com/route/ferrum
219
220
  licenses:
220
221
  - MIT
221
- metadata: {}
222
+ metadata:
223
+ homepage_uri: https://ferrum.rubycdp.com/
224
+ bug_tracker_uri: https://github.com/rubycdp/ferrum/issues
225
+ documentation_uri: https://github.com/rubycdp/ferrum/blob/master/README.md
226
+ changelog_uri: https://github.com/rubycdp/ferrum/blob/master/CHANGELOG.md
227
+ source_code_uri: https://github.com/rubycdp/ferrum
222
228
  post_install_message:
223
229
  rdoc_options: []
224
230
  require_paths: