puppeteer-ruby 0.0.5 → 0.0.6
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 +4 -4
- data/docs/Puppeteer.html +2 -2
- data/docs/Puppeteer/AsyncAwaitBehavior.html +1 -1
- data/docs/Puppeteer/Browser.html +1 -1
- data/docs/Puppeteer/BrowserContext.html +1 -1
- data/docs/Puppeteer/BrowserFetcher.html +1 -1
- data/docs/Puppeteer/BrowserRunner.html +1 -1
- data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +1 -1
- data/docs/Puppeteer/CDPSession.html +86 -57
- data/docs/Puppeteer/CDPSession/Error.html +1 -1
- data/docs/Puppeteer/ConcurrentRubyUtils.html +1 -1
- data/docs/Puppeteer/Connection.html +1 -1
- data/docs/Puppeteer/Connection/MessageCallback.html +1 -1
- data/docs/Puppeteer/Connection/ProtocolError.html +1 -1
- data/docs/Puppeteer/Connection/RequestDebugPrinter.html +1 -1
- data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +1 -1
- data/docs/Puppeteer/ConsoleMessage.html +1 -1
- data/docs/Puppeteer/ConsoleMessage/Location.html +1 -1
- data/docs/Puppeteer/DOMWorld.html +610 -68
- data/docs/Puppeteer/DOMWorld/DetachedError.html +1 -1
- data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +1 -1
- data/docs/Puppeteer/DebugPrint.html +2 -2
- data/docs/Puppeteer/Device.html +1 -1
- data/docs/Puppeteer/Devices.html +1 -1
- data/docs/Puppeteer/ElementHandle.html +306 -109
- data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +5 -5
- data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +5 -5
- data/docs/Puppeteer/ElementHandle/Point.html +28 -28
- data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +1 -1
- data/docs/Puppeteer/EmulationManager.html +1 -1
- data/docs/Puppeteer/EventCallbackable.html +1 -1
- data/docs/Puppeteer/EventCallbackable/EventListeners.html +1 -1
- data/docs/Puppeteer/ExecutionContext.html +124 -1
- data/docs/Puppeteer/ExecutionContext/EvaluationError.html +1 -1
- data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +1 -1
- data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +2 -2
- data/docs/Puppeteer/Frame.html +117 -65
- data/docs/Puppeteer/FrameManager.html +1 -1
- data/docs/Puppeteer/FrameManager/NavigationError.html +1 -1
- data/docs/Puppeteer/IfPresent.html +1 -1
- data/docs/Puppeteer/JSHandle.html +1 -1
- data/docs/Puppeteer/Keyboard.html +1 -1
- data/docs/Puppeteer/Keyboard/KeyDefinition.html +1 -1
- data/docs/Puppeteer/Keyboard/KeyDescription.html +1 -1
- data/docs/Puppeteer/Launcher.html +1 -1
- data/docs/Puppeteer/Launcher/Base.html +1 -1
- data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +1 -1
- data/docs/Puppeteer/Launcher/BrowserOptions.html +1 -1
- data/docs/Puppeteer/Launcher/Chrome.html +1 -1
- data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +1 -1
- data/docs/Puppeteer/Launcher/ChromeArgOptions.html +1 -1
- data/docs/Puppeteer/Launcher/LaunchOptions.html +1 -1
- data/docs/Puppeteer/LifecycleWatcher.html +1 -1
- data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +1 -1
- data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +1 -1
- data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +1 -1
- data/docs/Puppeteer/Mouse.html +1 -1
- data/docs/Puppeteer/Mouse/Button.html +1 -1
- data/docs/Puppeteer/NetworkManager.html +1 -1
- data/docs/Puppeteer/NetworkManager/Credentials.html +1 -1
- data/docs/Puppeteer/Page.html +95 -43
- data/docs/Puppeteer/Page/ScreenshotOptions.html +1 -1
- data/docs/Puppeteer/Page/ScriptTag.html +1 -1
- data/docs/Puppeteer/Page/StyleTag.html +1 -1
- data/docs/Puppeteer/Page/TargetCrashedError.html +1 -1
- data/docs/Puppeteer/RemoteObject.html +1 -1
- data/docs/Puppeteer/Target.html +1 -1
- data/docs/Puppeteer/Target/InitializeFailure.html +1 -1
- data/docs/Puppeteer/Target/TargetInfo.html +1 -1
- data/docs/Puppeteer/TimeoutError.html +1 -1
- data/docs/Puppeteer/TimeoutSettings.html +1 -1
- data/docs/Puppeteer/TouchScreen.html +1 -1
- data/docs/Puppeteer/Viewport.html +1 -1
- data/docs/Puppeteer/WaitTask.html +434 -8
- data/docs/Puppeteer/WaitTask/TerminatedError.html +1 -1
- data/docs/Puppeteer/WaitTask/TimeoutError.html +206 -0
- data/docs/Puppeteer/WebSocket.html +1 -1
- data/docs/Puppeteer/WebSocket/DriverImpl.html +1 -1
- data/docs/Puppeteer/WebSocketTransport.html +1 -1
- data/docs/Puppeteer/WebSocktTransportError.html +1 -1
- data/docs/_index.html +8 -1
- data/docs/class_list.html +1 -1
- data/docs/file.README.html +1 -1
- data/docs/index.html +1 -1
- data/docs/method_list.html +615 -519
- data/docs/top-level-namespace.html +1 -1
- data/lib/puppeteer/cdp_session.rb +33 -11
- data/lib/puppeteer/dom_world.rb +97 -90
- data/lib/puppeteer/element_handle.rb +36 -54
- data/lib/puppeteer/execution_context.rb +23 -17
- data/lib/puppeteer/frame.rb +13 -11
- data/lib/puppeteer/page.rb +29 -11
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer/wait_task.rb +183 -1
- metadata +3 -2
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
</div>
|
|
117
117
|
|
|
118
118
|
<div id="footer">
|
|
119
|
-
Generated on
|
|
119
|
+
Generated on Mon May 25 23:22:48 2020 by
|
|
120
120
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
121
121
|
0.9.24 (ruby-2.6.3).
|
|
122
122
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
class Puppeteer::CDPSession
|
|
2
|
+
include Puppeteer::DebugPrint
|
|
2
3
|
include Puppeteer::EventCallbackable
|
|
3
4
|
using Puppeteer::AsyncAwaitBehavior
|
|
4
5
|
|
|
@@ -12,6 +13,7 @@ class Puppeteer::CDPSession
|
|
|
12
13
|
@connection = connection
|
|
13
14
|
@target_type = target_type
|
|
14
15
|
@session_id = session_id
|
|
16
|
+
@pending_messages = {}
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
attr_reader :connection
|
|
@@ -32,7 +34,13 @@ class Puppeteer::CDPSession
|
|
|
32
34
|
end
|
|
33
35
|
id = @connection.raw_send(message: { sessionId: @session_id, method: method, params: params })
|
|
34
36
|
promise = resolvable_future
|
|
35
|
-
|
|
37
|
+
callback = Puppeteer::Connection::MessageCallback.new(method: method, promise: promise)
|
|
38
|
+
if pending_message = @pending_messages.delete(id)
|
|
39
|
+
debug_puts "Pending message (id: #{id}) is handled"
|
|
40
|
+
callback_with_message(callback, pending_message)
|
|
41
|
+
else
|
|
42
|
+
@callbacks[id] = callback
|
|
43
|
+
end
|
|
36
44
|
promise
|
|
37
45
|
end
|
|
38
46
|
|
|
@@ -40,23 +48,37 @@ class Puppeteer::CDPSession
|
|
|
40
48
|
def handle_message(message)
|
|
41
49
|
if message['id']
|
|
42
50
|
if callback = @callbacks.delete(message['id'])
|
|
43
|
-
|
|
44
|
-
callback.reject(
|
|
45
|
-
Puppeteer::Connection::ProtocolError.new(
|
|
46
|
-
method: callback.method,
|
|
47
|
-
error_message: message['error']['message'],
|
|
48
|
-
error_data: message['error']['data']))
|
|
49
|
-
else
|
|
50
|
-
callback.resolve(message['result'])
|
|
51
|
-
end
|
|
51
|
+
callback_with_message(callback, message)
|
|
52
52
|
else
|
|
53
|
-
|
|
53
|
+
debug_puts "unknown id: #{id}. Store it into pending message"
|
|
54
|
+
|
|
55
|
+
# RECV is often notified before SEND.
|
|
56
|
+
# Wait about 10 frames before throwing an error.
|
|
57
|
+
message_id = message['id']
|
|
58
|
+
@pending_messages[message_id] = message
|
|
59
|
+
Concurrent::Promises.schedule(0.16, message_id) do |id|
|
|
60
|
+
if @pending_messages.delete(id)
|
|
61
|
+
raise Error.new("unknown id: #{id}")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
54
64
|
end
|
|
55
65
|
else
|
|
56
66
|
emit_event message['method'], message['params']
|
|
57
67
|
end
|
|
58
68
|
end
|
|
59
69
|
|
|
70
|
+
private def callback_with_message(callback, message)
|
|
71
|
+
if message['error']
|
|
72
|
+
callback.reject(
|
|
73
|
+
Puppeteer::Connection::ProtocolError.new(
|
|
74
|
+
method: callback.method,
|
|
75
|
+
error_message: message['error']['message'],
|
|
76
|
+
error_data: message['error']['data']))
|
|
77
|
+
else
|
|
78
|
+
callback.resolve(message['result'])
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
60
82
|
def detach
|
|
61
83
|
if !@connection
|
|
62
84
|
raise Error.new("Session already detarched. Most likely the #{@target_type} has been closed.")
|
data/lib/puppeteer/dom_world.rb
CHANGED
|
@@ -19,6 +19,11 @@ class Puppeteer::DOMWorld
|
|
|
19
19
|
|
|
20
20
|
attr_reader :frame
|
|
21
21
|
|
|
22
|
+
# only used in Puppeteer::WaitTask#initialize
|
|
23
|
+
def _wait_tasks
|
|
24
|
+
@wait_tasks
|
|
25
|
+
end
|
|
26
|
+
|
|
22
27
|
# @param {?Puppeteer.ExecutionContext} context
|
|
23
28
|
def context=(context)
|
|
24
29
|
# D, [2020-04-12T22:45:03.938754 #46154] DEBUG -- : RECV << {"method"=>"Runtime.executionContextCreated", "params"=>{"context"=>{"id"=>3, "origin"=>"https://github.com", "name"=>"", "auxData"=>{"isDefault"=>true, "type"=>"default", "frameId"=>"3AD7F1E82BCBA88BFE31D03BC49FF6CB"}}}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
|
|
@@ -35,8 +40,7 @@ class Puppeteer::DOMWorld
|
|
|
35
40
|
@context_promise = resolvable_future
|
|
36
41
|
end
|
|
37
42
|
@context_promise.fulfill(context)
|
|
38
|
-
|
|
39
|
-
# waitTask.rerun();
|
|
43
|
+
@wait_tasks.each(&:async_rerun)
|
|
40
44
|
else
|
|
41
45
|
raise ArgumentError.new("context should now be nil. Use #delete_context for clearing document.")
|
|
42
46
|
end
|
|
@@ -364,45 +368,37 @@ class Puppeteer::DOMWorld
|
|
|
364
368
|
# return result;
|
|
365
369
|
# }
|
|
366
370
|
|
|
367
|
-
#
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
# await handle.tap();
|
|
374
|
-
# await handle.dispose();
|
|
375
|
-
# }
|
|
371
|
+
# @param selector [String]
|
|
372
|
+
def tap(selector)
|
|
373
|
+
handle = S(selector)
|
|
374
|
+
handle.tap
|
|
375
|
+
handle.dispose
|
|
376
|
+
end
|
|
376
377
|
|
|
377
|
-
#
|
|
378
|
-
#
|
|
379
|
-
#
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
# await handle.type(text, options);
|
|
386
|
-
# await handle.dispose();
|
|
387
|
-
# }
|
|
378
|
+
# @param selector [String]
|
|
379
|
+
# @param text [String]
|
|
380
|
+
# @param delay [Number]
|
|
381
|
+
def type_text(selector, text, delay: nil)
|
|
382
|
+
handle = S(selector)
|
|
383
|
+
handle.type_text(text, delay: delay)
|
|
384
|
+
handle.dispose
|
|
385
|
+
end
|
|
388
386
|
|
|
389
|
-
#
|
|
390
|
-
#
|
|
391
|
-
#
|
|
392
|
-
#
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
# }
|
|
387
|
+
# @param selector [String]
|
|
388
|
+
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
|
389
|
+
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
|
390
|
+
# @param timeout [Integer]
|
|
391
|
+
def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil)
|
|
392
|
+
wait_for_selector_or_xpath(selector, false, visible: visible, hidden: hidden, timeout: timeout)
|
|
393
|
+
end
|
|
397
394
|
|
|
398
|
-
#
|
|
399
|
-
#
|
|
400
|
-
#
|
|
401
|
-
#
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
# }
|
|
395
|
+
# @param xpath [String]
|
|
396
|
+
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
|
397
|
+
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
|
398
|
+
# @param timeout [Integer]
|
|
399
|
+
def wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil)
|
|
400
|
+
wait_for_selector_or_xpath(xpath, true, visible: visible, hidden: hidden, timeout: timeout)
|
|
401
|
+
end
|
|
406
402
|
|
|
407
403
|
# /**
|
|
408
404
|
# * @param {Function|string} pageFunction
|
|
@@ -424,57 +420,68 @@ class Puppeteer::DOMWorld
|
|
|
424
420
|
# return this.evaluate(() => document.title);
|
|
425
421
|
# }
|
|
426
422
|
|
|
427
|
-
#
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
#
|
|
431
|
-
#
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
423
|
+
# @param selector_or_xpath [String]
|
|
424
|
+
# @param is_xpath [Boolean]
|
|
425
|
+
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
|
426
|
+
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
|
427
|
+
# @param timeout [Integer]
|
|
428
|
+
private def wait_for_selector_or_xpath(selector_or_xpath, is_xpath, visible: nil, hidden: nil, timeout: nil)
|
|
429
|
+
option_wait_for_visible = visible || false
|
|
430
|
+
option_wait_for_hidden = hidden || false
|
|
431
|
+
option_timeout = timeout || @timeout_settings.timeout
|
|
432
|
+
|
|
433
|
+
polling =
|
|
434
|
+
if option_wait_for_visible || option_wait_for_hidden
|
|
435
|
+
'raf'
|
|
436
|
+
else
|
|
437
|
+
'mutation'
|
|
438
|
+
end
|
|
439
|
+
title = "#{is_xpath ? :XPath : :selector} #{selector_or_xpath}#{option_wait_for_hidden ? 'to be hidden' : ''}"
|
|
440
|
+
|
|
441
|
+
wait_task = Puppeteer::WaitTask.new(
|
|
442
|
+
dom_world: self,
|
|
443
|
+
predicate_body: "return (#{PREDICATE})(...args)",
|
|
444
|
+
title: title,
|
|
445
|
+
polling: polling,
|
|
446
|
+
timeout: option_timeout,
|
|
447
|
+
args: [selector_or_xpath, is_xpath, option_wait_for_visible, option_wait_for_hidden],
|
|
448
|
+
)
|
|
449
|
+
handle = wait_task.await_promise
|
|
450
|
+
unless handle.as_element
|
|
451
|
+
handle.dispose
|
|
452
|
+
return nil
|
|
453
|
+
end
|
|
454
|
+
handle.as_element
|
|
455
|
+
end
|
|
448
456
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
# }
|
|
457
|
+
PREDICATE = <<~JAVASCRIPT
|
|
458
|
+
/**
|
|
459
|
+
* @param {string} selectorOrXPath
|
|
460
|
+
* @param {boolean} isXPath
|
|
461
|
+
* @param {boolean} waitForVisible
|
|
462
|
+
* @param {boolean} waitForHidden
|
|
463
|
+
* @return {?Node|boolean}
|
|
464
|
+
*/
|
|
465
|
+
function _(selectorOrXPath, isXPath, waitForVisible, waitForHidden) {
|
|
466
|
+
const node = isXPath
|
|
467
|
+
? document.evaluate(selectorOrXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
|
|
468
|
+
: document.querySelector(selectorOrXPath);
|
|
469
|
+
if (!node)
|
|
470
|
+
return waitForHidden;
|
|
471
|
+
if (!waitForVisible && !waitForHidden)
|
|
472
|
+
return node;
|
|
473
|
+
const element = /** @type {Element} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node);
|
|
474
|
+
const style = window.getComputedStyle(element);
|
|
475
|
+
const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
|
|
476
|
+
const success = (waitForVisible === isVisible || waitForHidden === !isVisible);
|
|
477
|
+
return success ? node : null;
|
|
478
|
+
/**
|
|
479
|
+
* @return {boolean}
|
|
480
|
+
*/
|
|
481
|
+
function hasVisibleBoundingBox() {
|
|
482
|
+
const rect = element.getBoundingClientRect();
|
|
483
|
+
return !!(rect.top || rect.bottom || rect.width || rect.height);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
JAVASCRIPT
|
|
480
487
|
end
|
|
@@ -37,20 +37,8 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
|
37
37
|
return 'Node is detached from document';
|
|
38
38
|
if (element.nodeType !== Node.ELEMENT_NODE)
|
|
39
39
|
return 'Node is not of type HTMLElement';
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
element.scrollIntoView({block: 'center', inline: 'center', behavior: 'instant'});
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
const visibleRatio = await new Promise(resolve => {
|
|
46
|
-
const observer = new IntersectionObserver(entries => {
|
|
47
|
-
resolve(entries[0].intersectionRatio);
|
|
48
|
-
observer.disconnect();
|
|
49
|
-
});
|
|
50
|
-
observer.observe(element);
|
|
51
|
-
});
|
|
52
|
-
if (visibleRatio !== 1.0)
|
|
53
|
-
element.scrollIntoView({block: 'center', inline: 'center', behavior: 'instant'});
|
|
40
|
+
|
|
41
|
+
element.scrollIntoViewIfNeeded({block: 'center', inline: 'center', behavior: 'instant'});
|
|
54
42
|
return false;
|
|
55
43
|
}
|
|
56
44
|
JAVASCRIPT
|
|
@@ -58,6 +46,9 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
|
58
46
|
if error
|
|
59
47
|
raise ScrollIntoViewError.new(error)
|
|
60
48
|
end
|
|
49
|
+
# clickpoint is often calculated before scrolling is completed.
|
|
50
|
+
# So, just sleep about 10 frames
|
|
51
|
+
sleep 0.16
|
|
61
52
|
end
|
|
62
53
|
|
|
63
54
|
class Point
|
|
@@ -157,14 +148,12 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
|
157
148
|
@page.mouse.click(point.x, point.y, delay: delay, button: button, click_count: click_count)
|
|
158
149
|
end
|
|
159
150
|
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# await this._page.mouse.click(x, y, options);
|
|
167
|
-
# }
|
|
151
|
+
# @param delay [Number]
|
|
152
|
+
# @param button [String] "left"|"right"|"middle"
|
|
153
|
+
# @param click_count [Number]
|
|
154
|
+
async def async_click(delay: nil, button: nil, click_count: nil)
|
|
155
|
+
click(delay: delay, button: button, click_count: click_count)
|
|
156
|
+
end
|
|
168
157
|
|
|
169
158
|
# /**
|
|
170
159
|
# * @param {!Array<string>} values
|
|
@@ -228,11 +217,11 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
|
228
217
|
# }, files);
|
|
229
218
|
# }
|
|
230
219
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
220
|
+
def tap
|
|
221
|
+
scroll_into_view_if_needed
|
|
222
|
+
point = clickable_point
|
|
223
|
+
@page.touchscreen.tap(point.x, point.y)
|
|
224
|
+
end
|
|
236
225
|
|
|
237
226
|
|
|
238
227
|
def focus
|
|
@@ -419,33 +408,26 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
|
419
408
|
result
|
|
420
409
|
end
|
|
421
410
|
|
|
422
|
-
#
|
|
423
|
-
#
|
|
424
|
-
#
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
# for (const property of properties.values()) {
|
|
443
|
-
# const elementHandle = property.asElement();
|
|
444
|
-
# if (elementHandle)
|
|
445
|
-
# result.push(elementHandle);
|
|
446
|
-
# }
|
|
447
|
-
# return result;
|
|
448
|
-
# }
|
|
411
|
+
# `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
|
412
|
+
# @param expression [String]
|
|
413
|
+
# @return [Array<ElementHandle>]
|
|
414
|
+
def Sx(expression)
|
|
415
|
+
fn = <<~JAVASCRIPT
|
|
416
|
+
(element, expression) => {
|
|
417
|
+
const document = element.ownerDocument || element;
|
|
418
|
+
const iterator = document.evaluate(expression, element, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
|
|
419
|
+
const array = [];
|
|
420
|
+
let item;
|
|
421
|
+
while ((item = iterator.iterateNext()))
|
|
422
|
+
array.push(item);
|
|
423
|
+
return array;
|
|
424
|
+
}
|
|
425
|
+
JAVASCRIPT
|
|
426
|
+
handles = evaluate_handle(fn, expression)
|
|
427
|
+
properties = handles.properties
|
|
428
|
+
handles.dispose
|
|
429
|
+
properties.values.map(&:as_element).compact
|
|
430
|
+
end
|
|
449
431
|
|
|
450
432
|
# /**
|
|
451
433
|
# * @returns {!Promise<boolean>}
|
|
@@ -122,7 +122,7 @@ class Puppeteer::ExecutionContext
|
|
|
122
122
|
remote_object = Puppeteer::RemoteObject.new(result['result'])
|
|
123
123
|
|
|
124
124
|
if exception_details
|
|
125
|
-
raise EvaluationError.new("Evaluation failed: #{
|
|
125
|
+
raise EvaluationError.new("Evaluation failed: #{exception_details}")
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
if @return_by_value
|
|
@@ -216,20 +216,26 @@ class Puppeteer::ExecutionContext
|
|
|
216
216
|
# return createJSHandle(this, response.objects);
|
|
217
217
|
# }
|
|
218
218
|
|
|
219
|
-
#
|
|
220
|
-
#
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
219
|
+
# @param element_handle [Puppeteer::ElementHandle]
|
|
220
|
+
# @return [Puppeteer::ElementHandle]
|
|
221
|
+
def adopt_element_handle(element_handle)
|
|
222
|
+
if element_handle.execution_context == self
|
|
223
|
+
raise ArgumentError.new('Cannot adopt handle that already belongs to this execution context')
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
unless @world
|
|
227
|
+
raise 'Cannot adopt handle without DOMWorld'
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
node_info = element_handle.remote_object.node_info(@client)
|
|
231
|
+
response = @client.send_message('DOM.resolveNode',
|
|
232
|
+
backendNodeId: node_info["node"]["backendNodeId"],
|
|
233
|
+
executionContextId: @context_id,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
Puppeteer::JSHandle.create(
|
|
237
|
+
context: self,
|
|
238
|
+
remote_object: Puppeteer::RemoteObject.new(response["object"]),
|
|
239
|
+
)
|
|
240
|
+
end
|
|
235
241
|
end
|