puppeteer-ruby 0.43.1 → 0.44.0

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: e723d5efd8074f8c70f1b94de1399f35ec39eca88fd86d1991b036db32d783a8
4
- data.tar.gz: 463781ad3737b5db0f09b2ba9ec2ed8f62863991c011291437230c512671e0ba
3
+ metadata.gz: 6ade25ba8f8e99240ed29fdad9300af7b65cc12ddf09e45c43f7b672c6324ed4
4
+ data.tar.gz: 97d3bfc48b3a2e3729dd8857c2bb6deca7babd4d0b055195f2dbe7c01c941e97
5
5
  SHA512:
6
- metadata.gz: 46462c2894970d02792d5021088252fce262f41f81531449a73d9d40745ede1742fe187cde65cae64222ba817366500d347ca310aa658147040e4fbfa5d1b5db
7
- data.tar.gz: d5b6e7ae1e0efc6c1e69e7bb136f90dfdc1c2370c29ec4bf9a6877c22bbe38cd6a81f698f086dce3157800bdfc7bfcb06f7eb35b518434870fd95456dc1fbe3c
6
+ metadata.gz: 891d8c29ac63d25cdb34178024d7a9202675d77b121a903e24a51e9465e46a9b7a0a9b70a2d893d9b274724b5547d5bb90e133aa2c217052f3f523f952e1a0a3
7
+ data.tar.gz: eea1fb6ff2f179208932a3bb84ca96841b1b08ff588d914e88ace6ad9e31f71c567c21321e3376b019a265122e51a4352b3f0039dd6bea770dba2a383efe82e5
data/CHANGELOG.md CHANGED
@@ -1,7 +1,13 @@
1
- ### main [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.43.1...main)]
1
+ ### main [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.44.0...main)]
2
2
 
3
3
  - xxx
4
4
 
5
+ ### 0.44.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.43.1...0.44.0)]
6
+
7
+ - Port Puppeteer v17.0-v17.1 features.
8
+ - `wait_for_selector` no longer accept `root` parameter.
9
+
10
+
5
11
  ### 0.43.1 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.43.0...0.43.1)]
6
12
 
7
13
  - Port Puppeteer v16.1 features, including bugfix and XPath query handler.
data/docs/api_coverage.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # API coverages
2
- - Puppeteer version: v16.2.0
3
- - puppeteer-ruby version: 0.43.1
2
+ - Puppeteer version: v17.1.3
3
+ - puppeteer-ruby version: 0.44.0
4
4
 
5
5
  ## Puppeteer
6
6
 
@@ -150,13 +150,6 @@
150
150
  * ~~removeAllListeners~~
151
151
  * ~~removeListener~~
152
152
 
153
- ## ExecutionContext
154
-
155
- * evaluate
156
- * evaluateHandle => `#evaluate_handle`
157
- * frame
158
- * ~~queryObjects~~
159
-
160
153
  ## FileChooser
161
154
 
162
155
  * accept
@@ -172,12 +165,12 @@
172
165
  * $x => `#Sx`
173
166
  * addScriptTag => `#add_script_tag`
174
167
  * addStyleTag => `#add_style_tag`
168
+ * addStyleTag => `#add_style_tag`
175
169
  * childFrames => `#child_frames`
176
170
  * click
177
171
  * content
178
172
  * evaluate
179
173
  * evaluateHandle => `#evaluate_handle`
180
- * executionContext => `#execution_context`
181
174
  * focus
182
175
  * goto
183
176
  * hover
@@ -251,7 +244,6 @@
251
244
  * dispose
252
245
  * evaluate
253
246
  * evaluateHandle => `#evaluate_handle`
254
- * executionContext => `#execution_context`
255
247
  * getProperties => `#properties`
256
248
  * getProperty => `#[]`
257
249
  * getProperty => `#[]`
@@ -289,6 +281,7 @@
289
281
  * $x => `#Sx`
290
282
  * addScriptTag => `#add_script_tag`
291
283
  * addStyleTag => `#add_style_tag`
284
+ * addStyleTag => `#add_style_tag`
292
285
  * authenticate
293
286
  * bringToFront => `#bring_to_front`
294
287
  * browser
@@ -313,6 +306,7 @@
313
306
  * exposeFunction => `#expose_function`
314
307
  * focus
315
308
  * frames
309
+ * ~~getDefaultTimeout~~
316
310
  * goBack => `#go_back`
317
311
  * goForward => `#go_forward`
318
312
  * goto
@@ -401,5 +395,4 @@
401
395
 
402
396
  * ~~evaluate~~
403
397
  * ~~evaluateHandle~~
404
- * ~~executionContext~~
405
398
  * ~~url~~
@@ -25,43 +25,83 @@ class Puppeteer::AriaQueryHandler
25
25
  query_options
26
26
  end
27
27
 
28
- def query_one(element, selector)
29
- context = element.execution_context
28
+ # @param element [Puppeteer::ElementHandle]
29
+ # @param selector [String]
30
+ private def query_one_id(element, selector)
30
31
  parse_result = parse_aria_selector(selector)
31
32
  res = element.query_ax_tree(accessible_name: parse_result[:name], role: parse_result[:role])
32
- if res.empty?
33
+
34
+ if res.first.is_a?(Hash)
35
+ res.first['backendDOMNodeId']
36
+ else
33
37
  nil
38
+ end
39
+ end
40
+
41
+ def query_one(element, selector)
42
+ id = query_one_id(element, selector)
43
+
44
+ if id
45
+ element.frame.main_world.adopt_backend_node(id)
34
46
  else
35
- context.adopt_backend_node_id(res.first['backendDOMNodeId'])
47
+ nil
36
48
  end
37
49
  end
38
50
 
39
- def wait_for(dom_world, selector, visible: nil, hidden: nil, timeout: nil, root: nil)
51
+ def wait_for(element_or_frame, selector, visible: nil, hidden: nil, timeout: nil)
52
+ case element_or_frame
53
+ when Puppeteer::Frame
54
+ frame = element_or_frame
55
+ element = nil
56
+ when Puppeteer::ElementHandle
57
+ frame = element_or_frame.frame
58
+ element = frame.puppeteer_world.adopt_handle(element_or_frame)
59
+ else
60
+ raise ArgumentError.new("element_or_frame must be a Frame or ElementHandle. #{element_or_frame.inspect}")
61
+ end
62
+
40
63
  # addHandlerToWorld
41
- binding_function = Puppeteer::DOMWorld::BindingFunction.new(
64
+ binding_function = Puppeteer::IsolaatedWorld::BindingFunction.new(
42
65
  name: 'ariaQuerySelector',
43
- proc: -> (sel) { query_one(root || dom_world.send(:document), sel) },
66
+ proc: -> (sel) {
67
+ id = query_one_id(element || frame.puppeteer_world.document, sel)
68
+
69
+ if id
70
+ frame.puppeteer_world.adopt_backend_node(id)
71
+ else
72
+ nil
73
+ end
74
+ },
44
75
  )
45
- dom_world.send(:wait_for_selector_in_page,
76
+ result = frame.puppeteer_world.send(:wait_for_selector_in_page,
46
77
  '(_, selector) => globalThis.ariaQuerySelector(selector)',
78
+ element,
47
79
  selector,
48
80
  visible: visible,
49
81
  hidden: hidden,
50
82
  timeout: timeout,
51
83
  binding_function: binding_function,
52
- root: root,
53
84
  )
85
+
86
+ element&.dispose
87
+
88
+ if result.is_a?(Puppeteer::ElementHandle)
89
+ result.frame.main_world.transfer_handle(result)
90
+ else
91
+ result&.dispose
92
+ nil
93
+ end
54
94
  end
55
95
 
56
96
  def query_all(element, selector)
57
- context = element.execution_context
97
+ world = element.frame.main_world
58
98
  parse_result = parse_aria_selector(selector)
59
99
  res = element.query_ax_tree(accessible_name: parse_result[:name], role: parse_result[:role])
60
100
  if res.empty?
61
101
  nil
62
102
  else
63
103
  promises = res.map do |ax_node|
64
- context.send(:async_adopt_backend_node_id, ax_node['backendDOMNodeId'])
104
+ world.send(:async_adopt_backend_node, ax_node['backendDOMNodeId'])
65
105
  end
66
106
  await_all(*promises)
67
107
  end
@@ -108,7 +108,7 @@ class Puppeteer::Coverage
108
108
 
109
109
  # Filter out empty ranges.
110
110
  results.select do |range|
111
- range[:end] - range[:start] > 1
111
+ range[:end] - range[:start] > 0
112
112
  end
113
113
  end
114
114
  end
@@ -21,12 +21,39 @@ class Puppeteer::CustomQueryHandler
21
21
  nil
22
22
  end
23
23
 
24
- def wait_for(dom_world, selector, visible: nil, hidden: nil, timeout: nil, root: nil)
24
+ def wait_for(element_or_frame, selector, visible: nil, hidden: nil, timeout: nil)
25
+ case element_or_frame
26
+ when Puppeteer::Frame
27
+ frame = element_or_frame
28
+ element = nil
29
+ when Puppeteer::ElementHandle
30
+ frame = element_or_frame.frame
31
+ element = frame.puppeteer_world.adopt_handle(element_or_frame)
32
+ else
33
+ raise ArgumentError.new("element_or_frame must be a Frame or ElementHandle. #{element_or_frame.inspect}")
34
+ end
35
+
25
36
  unless @query_one
26
37
  raise NotImplementedError.new("#{self.class}##{__method__} is not implemented.")
27
38
  end
28
39
 
29
- dom_world.send(:wait_for_selector_in_page, @query_one, selector, visible: visible, hidden: hidden, timeout: timeout, root: root)
40
+ result = frame.puppeteer_world.send(:wait_for_selector_in_page,
41
+ @query_one,
42
+ element,
43
+ selector,
44
+ visible: visible,
45
+ hidden: hidden,
46
+ timeout: timeout,
47
+ )
48
+
49
+ element&.dispose
50
+
51
+ if result.is_a?(Puppeteer::ElementHandle)
52
+ result.frame.main_world.transfer_handle(result)
53
+ else
54
+ result&.dispose
55
+ nil
56
+ end
30
57
  end
31
58
 
32
59
  def query_all(element, selector)
@@ -12,16 +12,16 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
12
12
  # @param client [Puppeteer::CDPSession]
13
13
  # @param remote_object [Puppeteer::RemoteObject]
14
14
  # @param frame [Puppeteer::Frame]
15
- # @param page [Puppeteer::Page]
16
- # @param frame_manager [Puppeteer::FrameManager]
17
- def initialize(context:, client:, remote_object:, frame:, page:, frame_manager:)
15
+ def initialize(context:, client:, remote_object:, frame:)
18
16
  super(context: context, client: client, remote_object: remote_object)
19
17
  @frame = frame
20
- @page = page
21
- @frame_manager = frame_manager
18
+ @page = frame.page
19
+ @frame_manager = frame.frame_manager
22
20
  @disposed = false
23
21
  end
24
22
 
23
+ attr_reader :page, :frame, :frame_manager
24
+
25
25
  def inspect
26
26
  values = %i[context remote_object page disposed].map do |sym|
27
27
  value = instance_variable_get(:"@#{sym}")
@@ -60,18 +60,7 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
60
60
  # (30 seconds). Pass `0` to disable timeout. The default value can be changed
61
61
  # by using the {@link Page.setDefaultTimeout} method.
62
62
  def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil)
63
- frame = @context.frame
64
-
65
- secondary_world = frame.secondary_world
66
- adopted_root = secondary_world.execution_context.adopt_element_handle(self)
67
- handle = secondary_world.wait_for_selector(selector, visible: visible, hidden: hidden, timeout: timeout, root: adopted_root)
68
- adopted_root.dispose
69
- return nil unless handle
70
-
71
- main_world = frame.main_world
72
- result = main_world.execution_context.adopt_element_handle(handle)
73
- handle.dispose
74
- result
63
+ query_handler_manager.detect_query_handler(selector).wait_for(self, visible: visible, hidden: hidden, timeout: timeout)
75
64
  end
76
65
 
77
66
  define_async_method :async_wait_for_selector
@@ -653,6 +642,6 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
653
642
  # used in AriaQueryHandler
654
643
  def query_ax_tree(accessible_name: nil, role: nil)
655
644
  @remote_object.query_ax_tree(@client,
656
- accessible_name: accessible_name, role: role)
645
+ accessible_name: accessible_name, role: role)
657
646
  end
658
647
  end
@@ -7,7 +7,7 @@ class Puppeteer::ExecutionContext
7
7
 
8
8
  # @param client [Puppeteer::CDPSession]
9
9
  # @param context_payload [Hash]
10
- # @param world [Puppeteer::DOMWorld?]
10
+ # @param world [Puppeteer::IsolaatedWorld?]
11
11
  def initialize(client, context_payload, world)
12
12
  @client = client
13
13
  @world = world
@@ -17,23 +17,16 @@ class Puppeteer::ExecutionContext
17
17
 
18
18
  attr_reader :client, :world
19
19
 
20
- # only used in DOMWorld
20
+ # only used in IsolaatedWorld
21
21
  private def _context_id
22
22
  @context_id
23
23
  end
24
24
 
25
- # only used in DOMWorld::BindingFunction#add_binding_to_context
25
+ # only used in IsolaatedWorld::BindingFunction#add_binding_to_context
26
26
  private def _context_name
27
27
  @context_name
28
28
  end
29
29
 
30
- # @return [Puppeteer::Frame]
31
- def frame
32
- if_present(@world) do |world|
33
- world.frame
34
- end
35
- end
36
-
37
30
  # @param page_function [String]
38
31
  # @return [Object]
39
32
  def evaluate(page_function, *args)
@@ -208,54 +201,4 @@ class Puppeteer::ExecutionContext
208
201
  context_id: @context_id,
209
202
  )
210
203
  end
211
-
212
- # /**
213
- # * @param {!JSHandle} prototypeHandle
214
- # * @return {!Promise<!JSHandle>}
215
- # */
216
- # async queryObjects(prototypeHandle) {
217
- # assert(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!');
218
- # assert(prototypeHandle._remoteObject.objectId, 'Prototype JSHandle must not be referencing primitive value');
219
- # const response = await this._client.send('Runtime.queryObjects', {
220
- # prototypeObjectId: prototypeHandle._remoteObject.objectId
221
- # });
222
- # return createJSHandle(this, response.objects);
223
- # }
224
-
225
- # @param backend_node_id [Integer]
226
- # @return [Puppeteer::ElementHandle]
227
- def adopt_backend_node_id(backend_node_id)
228
- response = @client.send_message('DOM.resolveNode',
229
- backendNodeId: backend_node_id,
230
- executionContextId: @context_id,
231
- )
232
- Puppeteer::JSHandle.create(
233
- context: self,
234
- remote_object: Puppeteer::RemoteObject.new(response["object"]),
235
- )
236
- end
237
- private define_async_method :async_adopt_backend_node_id
238
-
239
- # @param element_handle [Puppeteer::ElementHandle]
240
- # @return [Puppeteer::ElementHandle]
241
- def adopt_element_handle(element_handle)
242
- if element_handle.execution_context == self
243
- raise ArgumentError.new('Cannot adopt handle that already belongs to this execution context')
244
- end
245
-
246
- unless @world
247
- raise 'Cannot adopt handle without DOMWorld'
248
- end
249
-
250
- node_info = element_handle.remote_object.node_info(@client)
251
- response = @client.send_message('DOM.resolveNode',
252
- backendNodeId: node_info["node"]["backendNodeId"],
253
- executionContextId: @context_id,
254
- )
255
-
256
- Puppeteer::JSHandle.create(
257
- context: self,
258
- remote_object: Puppeteer::RemoteObject.new(response["object"]),
259
- )
260
- end
261
204
  end
@@ -37,8 +37,8 @@ class Puppeteer::Frame
37
37
  # @param client [Puppeteer::CDPSession]
38
38
  private def update_client(client)
39
39
  @client = client
40
- @main_world = Puppeteer::DOMWorld.new(@client, @frame_manager, self, @frame_manager.timeout_settings)
41
- @secondary_world = Puppeteer::DOMWorld.new(@client, @frame_manager, self, @frame_manager.timeout_settings)
40
+ @main_world = Puppeteer::IsolaatedWorld.new(@client, @frame_manager, self, @frame_manager.timeout_settings)
41
+ @puppeteer_world = Puppeteer::IsolaatedWorld.new(@client, @frame_manager, self, @frame_manager.timeout_settings)
42
42
  end
43
43
 
44
44
  def page
@@ -49,7 +49,7 @@ class Puppeteer::Frame
49
49
  @client != @frame_manager.client
50
50
  end
51
51
 
52
- attr_accessor :frame_manager, :id, :loader_id, :lifecycle_events, :main_world, :secondary_world
52
+ attr_accessor :frame_manager, :id, :loader_id, :lifecycle_events, :main_world, :puppeteer_world
53
53
 
54
54
  def has_started_loading?
55
55
  @has_started_loading
@@ -154,14 +154,14 @@ class Puppeteer::Frame
154
154
 
155
155
  # @return [String]
156
156
  def content
157
- @secondary_world.content
157
+ @puppeteer_world.content
158
158
  end
159
159
 
160
160
  # @param html [String]
161
161
  # @param timeout [Integer]
162
162
  # @param wait_until [String|Array<String>]
163
163
  def set_content(html, timeout: nil, wait_until: nil)
164
- @secondary_world.set_content(html, timeout: timeout, wait_until: wait_until)
164
+ @puppeteer_world.set_content(html, timeout: timeout, wait_until: wait_until)
165
165
  end
166
166
 
167
167
  # @return [String]
@@ -212,35 +212,35 @@ class Puppeteer::Frame
212
212
  # @param button [String] "left"|"right"|"middle"
213
213
  # @param click_count [Number]
214
214
  def click(selector, delay: nil, button: nil, click_count: nil)
215
- @secondary_world.click(selector, delay: delay, button: button, click_count: click_count)
215
+ @puppeteer_world.click(selector, delay: delay, button: button, click_count: click_count)
216
216
  end
217
217
 
218
218
  define_async_method :async_click
219
219
 
220
220
  # @param {string} selector
221
221
  def focus(selector)
222
- @secondary_world.focus(selector)
222
+ @puppeteer_world.focus(selector)
223
223
  end
224
224
 
225
225
  define_async_method :async_focus
226
226
 
227
227
  # @param {string} selector
228
228
  def hover(selector)
229
- @secondary_world.hover(selector)
229
+ @puppeteer_world.hover(selector)
230
230
  end
231
231
 
232
232
  # @param {string} selector
233
233
  # @param {!Array<string>} values
234
234
  # @return {!Promise<!Array<string>>}
235
235
  def select(selector, *values)
236
- @secondary_world.select(selector, *values)
236
+ @puppeteer_world.select(selector, *values)
237
237
  end
238
238
 
239
239
  define_async_method :async_select
240
240
 
241
241
  # @param {string} selector
242
242
  def tap(selector)
243
- @secondary_world.tap(selector)
243
+ @puppeteer_world.tap(selector)
244
244
  end
245
245
 
246
246
  define_async_method :async_tap
@@ -259,14 +259,8 @@ class Puppeteer::Frame
259
259
  # @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
260
260
  # @param timeout [Integer]
261
261
  def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil)
262
- handle = @secondary_world.wait_for_selector(selector, visible: visible, hidden: hidden, timeout: timeout)
263
- if !handle
264
- return nil
265
- end
266
- main_execution_context = @main_world.execution_context
267
- result = main_execution_context.adopt_element_handle(handle)
268
- handle.dispose
269
- result
262
+ query_handler_manager = Puppeteer::QueryHandlerManager.instance
263
+ query_handler_manager.detect_query_handler(selector).wait_for(self, visible: visible, hidden: hidden, timeout: timeout)
270
264
  end
271
265
 
272
266
  define_async_method :async_wait_for_selector
@@ -306,7 +300,7 @@ class Puppeteer::Frame
306
300
 
307
301
  # @return [String]
308
302
  def title
309
- @secondary_world.title
303
+ @puppeteer_world.title
310
304
  end
311
305
 
312
306
  # @param frame_payload [Hash]
@@ -344,7 +338,7 @@ class Puppeteer::Frame
344
338
  def detach
345
339
  @detached = true
346
340
  @main_world.detach
347
- @secondary_world.detach
341
+ @puppeteer_world.detach
348
342
  if @parent_frame
349
343
  @parent_frame._child_frames.delete(self)
350
344
  end
@@ -413,11 +413,11 @@ class Puppeteer::FrameManager
413
413
 
414
414
  if context_payload.dig('auxData', 'isDefault')
415
415
  world = frame.main_world
416
- elsif context_payload['name'] == UTILITY_WORLD_NAME && !frame.secondary_world.has_context?
416
+ elsif context_payload['name'] == UTILITY_WORLD_NAME && !frame.puppeteer_world.has_context?
417
417
  # In case of multiple sessions to the same target, there's a race between
418
418
  # connections so we might end up creating multiple isolated worlds.
419
419
  # We can use either.
420
- world = frame.secondary_world
420
+ world = frame.puppeteer_world
421
421
  end
422
422
  end
423
423
 
@@ -1,7 +1,7 @@
1
1
  require 'thread'
2
2
 
3
- # https://github.com/puppeteer/puppeteer/blob/master/src/DOMWorld.js
4
- class Puppeteer::DOMWorld
3
+ # https://github.com/puppeteer/puppeteer/blob/master/src/IsolaatedWorld.js
4
+ class Puppeteer::IsolaatedWorld
5
5
  using Puppeteer::DefineAsyncMethod
6
6
 
7
7
  class BindingFunction
@@ -152,7 +152,7 @@ class Puppeteer::DOMWorld
152
152
  raise 'Bug of puppeteer-ruby...'
153
153
  end
154
154
 
155
- private def document
155
+ def document
156
156
  @document ||= evaluate_document.as_element
157
157
  end
158
158
 
@@ -416,16 +416,6 @@ class Puppeteer::DOMWorld
416
416
  handle.dispose
417
417
  end
418
418
 
419
- # @param selector [String]
420
- # @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
421
- # @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
422
- # @param timeout [Integer]
423
- def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil, root: nil)
424
- # call wait_for_selector_in_page with custom query selector.
425
- query_selector_manager = Puppeteer::QueryHandlerManager.instance
426
- query_selector_manager.detect_query_handler(selector).wait_for(self, visible: visible, hidden: hidden, timeout: timeout, root: root)
427
- end
428
-
429
419
  private def binding_identifier(name, context)
430
420
  "#{name}_#{context.send(:_context_id)}"
431
421
  end
@@ -497,7 +487,7 @@ class Puppeteer::DOMWorld
497
487
  # @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
498
488
  # @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
499
489
  # @param timeout [Integer]
500
- private def wait_for_selector_in_page(query_one, selector, visible: nil, hidden: nil, timeout: nil, root: nil, binding_function: nil)
490
+ private def wait_for_selector_in_page(query_one, root, selector, visible: nil, hidden: nil, timeout: nil, binding_function: nil)
501
491
  option_wait_for_visible = visible || false
502
492
  option_wait_for_hidden = hidden || false
503
493
  option_timeout = timeout || @timeout_settings.timeout
@@ -531,12 +521,7 @@ class Puppeteer::DOMWorld
531
521
  root: option_root,
532
522
  binding_function: binding_function,
533
523
  )
534
- handle = wait_task.await_promise
535
- unless handle.as_element
536
- handle.dispose
537
- return nil
538
- end
539
- handle.as_element
524
+ wait_task.await_promise
540
525
  end
541
526
 
542
527
  # @param page_function [String]
@@ -601,4 +586,35 @@ class Puppeteer::DOMWorld
601
586
  }
602
587
  JAVASCRIPT
603
588
  end
589
+
590
+ # @param backend_node_id [Integer]
591
+ # @return [Puppeteer::ElementHandle]
592
+ def adopt_backend_node(backend_node_id)
593
+ response = @client.send_message('DOM.resolveNode',
594
+ backendNodeId: backend_node_id,
595
+ executionContextId: execution_context.send(:_context_id),
596
+ )
597
+ Puppeteer::JSHandle.create(
598
+ context: execution_context,
599
+ remote_object: Puppeteer::RemoteObject.new(response["object"]),
600
+ )
601
+ end
602
+ private define_async_method :async_adopt_backend_node
603
+
604
+ # @param element_handle [Puppeteer::ElementHandle]
605
+ # @return [Puppeteer::ElementHandle]
606
+ def adopt_handle(element_handle)
607
+ if element_handle.execution_context == execution_context
608
+ raise ArgumentError.new('Cannot adopt handle that already belongs to this execution context')
609
+ end
610
+
611
+ node_info = element_handle.remote_object.node_info(@client)
612
+ adopt_backend_node(node_info["node"]["backendNodeId"])
613
+ end
614
+
615
+ def transfer_handle(element_handle)
616
+ result = adopt_handle(element_handle)
617
+ element_handle.dispose
618
+ result
619
+ end
604
620
  end
@@ -5,16 +5,12 @@ class Puppeteer::JSHandle
5
5
  # @param context [Puppeteer::ExecutionContext]
6
6
  # @param remote_object [Puppeteer::RemoteObject]
7
7
  def self.create(context:, remote_object:)
8
- frame = context.frame
9
- if remote_object.sub_type == 'node' && frame
10
- frame_manager = frame.frame_manager
8
+ if remote_object.sub_type == 'node' && context.world
11
9
  Puppeteer::ElementHandle.new(
12
10
  context: context,
13
11
  client: context.client,
14
12
  remote_object: remote_object,
15
- frame: frame,
16
- page: frame_manager.page,
17
- frame_manager: frame_manager,
13
+ frame: context.world.frame,
18
14
  )
19
15
  else
20
16
  Puppeteer::JSHandle.new(
@@ -93,13 +93,14 @@ class Puppeteer::LifecycleWatcher
93
93
  check_lifecycle_complete
94
94
  end
95
95
 
96
- class AnotherRequestReceivedError < StandardError ; end
97
-
98
96
  # @param [Puppeteer::HTTPRequest] request
99
97
  def handle_request(request)
100
98
  return if request.frame != @frame || !request.navigation_request?
101
99
  @navigation_request = request
102
- @navigation_response_received&.reject(AnotherRequestReceivedError.new('New navigation request was received'))
100
+ # Resolve previous navigation response in case there are multiple
101
+ # navigation requests reported by the backend. This generally should not
102
+ # happen by it looks like it's possible.
103
+ @navigation_response_received&.fulfill(nil)
103
104
  @navigation_response_received = resolvable_future
104
105
  if request.response && !@navigation_response_received.resolved?
105
106
  @navigation_response_received.fulfill(nil)
@@ -191,8 +191,7 @@ class Puppeteer::Page
191
191
  return if @file_chooser_interceptors.empty?
192
192
 
193
193
  frame = @frame_manager.frame(event['frameId'])
194
- context = frame.execution_context
195
- element = context.adopt_backend_node_id(event['backendNodeId'])
194
+ element = frame.main_world.adopt_backend_node(event['backendNodeId'])
196
195
  interceptors = @file_chooser_interceptors.to_a
197
196
  @file_chooser_interceptors.clear
198
197
  file_chooser = Puppeteer::FileChooser.new(element, event)
@@ -1070,7 +1069,8 @@ class Puppeteer::Page
1070
1069
  clip = if_present(screenshot_options.clip) do |rect|
1071
1070
  x = rect[:x].round
1072
1071
  y = rect[:y].round
1073
- { x: x, y: y, width: rect[:width] + rect[:x] - x, height: rect[:height] + rect[:y] - y, scale: 1 }
1072
+ scale = rect[:scale] || 1
1073
+ { x: x, y: y, width: rect[:width] + rect[:x] - x, height: rect[:height] + rect[:y] - y, scale: scale }
1074
1074
  end
1075
1075
 
1076
1076
  if screenshot_options.full_page?
@@ -61,8 +61,8 @@ class Puppeteer::QueryHandlerManager
61
61
  @query_handler.query_one(element_handle, @selector)
62
62
  end
63
63
 
64
- def wait_for(dom_world, visible:, hidden:, timeout:, root:)
65
- @query_handler.wait_for(dom_world, @selector, visible: visible, hidden: hidden, timeout: timeout, root: root)
64
+ def wait_for(element_or_frame, visible:, hidden:, timeout:)
65
+ @query_handler.wait_for(element_or_frame, @selector, visible: visible, hidden: hidden, timeout: timeout)
66
66
  end
67
67
 
68
68
  def query_all(element_handle)
@@ -105,8 +105,8 @@ class Puppeteer::RemoteObject
105
105
  role: role,
106
106
  }.compact)
107
107
 
108
- result['nodes'].reject do |node|
109
- node['role']['value'] == 'text'
108
+ result['nodes'].select do |node|
109
+ node['role'] && node['role']['value'] != 'StaticText'
110
110
  end
111
111
  end
112
112
 
@@ -1,3 +1,3 @@
1
1
  module Puppeteer
2
- VERSION = '0.43.1'
2
+ VERSION = '0.44.0'
3
3
  end
data/lib/puppeteer.rb CHANGED
@@ -32,7 +32,6 @@ require 'puppeteer/css_coverage'
32
32
  require 'puppeteer/custom_query_handler'
33
33
  require 'puppeteer/devices'
34
34
  require 'puppeteer/dialog'
35
- require 'puppeteer/dom_world'
36
35
  require 'puppeteer/emulation_manager'
37
36
  require 'puppeteer/exception_details'
38
37
  require 'puppeteer/executable_path_finder'
@@ -43,6 +42,7 @@ require 'puppeteer/frame'
43
42
  require 'puppeteer/frame_manager'
44
43
  require 'puppeteer/http_request'
45
44
  require 'puppeteer/http_response'
45
+ require 'puppeteer/isolated_world'
46
46
  require 'puppeteer/js_coverage'
47
47
  require 'puppeteer/js_handle'
48
48
  require 'puppeteer/keyboard'
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.43.1
4
+ version: 0.44.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - YusukeIwaki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-18 00:00:00.000000000 Z
11
+ date: 2022-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -272,7 +272,6 @@ files:
272
272
  - lib/puppeteer/device.rb
273
273
  - lib/puppeteer/devices.rb
274
274
  - lib/puppeteer/dialog.rb
275
- - lib/puppeteer/dom_world.rb
276
275
  - lib/puppeteer/element_handle.rb
277
276
  - lib/puppeteer/element_handle/bounding_box.rb
278
277
  - lib/puppeteer/element_handle/box_model.rb
@@ -294,6 +293,7 @@ files:
294
293
  - lib/puppeteer/http_request.rb
295
294
  - lib/puppeteer/http_response.rb
296
295
  - lib/puppeteer/if_present.rb
296
+ - lib/puppeteer/isolated_world.rb
297
297
  - lib/puppeteer/js_coverage.rb
298
298
  - lib/puppeteer/js_handle.rb
299
299
  - lib/puppeteer/keyboard.rb