puppeteer-ruby 0.0.10
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 +7 -0
- data/.circleci/config.yml +71 -0
- data/.github/stale.yml +16 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.rubocop.yml +302 -0
- data/.travis.yml +7 -0
- data/Dockerfile +6 -0
- data/Gemfile +6 -0
- data/README.md +54 -0
- data/Rakefile +1 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/docker-compose.yml +15 -0
- data/docs/Puppeteer.html +2020 -0
- data/docs/Puppeteer/AsyncAwaitBehavior.html +105 -0
- data/docs/Puppeteer/Browser.html +2148 -0
- data/docs/Puppeteer/BrowserContext.html +809 -0
- data/docs/Puppeteer/BrowserFetcher.html +214 -0
- data/docs/Puppeteer/BrowserRunner.html +914 -0
- data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +477 -0
- data/docs/Puppeteer/CDPSession.html +813 -0
- data/docs/Puppeteer/CDPSession/Error.html +124 -0
- data/docs/Puppeteer/ConcurrentRubyUtils.html +430 -0
- data/docs/Puppeteer/Connection.html +960 -0
- data/docs/Puppeteer/Connection/MessageCallback.html +434 -0
- data/docs/Puppeteer/Connection/ProtocolError.html +216 -0
- data/docs/Puppeteer/Connection/RequestDebugPrinter.html +217 -0
- data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +244 -0
- data/docs/Puppeteer/ConsoleMessage.html +565 -0
- data/docs/Puppeteer/ConsoleMessage/Location.html +433 -0
- data/docs/Puppeteer/DOMWorld.html +2219 -0
- data/docs/Puppeteer/DOMWorld/DetachedError.html +124 -0
- data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +124 -0
- data/docs/Puppeteer/DebugPrint.html +233 -0
- data/docs/Puppeteer/Device.html +470 -0
- data/docs/Puppeteer/Devices.html +139 -0
- data/docs/Puppeteer/ElementHandle.html +2542 -0
- data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +206 -0
- data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +206 -0
- data/docs/Puppeteer/ElementHandle/Point.html +492 -0
- data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +124 -0
- data/docs/Puppeteer/EmulationManager.html +454 -0
- data/docs/Puppeteer/EventCallbackable.html +433 -0
- data/docs/Puppeteer/EventCallbackable/EventListeners.html +435 -0
- data/docs/Puppeteer/ExecutionContext.html +998 -0
- data/docs/Puppeteer/ExecutionContext/EvaluationError.html +124 -0
- data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +357 -0
- data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +389 -0
- data/docs/Puppeteer/FileChooser.html +455 -0
- data/docs/Puppeteer/Frame.html +3677 -0
- data/docs/Puppeteer/FrameManager.html +2410 -0
- data/docs/Puppeteer/FrameManager/NavigationError.html +124 -0
- data/docs/Puppeteer/IfPresent.html +222 -0
- data/docs/Puppeteer/JSHandle.html +1352 -0
- data/docs/Puppeteer/Keyboard.html +1557 -0
- data/docs/Puppeteer/Keyboard/KeyDefinition.html +831 -0
- data/docs/Puppeteer/Keyboard/KeyDescription.html +603 -0
- data/docs/Puppeteer/Launcher.html +237 -0
- data/docs/Puppeteer/Launcher/Base.html +385 -0
- data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +124 -0
- data/docs/Puppeteer/Launcher/BrowserOptions.html +441 -0
- data/docs/Puppeteer/Launcher/Chrome.html +669 -0
- data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +382 -0
- data/docs/Puppeteer/Launcher/ChromeArgOptions.html +531 -0
- data/docs/Puppeteer/Launcher/LaunchOptions.html +893 -0
- data/docs/Puppeteer/LifecycleWatcher.html +834 -0
- data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +363 -0
- data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +206 -0
- data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +124 -0
- data/docs/Puppeteer/Mouse.html +1105 -0
- data/docs/Puppeteer/Mouse/Button.html +136 -0
- data/docs/Puppeteer/NetworkManager.html +901 -0
- data/docs/Puppeteer/NetworkManager/Credentials.html +385 -0
- data/docs/Puppeteer/Page.html +5970 -0
- data/docs/Puppeteer/Page/FileChooserTimeoutError.html +206 -0
- data/docs/Puppeteer/Page/ScreenshotOptions.html +845 -0
- data/docs/Puppeteer/Page/ScriptTag.html +555 -0
- data/docs/Puppeteer/Page/StyleTag.html +448 -0
- data/docs/Puppeteer/Page/TargetCrashedError.html +124 -0
- data/docs/Puppeteer/RemoteObject.html +1087 -0
- data/docs/Puppeteer/Target.html +1336 -0
- data/docs/Puppeteer/Target/InitializeFailure.html +124 -0
- data/docs/Puppeteer/Target/TargetInfo.html +729 -0
- data/docs/Puppeteer/TimeoutError.html +135 -0
- data/docs/Puppeteer/TimeoutSettings.html +496 -0
- data/docs/Puppeteer/TouchScreen.html +464 -0
- data/docs/Puppeteer/Viewport.html +837 -0
- data/docs/Puppeteer/WaitTask.html +637 -0
- data/docs/Puppeteer/WaitTask/TerminatedError.html +124 -0
- data/docs/Puppeteer/WaitTask/TimeoutError.html +206 -0
- data/docs/Puppeteer/WebSocket.html +673 -0
- data/docs/Puppeteer/WebSocket/DriverImpl.html +412 -0
- data/docs/Puppeteer/WebSocketTransport.html +600 -0
- data/docs/Puppeteer/WebSocktTransportError.html +124 -0
- data/docs/_index.html +823 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +496 -0
- data/docs/file.README.html +123 -0
- data/docs/file_list.html +56 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +123 -0
- data/docs/js/app.js +314 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +4075 -0
- data/docs/top-level-namespace.html +126 -0
- data/lib/puppeteer.rb +200 -0
- data/lib/puppeteer/async_await_behavior.rb +38 -0
- data/lib/puppeteer/browser.rb +259 -0
- data/lib/puppeteer/browser_context.rb +90 -0
- data/lib/puppeteer/browser_fetcher.rb +6 -0
- data/lib/puppeteer/browser_runner.rb +161 -0
- data/lib/puppeteer/cdp_session.rb +100 -0
- data/lib/puppeteer/concurrent_ruby_utils.rb +37 -0
- data/lib/puppeteer/connection.rb +254 -0
- data/lib/puppeteer/console_message.rb +24 -0
- data/lib/puppeteer/debug_print.rb +20 -0
- data/lib/puppeteer/device.rb +12 -0
- data/lib/puppeteer/devices.rb +885 -0
- data/lib/puppeteer/dom_world.rb +484 -0
- data/lib/puppeteer/element_handle.rb +433 -0
- data/lib/puppeteer/element_handle/bounding_box.rb +12 -0
- data/lib/puppeteer/element_handle/box_model.rb +19 -0
- data/lib/puppeteer/element_handle/point.rb +26 -0
- data/lib/puppeteer/emulation_manager.rb +46 -0
- data/lib/puppeteer/errors.rb +2 -0
- data/lib/puppeteer/event_callbackable.rb +88 -0
- data/lib/puppeteer/execution_context.rb +254 -0
- data/lib/puppeteer/file_chooser.rb +29 -0
- data/lib/puppeteer/frame.rb +286 -0
- data/lib/puppeteer/frame_manager.rb +378 -0
- data/lib/puppeteer/if_present.rb +18 -0
- data/lib/puppeteer/js_handle.rb +142 -0
- data/lib/puppeteer/keyboard.rb +183 -0
- data/lib/puppeteer/keyboard/key_description.rb +19 -0
- data/lib/puppeteer/keyboard/us_keyboard_layout.rb +283 -0
- data/lib/puppeteer/launcher.rb +25 -0
- data/lib/puppeteer/launcher/base.rb +48 -0
- data/lib/puppeteer/launcher/browser_options.rb +41 -0
- data/lib/puppeteer/launcher/chrome.rb +211 -0
- data/lib/puppeteer/launcher/chrome_arg_options.rb +49 -0
- data/lib/puppeteer/launcher/launch_options.rb +68 -0
- data/lib/puppeteer/lifecycle_watcher.rb +171 -0
- data/lib/puppeteer/mouse.rb +123 -0
- data/lib/puppeteer/network_manager.rb +122 -0
- data/lib/puppeteer/page.rb +1065 -0
- data/lib/puppeteer/page/screenshot_options.rb +78 -0
- data/lib/puppeteer/remote_object.rb +143 -0
- data/lib/puppeteer/target.rb +150 -0
- data/lib/puppeteer/timeout_settings.rb +15 -0
- data/lib/puppeteer/touch_screen.rb +43 -0
- data/lib/puppeteer/version.rb +3 -0
- data/lib/puppeteer/viewport.rb +54 -0
- data/lib/puppeteer/wait_task.rb +188 -0
- data/lib/puppeteer/web_socket.rb +122 -0
- data/lib/puppeteer/web_socket_transport.rb +49 -0
- data/puppeteer-ruby.gemspec +32 -0
- metadata +355 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
require 'thread'
|
|
2
|
+
|
|
3
|
+
# https://github.com/puppeteer/puppeteer/blob/master/src/DOMWorld.js
|
|
4
|
+
class Puppeteer::DOMWorld
|
|
5
|
+
using Puppeteer::AsyncAwaitBehavior
|
|
6
|
+
|
|
7
|
+
# @param {!Puppeteer.FrameManager} frameManager
|
|
8
|
+
# @param {!Puppeteer.Frame} frame
|
|
9
|
+
# @param {!Puppeteer.TimeoutSettings} timeoutSettings
|
|
10
|
+
def initialize(frame_manager, frame, timeout_settings)
|
|
11
|
+
@frame_manager = frame_manager
|
|
12
|
+
@frame = frame
|
|
13
|
+
@timeout_settings = timeout_settings
|
|
14
|
+
@context_promise = resolvable_future
|
|
15
|
+
@pending_destroy = []
|
|
16
|
+
@wait_tasks = Set.new
|
|
17
|
+
@detached = false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
attr_reader :frame
|
|
21
|
+
|
|
22
|
+
# only used in Puppeteer::WaitTask#initialize
|
|
23
|
+
def _wait_tasks
|
|
24
|
+
@wait_tasks
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param {?Puppeteer.ExecutionContext} context
|
|
28
|
+
def context=(context)
|
|
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"}
|
|
30
|
+
# D, [2020-04-12T22:45:03.938856 #46154] DEBUG -- : RECV << {"method"=>"Runtime.executionContextCreated", "params"=>{"context"=>{"id"=>4, "origin"=>"://", "name"=>"__puppeteer_utility_world__", "auxData"=>{"isDefault"=>false, "type"=>"isolated", "frameId"=>"3AD7F1E82BCBA88BFE31D03BC49FF6CB"}}}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
|
|
31
|
+
# D, [2020-04-12T22:45:03.938960 #46154] DEBUG -- : RECV << {"method"=>"Runtime.executionContextDestroyed", "params"=>{"executionContextId"=>1}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
|
|
32
|
+
# D, [2020-04-12T22:45:03.939110 #46154] DEBUG -- : RECV << {"method"=>"Page.frameNavigated", "params"=>{"frame"=>{"id"=>"3AD7F1E82BCBA88BFE31D03BC49FF6CB", "loaderId"=>"301B349884E582986C502CBE020966DF", "url"=>"https://github.com/", "securityOrigin"=>"https://github.com", "mimeType"=>"text/html"}}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
|
|
33
|
+
# D, [2020-04-12T22:45:03.939793 #46154] DEBUG -- : RECV << {"method"=>"Runtime.executionContextDestroyed", "params"=>{"executionContextId"=>2}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
|
|
34
|
+
# executionContextDestroyed is often notified after executionContextCreated.
|
|
35
|
+
|
|
36
|
+
if context
|
|
37
|
+
if @context_promise.fulfilled?
|
|
38
|
+
@pending_destroy << context._context_id
|
|
39
|
+
@document = nil
|
|
40
|
+
@context_promise = resolvable_future
|
|
41
|
+
end
|
|
42
|
+
@context_promise.fulfill(context)
|
|
43
|
+
@wait_tasks.each(&:async_rerun)
|
|
44
|
+
else
|
|
45
|
+
raise ArgumentError.new("context should now be nil. Use #delete_context for clearing document.")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def delete_context(execution_context_id)
|
|
50
|
+
if @pending_destroy.include?(execution_context_id)
|
|
51
|
+
@pending_destroy.delete(execution_context_id)
|
|
52
|
+
else
|
|
53
|
+
@document = nil
|
|
54
|
+
@context_promise = resolvable_future
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def has_context?
|
|
59
|
+
@context_promise.resolved?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def detach
|
|
63
|
+
@detached = true
|
|
64
|
+
@wait_tasks.each do |wait_task|
|
|
65
|
+
wait_task.terminate(Puppeteer::WaitTask::TerminatedError.new('waitForFunction failed: frame got detached.'))
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
class DetachedError < StandardError; end
|
|
70
|
+
|
|
71
|
+
# @return {!Promise<!Puppeteer.ExecutionContext>}
|
|
72
|
+
def execution_context
|
|
73
|
+
if @detached
|
|
74
|
+
raise DetachedError.new("Execution Context is not available in detached frame \"#{@frame.url}\" (are you trying to evaluate?)")
|
|
75
|
+
end
|
|
76
|
+
@context_promise.value!
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @param {Function|string} pageFunction
|
|
80
|
+
# @param {!Array<*>} args
|
|
81
|
+
# @return {!Promise<!Puppeteer.JSHandle>}
|
|
82
|
+
def evaluate_handle(page_function, *args)
|
|
83
|
+
execution_context.evaluate_handle(page_function, *args)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @param {Function|string} pageFunction
|
|
87
|
+
# @param {!Array<*>} args
|
|
88
|
+
# @return {!Promise<*>}
|
|
89
|
+
def evaluate(page_function, *args)
|
|
90
|
+
execution_context.evaluate(page_function, *args)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# `$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
|
94
|
+
# @param {string} selector
|
|
95
|
+
# @return {!Promise<?Puppeteer.ElementHandle>}
|
|
96
|
+
def S(selector)
|
|
97
|
+
document.S(selector)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class DocumentEvaluationError < StandardError; end
|
|
101
|
+
|
|
102
|
+
private def evaluate_document
|
|
103
|
+
# sometimes execution_context.evaluate_handle('document') returns null object.
|
|
104
|
+
# D, [2020-04-24T02:17:51.023631 #220] DEBUG -- : RECV << {"id"=>20, "result"=>{"result"=>{"type"=>"object", "subtype"=>"null", "value"=>nil}}, "sessionId"=>"78E9CF1E14D81294E320E7C20E5CDE06"}
|
|
105
|
+
# retry if so.
|
|
106
|
+
5.times do
|
|
107
|
+
handle = execution_context.evaluate_handle('document')
|
|
108
|
+
return handle if handle.is_a?(Puppeteer::ElementHandle)
|
|
109
|
+
end
|
|
110
|
+
raise DocumentEvaluationError.new("'document' object cannot be evaluated as an Element")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
private def document
|
|
114
|
+
@document ||= evaluate_document.as_element
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
|
118
|
+
# @param {string} expression
|
|
119
|
+
# @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
|
120
|
+
def Sx(expression)
|
|
121
|
+
document.Sx(expression)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
|
125
|
+
# @param {string} selector
|
|
126
|
+
# @param {Function|string} pageFunction
|
|
127
|
+
# @param {!Array<*>} args
|
|
128
|
+
# @return {!Promise<(!Object|undefined)>}
|
|
129
|
+
def Seval(selector, page_function, *args)
|
|
130
|
+
document.Seval(selector, page_function, *args)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
|
134
|
+
# @param {string} selector
|
|
135
|
+
# @param {Function|string} pageFunction
|
|
136
|
+
# @param {!Array<*>} args
|
|
137
|
+
# @return {!Promise<(!Object|undefined)>}
|
|
138
|
+
def SSeval(selector, page_function, *args)
|
|
139
|
+
document.SSeval(selector, page_function, *args)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# `$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
|
|
143
|
+
# @param {string} selector
|
|
144
|
+
# @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
|
145
|
+
def SS(selector)
|
|
146
|
+
document.SS(selector)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# /**
|
|
150
|
+
# * @return {!Promise<String>}
|
|
151
|
+
# */
|
|
152
|
+
# async content() {
|
|
153
|
+
# return await this.evaluate(() => {
|
|
154
|
+
# let retVal = '';
|
|
155
|
+
# if (document.doctype)
|
|
156
|
+
# retVal = new XMLSerializer().serializeToString(document.doctype);
|
|
157
|
+
# if (document.documentElement)
|
|
158
|
+
# retVal += document.documentElement.outerHTML;
|
|
159
|
+
# return retVal;
|
|
160
|
+
# });
|
|
161
|
+
# }
|
|
162
|
+
|
|
163
|
+
# /**
|
|
164
|
+
# * @param {string} html
|
|
165
|
+
# * @param {!{timeout?: number, waitUntil?: string|!Array<string>}=} options
|
|
166
|
+
# */
|
|
167
|
+
# async setContent(html, options = {}) {
|
|
168
|
+
# const {
|
|
169
|
+
# waitUntil = ['load'],
|
|
170
|
+
# timeout = this._timeoutSettings.navigationTimeout(),
|
|
171
|
+
# } = options;
|
|
172
|
+
# // We rely upon the fact that document.open() will reset frame lifecycle with "init"
|
|
173
|
+
# // lifecycle event. @see https://crrev.com/608658
|
|
174
|
+
# await this.evaluate(html => {
|
|
175
|
+
# document.open();
|
|
176
|
+
# document.write(html);
|
|
177
|
+
# document.close();
|
|
178
|
+
# }, html);
|
|
179
|
+
# const watcher = new LifecycleWatcher(this._frameManager, this._frame, waitUntil, timeout);
|
|
180
|
+
# const error = await Promise.race([
|
|
181
|
+
# watcher.timeoutOrTerminationPromise(),
|
|
182
|
+
# watcher.lifecyclePromise(),
|
|
183
|
+
# ]);
|
|
184
|
+
# watcher.dispose();
|
|
185
|
+
# if (error)
|
|
186
|
+
# throw error;
|
|
187
|
+
# }
|
|
188
|
+
|
|
189
|
+
# /**
|
|
190
|
+
# * @param {!{url?: string, path?: string, content?: string, type?: string}} options
|
|
191
|
+
# * @return {!Promise<!Puppeteer.ElementHandle>}
|
|
192
|
+
# */
|
|
193
|
+
# async addScriptTag(options) {
|
|
194
|
+
# const {
|
|
195
|
+
# url = null,
|
|
196
|
+
# path = null,
|
|
197
|
+
# content = null,
|
|
198
|
+
# type = ''
|
|
199
|
+
# } = options;
|
|
200
|
+
# if (url !== null) {
|
|
201
|
+
# try {
|
|
202
|
+
# const context = await this.executionContext();
|
|
203
|
+
# return (await context.evaluateHandle(addScriptUrl, url, type)).asElement();
|
|
204
|
+
# } catch (error) {
|
|
205
|
+
# throw new Error(`Loading script from ${url} failed`);
|
|
206
|
+
# }
|
|
207
|
+
# }
|
|
208
|
+
|
|
209
|
+
# if (path !== null) {
|
|
210
|
+
# let contents = await readFileAsync(path, 'utf8');
|
|
211
|
+
# contents += '//# sourceURL=' + path.replace(/\n/g, '');
|
|
212
|
+
# const context = await this.executionContext();
|
|
213
|
+
# return (await context.evaluateHandle(addScriptContent, contents, type)).asElement();
|
|
214
|
+
# }
|
|
215
|
+
|
|
216
|
+
# if (content !== null) {
|
|
217
|
+
# const context = await this.executionContext();
|
|
218
|
+
# return (await context.evaluateHandle(addScriptContent, content, type)).asElement();
|
|
219
|
+
# }
|
|
220
|
+
|
|
221
|
+
# throw new Error('Provide an object with a `url`, `path` or `content` property');
|
|
222
|
+
|
|
223
|
+
# /**
|
|
224
|
+
# * @param {string} url
|
|
225
|
+
# * @param {string} type
|
|
226
|
+
# * @return {!Promise<!HTMLElement>}
|
|
227
|
+
# */
|
|
228
|
+
# async function addScriptUrl(url, type) {
|
|
229
|
+
# const script = document.createElement('script');
|
|
230
|
+
# script.src = url;
|
|
231
|
+
# if (type)
|
|
232
|
+
# script.type = type;
|
|
233
|
+
# const promise = new Promise((res, rej) => {
|
|
234
|
+
# script.onload = res;
|
|
235
|
+
# script.onerror = rej;
|
|
236
|
+
# });
|
|
237
|
+
# document.head.appendChild(script);
|
|
238
|
+
# await promise;
|
|
239
|
+
# return script;
|
|
240
|
+
# }
|
|
241
|
+
|
|
242
|
+
# /**
|
|
243
|
+
# * @param {string} content
|
|
244
|
+
# * @param {string} type
|
|
245
|
+
# * @return {!HTMLElement}
|
|
246
|
+
# */
|
|
247
|
+
# function addScriptContent(content, type = 'text/javascript') {
|
|
248
|
+
# const script = document.createElement('script');
|
|
249
|
+
# script.type = type;
|
|
250
|
+
# script.text = content;
|
|
251
|
+
# let error = null;
|
|
252
|
+
# script.onerror = e => error = e;
|
|
253
|
+
# document.head.appendChild(script);
|
|
254
|
+
# if (error)
|
|
255
|
+
# throw error;
|
|
256
|
+
# return script;
|
|
257
|
+
# }
|
|
258
|
+
# }
|
|
259
|
+
|
|
260
|
+
# /**
|
|
261
|
+
# * @param {!{url?: string, path?: string, content?: string}} options
|
|
262
|
+
# * @return {!Promise<!Puppeteer.ElementHandle>}
|
|
263
|
+
# */
|
|
264
|
+
# async addStyleTag(options) {
|
|
265
|
+
# const {
|
|
266
|
+
# url = null,
|
|
267
|
+
# path = null,
|
|
268
|
+
# content = null
|
|
269
|
+
# } = options;
|
|
270
|
+
# if (url !== null) {
|
|
271
|
+
# try {
|
|
272
|
+
# const context = await this.executionContext();
|
|
273
|
+
# return (await context.evaluateHandle(addStyleUrl, url)).asElement();
|
|
274
|
+
# } catch (error) {
|
|
275
|
+
# throw new Error(`Loading style from ${url} failed`);
|
|
276
|
+
# }
|
|
277
|
+
# }
|
|
278
|
+
|
|
279
|
+
# if (path !== null) {
|
|
280
|
+
# let contents = await readFileAsync(path, 'utf8');
|
|
281
|
+
# contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';
|
|
282
|
+
# const context = await this.executionContext();
|
|
283
|
+
# return (await context.evaluateHandle(addStyleContent, contents)).asElement();
|
|
284
|
+
# }
|
|
285
|
+
|
|
286
|
+
# if (content !== null) {
|
|
287
|
+
# const context = await this.executionContext();
|
|
288
|
+
# return (await context.evaluateHandle(addStyleContent, content)).asElement();
|
|
289
|
+
# }
|
|
290
|
+
|
|
291
|
+
# throw new Error('Provide an object with a `url`, `path` or `content` property');
|
|
292
|
+
|
|
293
|
+
# /**
|
|
294
|
+
# * @param {string} url
|
|
295
|
+
# * @return {!Promise<!HTMLElement>}
|
|
296
|
+
# */
|
|
297
|
+
# async function addStyleUrl(url) {
|
|
298
|
+
# const link = document.createElement('link');
|
|
299
|
+
# link.rel = 'stylesheet';
|
|
300
|
+
# link.href = url;
|
|
301
|
+
# const promise = new Promise((res, rej) => {
|
|
302
|
+
# link.onload = res;
|
|
303
|
+
# link.onerror = rej;
|
|
304
|
+
# });
|
|
305
|
+
# document.head.appendChild(link);
|
|
306
|
+
# await promise;
|
|
307
|
+
# return link;
|
|
308
|
+
# }
|
|
309
|
+
|
|
310
|
+
# /**
|
|
311
|
+
# * @param {string} content
|
|
312
|
+
# * @return {!Promise<!HTMLElement>}
|
|
313
|
+
# */
|
|
314
|
+
# async function addStyleContent(content) {
|
|
315
|
+
# const style = document.createElement('style');
|
|
316
|
+
# style.type = 'text/css';
|
|
317
|
+
# style.appendChild(document.createTextNode(content));
|
|
318
|
+
# const promise = new Promise((res, rej) => {
|
|
319
|
+
# style.onload = res;
|
|
320
|
+
# style.onerror = rej;
|
|
321
|
+
# });
|
|
322
|
+
# document.head.appendChild(style);
|
|
323
|
+
# await promise;
|
|
324
|
+
# return style;
|
|
325
|
+
# }
|
|
326
|
+
# }
|
|
327
|
+
|
|
328
|
+
# @param selector [String]
|
|
329
|
+
# @param delay [Number]
|
|
330
|
+
# @param button [String] "left"|"right"|"middle"
|
|
331
|
+
# @param click_count [Number]
|
|
332
|
+
def click(selector, delay: nil, button: nil, click_count: nil)
|
|
333
|
+
handle = S(selector)
|
|
334
|
+
handle.click(delay: delay, button: button, click_count: click_count)
|
|
335
|
+
handle.dispose
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# /**
|
|
339
|
+
# * @param {string} selector
|
|
340
|
+
# */
|
|
341
|
+
# async focus(selector) {
|
|
342
|
+
# const handle = await this.$(selector);
|
|
343
|
+
# assert(handle, 'No node found for selector: ' + selector);
|
|
344
|
+
# await handle.focus();
|
|
345
|
+
# await handle.dispose();
|
|
346
|
+
# }
|
|
347
|
+
|
|
348
|
+
# /**
|
|
349
|
+
# * @param {string} selector
|
|
350
|
+
# */
|
|
351
|
+
# async hover(selector) {
|
|
352
|
+
# const handle = await this.$(selector);
|
|
353
|
+
# assert(handle, 'No node found for selector: ' + selector);
|
|
354
|
+
# await handle.hover();
|
|
355
|
+
# await handle.dispose();
|
|
356
|
+
# }
|
|
357
|
+
|
|
358
|
+
# @param selector [String]
|
|
359
|
+
# @return [Array<String>]
|
|
360
|
+
def select(selector, *values)
|
|
361
|
+
handle = S(selector)
|
|
362
|
+
result = handle.select(*values)
|
|
363
|
+
handle.dispose
|
|
364
|
+
|
|
365
|
+
result
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# @param selector [String]
|
|
369
|
+
def tap(selector)
|
|
370
|
+
handle = S(selector)
|
|
371
|
+
handle.tap
|
|
372
|
+
handle.dispose
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# @param selector [String]
|
|
376
|
+
# @param text [String]
|
|
377
|
+
# @param delay [Number]
|
|
378
|
+
def type_text(selector, text, delay: nil)
|
|
379
|
+
handle = S(selector)
|
|
380
|
+
handle.type_text(text, delay: delay)
|
|
381
|
+
handle.dispose
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# @param selector [String]
|
|
385
|
+
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
|
386
|
+
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
|
387
|
+
# @param timeout [Integer]
|
|
388
|
+
def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil)
|
|
389
|
+
wait_for_selector_or_xpath(selector, false, visible: visible, hidden: hidden, timeout: timeout)
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# @param xpath [String]
|
|
393
|
+
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
|
394
|
+
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
|
395
|
+
# @param timeout [Integer]
|
|
396
|
+
def wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil)
|
|
397
|
+
wait_for_selector_or_xpath(xpath, true, visible: visible, hidden: hidden, timeout: timeout)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# /**
|
|
401
|
+
# * @param {Function|string} pageFunction
|
|
402
|
+
# * @param {!{polling?: string|number, timeout?: number}=} options
|
|
403
|
+
# * @return {!Promise<!Puppeteer.JSHandle>}
|
|
404
|
+
# */
|
|
405
|
+
# waitForFunction(pageFunction, options = {}, ...args) {
|
|
406
|
+
# const {
|
|
407
|
+
# polling = 'raf',
|
|
408
|
+
# timeout = this._timeoutSettings.timeout(),
|
|
409
|
+
# } = options;
|
|
410
|
+
# return new WaitTask(this, pageFunction, 'function', polling, timeout, ...args).promise;
|
|
411
|
+
# }
|
|
412
|
+
|
|
413
|
+
# /**
|
|
414
|
+
# * @return {!Promise<string>}
|
|
415
|
+
# */
|
|
416
|
+
# async title() {
|
|
417
|
+
# return this.evaluate(() => document.title);
|
|
418
|
+
# }
|
|
419
|
+
|
|
420
|
+
# @param selector_or_xpath [String]
|
|
421
|
+
# @param is_xpath [Boolean]
|
|
422
|
+
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
|
423
|
+
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
|
424
|
+
# @param timeout [Integer]
|
|
425
|
+
private def wait_for_selector_or_xpath(selector_or_xpath, is_xpath, visible: nil, hidden: nil, timeout: nil)
|
|
426
|
+
option_wait_for_visible = visible || false
|
|
427
|
+
option_wait_for_hidden = hidden || false
|
|
428
|
+
option_timeout = timeout || @timeout_settings.timeout
|
|
429
|
+
|
|
430
|
+
polling =
|
|
431
|
+
if option_wait_for_visible || option_wait_for_hidden
|
|
432
|
+
'raf'
|
|
433
|
+
else
|
|
434
|
+
'mutation'
|
|
435
|
+
end
|
|
436
|
+
title = "#{is_xpath ? :XPath : :selector} #{selector_or_xpath}#{option_wait_for_hidden ? 'to be hidden' : ''}"
|
|
437
|
+
|
|
438
|
+
wait_task = Puppeteer::WaitTask.new(
|
|
439
|
+
dom_world: self,
|
|
440
|
+
predicate_body: "return (#{PREDICATE})(...args)",
|
|
441
|
+
title: title,
|
|
442
|
+
polling: polling,
|
|
443
|
+
timeout: option_timeout,
|
|
444
|
+
args: [selector_or_xpath, is_xpath, option_wait_for_visible, option_wait_for_hidden],
|
|
445
|
+
)
|
|
446
|
+
handle = wait_task.await_promise
|
|
447
|
+
unless handle.as_element
|
|
448
|
+
handle.dispose
|
|
449
|
+
return nil
|
|
450
|
+
end
|
|
451
|
+
handle.as_element
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
PREDICATE = <<~JAVASCRIPT
|
|
455
|
+
/**
|
|
456
|
+
* @param {string} selectorOrXPath
|
|
457
|
+
* @param {boolean} isXPath
|
|
458
|
+
* @param {boolean} waitForVisible
|
|
459
|
+
* @param {boolean} waitForHidden
|
|
460
|
+
* @return {?Node|boolean}
|
|
461
|
+
*/
|
|
462
|
+
function _(selectorOrXPath, isXPath, waitForVisible, waitForHidden) {
|
|
463
|
+
const node = isXPath
|
|
464
|
+
? document.evaluate(selectorOrXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
|
|
465
|
+
: document.querySelector(selectorOrXPath);
|
|
466
|
+
if (!node)
|
|
467
|
+
return waitForHidden;
|
|
468
|
+
if (!waitForVisible && !waitForHidden)
|
|
469
|
+
return node;
|
|
470
|
+
const element = /** @type {Element} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node);
|
|
471
|
+
const style = window.getComputedStyle(element);
|
|
472
|
+
const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
|
|
473
|
+
const success = (waitForVisible === isVisible || waitForHidden === !isVisible);
|
|
474
|
+
return success ? node : null;
|
|
475
|
+
/**
|
|
476
|
+
* @return {boolean}
|
|
477
|
+
*/
|
|
478
|
+
function hasVisibleBoundingBox() {
|
|
479
|
+
const rect = element.getBoundingClientRect();
|
|
480
|
+
return !!(rect.top || rect.bottom || rect.width || rect.height);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
JAVASCRIPT
|
|
484
|
+
end
|