puppeteer-ruby 0.0.17 → 0.0.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +39 -3
- data/README.md +3 -1
- data/lib/puppeteer/dom_world.rb +21 -1
- data/lib/puppeteer/element_handle.rb +27 -16
- data/lib/puppeteer/frame.rb +13 -7
- data/lib/puppeteer/js_handle.rb +37 -27
- data/lib/puppeteer/page.rb +12 -6
- data/lib/puppeteer/remote_object.rb +16 -0
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer/wait_task.rb +1 -1
- data/puppeteer-ruby.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63cde4d139f1dc95710efb059310822219b905ef4b44ec8a1347b4bdc97a6b2e
|
4
|
+
data.tar.gz: '0989de5d246bb1c2bcb5ab625eb0702f608ec6ec667db9bbcf4282cf419314fa'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96aaf3dc540e160dd983660f2ea4fa10a8c3a2126e9c56f57f9c7a11c31c956376f556473c2d6c591b4cf4253c92e91055cc564e1910fe6dbaf3eb8244d2e852
|
7
|
+
data.tar.gz: c2195746ce0ed09fb2be8e66cb842cc2fb9487c51cb2232e51f3970df0234aec97fce173627bbedd1c4d113cd82154c134a69d0f9eb02c23826ab0bc0ad7ee18
|
data/.rubocop.yml
CHANGED
@@ -146,17 +146,47 @@ Lint/AmbiguousOperator:
|
|
146
146
|
Lint/AmbiguousRegexpLiteral:
|
147
147
|
Enabled: true
|
148
148
|
|
149
|
+
Lint/BinaryOperatorWithIdenticalOperands:
|
150
|
+
Enabled: true
|
151
|
+
|
152
|
+
Lint/DeprecatedClassMethods:
|
153
|
+
Enabled: true
|
154
|
+
|
155
|
+
Lint/DuplicateRescueException:
|
156
|
+
Enabled: true
|
157
|
+
|
149
158
|
Lint/ErbNewArguments:
|
150
159
|
Enabled: true
|
151
160
|
|
161
|
+
Lint/EmptyConditionalBody:
|
162
|
+
Enabled: true
|
163
|
+
|
164
|
+
Lint/FloatComparison:
|
165
|
+
Enabled: true
|
166
|
+
|
167
|
+
Lint/MissingSuper:
|
168
|
+
Enabled: true
|
169
|
+
|
170
|
+
Lint/OutOfRangeRegexpRef:
|
171
|
+
Enabled: true
|
172
|
+
|
173
|
+
Lint/RedundantStringCoercion:
|
174
|
+
Enabled: true
|
175
|
+
|
152
176
|
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
|
153
177
|
Lint/RequireParentheses:
|
154
178
|
Enabled: true
|
155
179
|
|
180
|
+
Lint/SelfAssignment:
|
181
|
+
Enabled: true
|
182
|
+
|
156
183
|
Lint/ShadowingOuterLocalVariable:
|
157
184
|
Enabled: true
|
158
185
|
|
159
|
-
Lint/
|
186
|
+
Lint/TopLevelReturnWithArgument:
|
187
|
+
Enabled: true
|
188
|
+
|
189
|
+
Lint/UnreachableLoop:
|
160
190
|
Enabled: true
|
161
191
|
|
162
192
|
Lint/UriEscapeUnescape:
|
@@ -165,15 +195,18 @@ Lint/UriEscapeUnescape:
|
|
165
195
|
Lint/UselessAssignment:
|
166
196
|
Enabled: true
|
167
197
|
|
168
|
-
|
198
|
+
Style/ParenthesesAroundCondition:
|
169
199
|
Enabled: true
|
170
200
|
|
171
|
-
Style/
|
201
|
+
Style/ExplicitBlockArgument:
|
172
202
|
Enabled: true
|
173
203
|
|
174
204
|
Style/FrozenStringLiteralComment:
|
175
205
|
Enabled: false
|
176
206
|
|
207
|
+
Style/GlobalStdStream:
|
208
|
+
Enabled: true
|
209
|
+
|
177
210
|
Style/HashEachMethods:
|
178
211
|
Enabled: true
|
179
212
|
|
@@ -198,6 +231,9 @@ Style/Semicolon:
|
|
198
231
|
Enabled: true
|
199
232
|
AllowAsExpressionSeparator: true
|
200
233
|
|
234
|
+
Style/StringConcatenation:
|
235
|
+
Enabled: true
|
236
|
+
|
201
237
|
# Prefer Foo.method over Foo::method
|
202
238
|
Style/ColonMethodCall:
|
203
239
|
Enabled: true
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/puppeteer-ruby.svg)](https://badge.fury.io/rb/puppeteer-ruby)
|
2
|
+
|
1
3
|
# Puppeteer in Ruby [UNDER HEAVY DEVELOPMENT]
|
2
4
|
|
3
5
|
A Ruby port of [puppeteer](https://pptr.dev/).
|
@@ -47,7 +49,7 @@ end
|
|
47
49
|
|
48
50
|
More usage examples can be found [here](https://github.com/YusukeIwaki/puppeteer-ruby-example)
|
49
51
|
|
50
|
-
## Collaboration with Selenium or Capybara
|
52
|
+
## :bulb: Collaboration with Selenium or Capybara
|
51
53
|
|
52
54
|
It is really remarkable that we can use puppeteer functions in existing Selenium or Capybara codes, with a few configuration in advance.
|
53
55
|
|
data/lib/puppeteer/dom_world.rb
CHANGED
@@ -402,6 +402,26 @@ class Puppeteer::DOMWorld
|
|
402
402
|
# return new WaitTask(this, pageFunction, 'function', polling, timeout, ...args).promise;
|
403
403
|
# }
|
404
404
|
|
405
|
+
# @param page_function [String]
|
406
|
+
# @param args [Array]
|
407
|
+
# @param polling [Integer|String]
|
408
|
+
# @param timeout [Integer]
|
409
|
+
# @return [Puppeteer::JSHandle]
|
410
|
+
def wait_for_function(page_function, args: [], polling: nil, timeout: nil)
|
411
|
+
option_polling = polling || 'raf'
|
412
|
+
option_timeout = timeout || @timeout_settings.timeout
|
413
|
+
|
414
|
+
Puppeteer::WaitTask.new(
|
415
|
+
dom_world: self,
|
416
|
+
predicate_body: page_function,
|
417
|
+
title: 'function',
|
418
|
+
polling: option_polling,
|
419
|
+
timeout: option_timeout,
|
420
|
+
args: args,
|
421
|
+
).await_promise
|
422
|
+
end
|
423
|
+
|
424
|
+
|
405
425
|
# @return [String]
|
406
426
|
def title
|
407
427
|
evaluate('() => document.title')
|
@@ -427,7 +447,7 @@ class Puppeteer::DOMWorld
|
|
427
447
|
|
428
448
|
wait_task = Puppeteer::WaitTask.new(
|
429
449
|
dom_world: self,
|
430
|
-
predicate_body:
|
450
|
+
predicate_body: PREDICATE,
|
431
451
|
title: title,
|
432
452
|
polling: polling,
|
433
453
|
timeout: option_timeout,
|
@@ -3,6 +3,7 @@ require_relative './element_handle/box_model'
|
|
3
3
|
require_relative './element_handle/point'
|
4
4
|
|
5
5
|
class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
6
|
+
include Puppeteer::DebugPrint
|
6
7
|
include Puppeteer::IfPresent
|
7
8
|
using Puppeteer::DefineAsyncMethod
|
8
9
|
|
@@ -62,7 +63,14 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def clickable_point
|
65
|
-
result =
|
66
|
+
result =
|
67
|
+
begin
|
68
|
+
@remote_object.content_quads(@client)
|
69
|
+
rescue => err
|
70
|
+
debug_puts(err)
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
66
74
|
if !result || result["quads"].empty?
|
67
75
|
raise ElementNotVisibleError.new
|
68
76
|
end
|
@@ -380,21 +388,24 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
380
388
|
|
381
389
|
define_async_method :async_Sx
|
382
390
|
|
383
|
-
#
|
384
|
-
#
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
391
|
+
# in JS, #isIntersectingViewport.
|
392
|
+
# @return [Boolean]
|
393
|
+
def intersecting_viewport?
|
394
|
+
js = <<~JAVASCRIPT
|
395
|
+
async element => {
|
396
|
+
const visibleRatio = await new Promise(resolve => {
|
397
|
+
const observer = new IntersectionObserver(entries => {
|
398
|
+
resolve(entries[0].intersectionRatio);
|
399
|
+
observer.disconnect();
|
400
|
+
});
|
401
|
+
observer.observe(element);
|
402
|
+
});
|
403
|
+
return visibleRatio > 0;
|
404
|
+
}
|
405
|
+
JAVASCRIPT
|
406
|
+
|
407
|
+
evaluate(js)
|
408
|
+
end
|
398
409
|
|
399
410
|
# @param quad [Array<Point>]
|
400
411
|
private def compute_quad_area(quad)
|
data/lib/puppeteer/frame.rb
CHANGED
@@ -142,7 +142,7 @@ class Puppeteer::Frame
|
|
142
142
|
end
|
143
143
|
|
144
144
|
def child_frames
|
145
|
-
@child_frames.
|
145
|
+
@child_frames.to_a
|
146
146
|
end
|
147
147
|
|
148
148
|
def detached?
|
@@ -225,6 +225,11 @@ class Puppeteer::Frame
|
|
225
225
|
|
226
226
|
define_async_method :async_wait_for_selector
|
227
227
|
|
228
|
+
# @param milliseconds [Integer] the number of milliseconds to wait.
|
229
|
+
def wait_for_timeout(milliseconds)
|
230
|
+
sleep(milliseconds / 1000.0)
|
231
|
+
end
|
232
|
+
|
228
233
|
# @param xpath [String]
|
229
234
|
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
230
235
|
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
@@ -242,12 +247,13 @@ class Puppeteer::Frame
|
|
242
247
|
|
243
248
|
define_async_method :async_wait_for_xpath
|
244
249
|
|
245
|
-
# @param
|
246
|
-
# @param
|
247
|
-
# @param
|
248
|
-
# @
|
249
|
-
|
250
|
-
|
250
|
+
# @param page_function [String]
|
251
|
+
# @param args [Integer|Array]
|
252
|
+
# @param polling [String]
|
253
|
+
# @param timeout [Integer]
|
254
|
+
# @return [Puppeteer::JSHandle]
|
255
|
+
def wait_for_function(page_function, args: [], polling: nil, timeout: nil)
|
256
|
+
@main_world.wait_for_function(page_function, args: args, polling: polling, timeout: timeout)
|
251
257
|
end
|
252
258
|
|
253
259
|
define_async_method :async_wait_for_function
|
data/lib/puppeteer/js_handle.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
class Puppeteer::JSHandle
|
2
2
|
using Puppeteer::DefineAsyncMethod
|
3
|
+
include Puppeteer::IfPresent
|
3
4
|
|
4
5
|
# @param context [Puppeteer::ExecutionContext]
|
5
6
|
# @param remote_object [Puppeteer::RemoteObject]
|
@@ -57,21 +58,29 @@ class Puppeteer::JSHandle
|
|
57
58
|
|
58
59
|
define_async_method :async_evaluate_handle
|
59
60
|
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
61
|
+
# getProperty(propertyName) in JavaScript
|
62
|
+
# @param name [String]
|
63
|
+
# @return [Puppeteer::JSHandle]
|
64
|
+
def property(name)
|
65
|
+
js = <<~JAVASCRIPT
|
66
|
+
(object, propertyName) => {
|
67
|
+
const result = {__proto__: null};
|
68
|
+
result[propertyName] = object[propertyName];
|
69
|
+
return result;
|
70
|
+
}
|
71
|
+
JAVASCRIPT
|
72
|
+
object_handle = evaluate_handle(js, name)
|
73
|
+
properties = object_handle.properties
|
74
|
+
result = properties[name]
|
75
|
+
object_handle.dispose
|
76
|
+
result
|
77
|
+
end
|
78
|
+
|
79
|
+
# @param name [String]
|
80
|
+
# @return [Puppeteer::JSHandle]
|
81
|
+
def [](name)
|
82
|
+
property(name)
|
83
|
+
end
|
75
84
|
|
76
85
|
# getProperties in JavaScript.
|
77
86
|
# @return [Hash<String, JSHandle>]
|
@@ -101,7 +110,7 @@ class Puppeteer::JSHandle
|
|
101
110
|
#
|
102
111
|
# However it would be better that RemoteObject is responsible for
|
103
112
|
# the logic `if (this._remoteObject.objectId) { ... }`.
|
104
|
-
@remote_object.evaluate_self(@client) || @remote_object.value
|
113
|
+
@remote_object.evaluate_self(@client)&.value || @remote_object.value
|
105
114
|
end
|
106
115
|
|
107
116
|
def as_element
|
@@ -119,15 +128,16 @@ class Puppeteer::JSHandle
|
|
119
128
|
@disposed
|
120
129
|
end
|
121
130
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
131
|
+
def to_s
|
132
|
+
# original logic was:
|
133
|
+
# if (this._remoteObject.objectId) {
|
134
|
+
# const type = this._remoteObject.subtype || this._remoteObject.type;
|
135
|
+
# return 'JSHandle@' + type;
|
136
|
+
# }
|
137
|
+
# return 'JSHandle:' + helper.valueFromRemoteObject(this._remoteObject);
|
138
|
+
#
|
139
|
+
# However it would be better that RemoteObject is responsible for
|
140
|
+
# the logic `if (this._remoteObject.objectId) { ... }`.
|
141
|
+
if_present(@remote_object.type_str) { |type_str| "JSHandle@#{type_str}" } || "JSHandle:#{@remote_object.value || 'undefined'}"
|
142
|
+
end
|
133
143
|
end
|
data/lib/puppeteer/page.rb
CHANGED
@@ -1116,6 +1116,11 @@ class Puppeteer::Page
|
|
1116
1116
|
|
1117
1117
|
define_async_method :async_wait_for_selector
|
1118
1118
|
|
1119
|
+
# @param milliseconds [Integer] the number of milliseconds to wait.
|
1120
|
+
def wait_for_timeout(milliseconds)
|
1121
|
+
main_frame.wait_for_timeout(milliseconds)
|
1122
|
+
end
|
1123
|
+
|
1119
1124
|
# @param xpath [String]
|
1120
1125
|
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
1121
1126
|
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
@@ -1126,12 +1131,13 @@ class Puppeteer::Page
|
|
1126
1131
|
|
1127
1132
|
define_async_method :async_wait_for_xpath
|
1128
1133
|
|
1129
|
-
# @param
|
1130
|
-
# @param
|
1131
|
-
# @param
|
1132
|
-
# @
|
1133
|
-
|
1134
|
-
|
1134
|
+
# @param page_function [String]
|
1135
|
+
# @param args [Integer|Array]
|
1136
|
+
# @param polling [String]
|
1137
|
+
# @param timeout [Integer]
|
1138
|
+
# @return [Puppeteer::JSHandle]
|
1139
|
+
def wait_for_function(page_function, args: [], polling: nil, timeout: nil)
|
1140
|
+
main_frame.wait_for_function(page_function, args: args, polling: polling, timeout: timeout)
|
1135
1141
|
end
|
1136
1142
|
|
1137
1143
|
define_async_method :async_wait_for_function
|
@@ -6,6 +6,7 @@ class Puppeteer::RemoteObject
|
|
6
6
|
# @param payload [Hash]
|
7
7
|
def initialize(payload)
|
8
8
|
@object_id = payload['objectId']
|
9
|
+
@type = payload['type']
|
9
10
|
@sub_type = payload['subtype']
|
10
11
|
@unserializable_value = payload['unserializableValue']
|
11
12
|
@value = payload['value']
|
@@ -42,6 +43,21 @@ class Puppeteer::RemoteObject
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
46
|
+
# @return [String]
|
47
|
+
def type_str
|
48
|
+
# used in JSHandle#to_s
|
49
|
+
# original logic:
|
50
|
+
# if (this._remoteObject.objectId) {
|
51
|
+
# const type = this._remoteObject.subtype || this._remoteObject.type;
|
52
|
+
# return 'JSHandle@' + type;
|
53
|
+
# }
|
54
|
+
if @object_id
|
55
|
+
@sub_type || @type
|
56
|
+
else
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
45
61
|
# used in JSHandle#properties
|
46
62
|
def properties(client)
|
47
63
|
# original logic:
|
data/lib/puppeteer/version.rb
CHANGED
data/lib/puppeteer/wait_task.rb
CHANGED
@@ -25,7 +25,7 @@ class Puppeteer::WaitTask
|
|
25
25
|
@dom_world = dom_world
|
26
26
|
@polling = polling
|
27
27
|
@timeout = timeout
|
28
|
-
@predicate_body = predicate_body
|
28
|
+
@predicate_body = "return (#{predicate_body})(...args);"
|
29
29
|
@args = args
|
30
30
|
@run_count = 0
|
31
31
|
@dom_world._wait_tasks.add(self)
|
data/puppeteer-ruby.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency 'rake', '~> 10.0'
|
27
27
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
28
|
spec.add_development_dependency 'rspec_junit_formatter' # for CircleCI.
|
29
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
29
|
+
spec.add_development_dependency 'rubocop', '~> 0.89.0'
|
30
30
|
spec.add_development_dependency 'rubocop-rspec'
|
31
31
|
spec.add_development_dependency 'sinatra'
|
32
32
|
spec.add_development_dependency 'yard'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppeteer-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- YusukeIwaki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.
|
131
|
+
version: 0.89.0
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.
|
138
|
+
version: 0.89.0
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: rubocop-rspec
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|