puppeteer-ruby 0.0.17 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2277fda99720c2566927af9a2acfc56da2b8e87ee10521871c368fd4a05649b2
4
- data.tar.gz: 59636e168935b0fb6c964cd62355ae3becf8199ed2ee1af58cb512ccacc9d7cb
3
+ metadata.gz: 63cde4d139f1dc95710efb059310822219b905ef4b44ec8a1347b4bdc97a6b2e
4
+ data.tar.gz: '0989de5d246bb1c2bcb5ab625eb0702f608ec6ec667db9bbcf4282cf419314fa'
5
5
  SHA512:
6
- metadata.gz: b45495a2ae160e740e242bc04bb81bfa493c1101583393f78e8e7ff3d065c00594fe0196b8225ac73e281a17428127597d11c8f8323ba6b58d64b437e2979d97
7
- data.tar.gz: 72c9bd1ca17f37927ceb51a79904583c638066e29cdb08cc2534e77bcc7b3ee348e53e69546ecd579917bd6d8db9c4413d4a63cf617ffa33b8c69c756603439e
6
+ metadata.gz: 96aaf3dc540e160dd983660f2ea4fa10a8c3a2126e9c56f57f9c7a11c31c956376f556473c2d6c591b4cf4253c92e91055cc564e1910fe6dbaf3eb8244d2e852
7
+ data.tar.gz: c2195746ce0ed09fb2be8e66cb842cc2fb9487c51cb2232e51f3970df0234aec97fce173627bbedd1c4d113cd82154c134a69d0f9eb02c23826ab0bc0ad7ee18
@@ -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/RedundantStringCoercion:
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
- Lint/DeprecatedClassMethods:
198
+ Style/ParenthesesAroundCondition:
169
199
  Enabled: true
170
200
 
171
- Style/ParenthesesAroundCondition:
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
 
@@ -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: "return (#{PREDICATE})(...args)",
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 = @remote_object.content_quads(@client)
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
- # * @returns {!Promise<boolean>}
385
- # */
386
- # isIntersectingViewport() {
387
- # return this.evaluate(async element => {
388
- # const visibleRatio = await new Promise(resolve => {
389
- # const observer = new IntersectionObserver(entries => {
390
- # resolve(entries[0].intersectionRatio);
391
- # observer.disconnect();
392
- # });
393
- # observer.observe(element);
394
- # });
395
- # return visibleRatio > 0;
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)
@@ -142,7 +142,7 @@ class Puppeteer::Frame
142
142
  end
143
143
 
144
144
  def child_frames
145
- @child_frames.dup
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 {Function|string} pageFunction
246
- # @param {!{polling?: string|number, timeout?: number}=} options
247
- # @param {!Array<*>} args
248
- # @return {!Promise<!Puppeteer.JSHandle>}
249
- def wait_for_function(page_function, options = {}, *args)
250
- @main_world.wait_for_function(page_function, options, *args)
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
@@ -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
- # * @param {string} propertyName
62
- # * @return {!Promise<?JSHandle>}
63
- # */
64
- # async getProperty(propertyName) {
65
- # const objectHandle = await this.evaluateHandle((object, propertyName) => {
66
- # const result = {__proto__: null};
67
- # result[propertyName] = object[propertyName];
68
- # return result;
69
- # }, propertyName);
70
- # const properties = await objectHandle.getProperties();
71
- # const result = properties.get(propertyName) || null;
72
- # await objectHandle.dispose();
73
- # return result;
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
- # * @override
124
- # * @return {string}
125
- # */
126
- # toString() {
127
- # if (this._remoteObject.objectId) {
128
- # const type = this._remoteObject.subtype || this._remoteObject.type;
129
- # return 'JSHandle@' + type;
130
- # }
131
- # return 'JSHandle:' + helper.valueFromRemoteObject(this._remoteObject);
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
@@ -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 {Function|string} pageFunction
1130
- # @param {!{polling?: string|number, timeout?: number}=} options
1131
- # @param {!Array<*>} args
1132
- # @return {!Promise<!Puppeteer.JSHandle>}
1133
- def wait_for_function(page_function, options = {}, *args)
1134
- main_frame.wait_for_function(page_function, options, *args)
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:
@@ -1,3 +1,3 @@
1
1
  class Puppeteer
2
- VERSION = '0.0.17'
2
+ VERSION = '0.0.18'
3
3
  end
@@ -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)
@@ -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.86.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.17
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-07-28 00:00:00.000000000 Z
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.86.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.86.0
138
+ version: 0.89.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rubocop-rspec
141
141
  requirement: !ruby/object:Gem::Requirement