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 +4 -4
- data/README.md +84 -0
- data/lib/ferrum.rb +7 -1
- data/lib/ferrum/browser.rb +6 -1
- data/lib/ferrum/browser/client.rb +2 -0
- data/lib/ferrum/browser/options/chrome.rb +1 -0
- data/lib/ferrum/context.rb +7 -3
- data/lib/ferrum/contexts.rb +4 -2
- data/lib/ferrum/node.rb +40 -28
- data/lib/ferrum/page.rb +10 -1
- data/lib/ferrum/page/animation.rb +16 -0
- data/lib/ferrum/page/screenshot.rb +2 -2
- data/lib/ferrum/version.rb +1 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c953c12b582e6d81031c8daa598f25d4f8b2dba8e6d736f227b2e8c461a83d41
|
4
|
+
data.tar.gz: 229fe35bc81a133eff2628e1b3e0e0d31d733da2b277e0dbe70c9699e80e2a15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
|
data/lib/ferrum/browser.rb
CHANGED
@@ -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
|
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
|
@@ -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,
|
data/lib/ferrum/context.rb
CHANGED
@@ -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::
|
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
|
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
|
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
|
data/lib/ferrum/contexts.rb
CHANGED
@@ -7,7 +7,7 @@ module Ferrum
|
|
7
7
|
attr_reader :contexts
|
8
8
|
|
9
9
|
def initialize(browser)
|
10
|
-
@contexts = Concurrent::
|
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
|
-
|
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
|
-
|
6
|
-
|
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
|
-
|
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
|
145
|
-
|
146
|
-
|
147
|
-
|
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
|
153
|
-
|
154
|
-
|
155
|
-
|
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
|
-
|
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 =
|
117
|
+
dimension = PAPER_FORMATS.fetch(format)
|
118
118
|
options.merge!(paper_width: dimension[:width],
|
119
119
|
paper_height: dimension[:height])
|
120
120
|
end
|
data/lib/ferrum/version.rb
CHANGED
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.
|
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-
|
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:
|