puppeteer-ruby 0.0.6 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/docs/Puppeteer.html +53 -43
  4. data/docs/Puppeteer/AsyncAwaitBehavior.html +1 -1
  5. data/docs/Puppeteer/Browser.html +1 -1
  6. data/docs/Puppeteer/BrowserContext.html +1 -1
  7. data/docs/Puppeteer/BrowserFetcher.html +1 -1
  8. data/docs/Puppeteer/BrowserRunner.html +1 -1
  9. data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +1 -1
  10. data/docs/Puppeteer/CDPSession.html +1 -1
  11. data/docs/Puppeteer/CDPSession/Error.html +1 -1
  12. data/docs/Puppeteer/ConcurrentRubyUtils.html +1 -1
  13. data/docs/Puppeteer/Connection.html +1 -1
  14. data/docs/Puppeteer/Connection/MessageCallback.html +1 -1
  15. data/docs/Puppeteer/Connection/ProtocolError.html +1 -1
  16. data/docs/Puppeteer/Connection/RequestDebugPrinter.html +1 -1
  17. data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +1 -1
  18. data/docs/Puppeteer/ConsoleMessage.html +1 -1
  19. data/docs/Puppeteer/ConsoleMessage/Location.html +1 -1
  20. data/docs/Puppeteer/DOMWorld.html +116 -19
  21. data/docs/Puppeteer/DOMWorld/DetachedError.html +1 -1
  22. data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +1 -1
  23. data/docs/Puppeteer/DebugPrint.html +1 -1
  24. data/docs/Puppeteer/Device.html +1 -1
  25. data/docs/Puppeteer/Devices.html +1 -1
  26. data/docs/Puppeteer/ElementHandle.html +565 -141
  27. data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +5 -5
  28. data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +5 -5
  29. data/docs/Puppeteer/ElementHandle/Point.html +21 -21
  30. data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +1 -1
  31. data/docs/Puppeteer/EmulationManager.html +1 -1
  32. data/docs/Puppeteer/EventCallbackable.html +1 -1
  33. data/docs/Puppeteer/EventCallbackable/EventListeners.html +1 -1
  34. data/docs/Puppeteer/ExecutionContext.html +114 -11
  35. data/docs/Puppeteer/ExecutionContext/EvaluationError.html +1 -1
  36. data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +1 -1
  37. data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +1 -1
  38. data/docs/Puppeteer/FileChooser.html +455 -0
  39. data/docs/Puppeteer/Frame.html +1 -1
  40. data/docs/Puppeteer/FrameManager.html +1 -1
  41. data/docs/Puppeteer/FrameManager/NavigationError.html +1 -1
  42. data/docs/Puppeteer/IfPresent.html +1 -1
  43. data/docs/Puppeteer/JSHandle.html +1 -1
  44. data/docs/Puppeteer/Keyboard.html +1 -1
  45. data/docs/Puppeteer/Keyboard/KeyDefinition.html +1 -1
  46. data/docs/Puppeteer/Keyboard/KeyDescription.html +1 -1
  47. data/docs/Puppeteer/Launcher.html +1 -1
  48. data/docs/Puppeteer/Launcher/Base.html +1 -1
  49. data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +1 -1
  50. data/docs/Puppeteer/Launcher/BrowserOptions.html +1 -1
  51. data/docs/Puppeteer/Launcher/Chrome.html +64 -23
  52. data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +1 -1
  53. data/docs/Puppeteer/Launcher/ChromeArgOptions.html +1 -1
  54. data/docs/Puppeteer/Launcher/LaunchOptions.html +1 -1
  55. data/docs/Puppeteer/LifecycleWatcher.html +1 -1
  56. data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +1 -1
  57. data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +1 -1
  58. data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +1 -1
  59. data/docs/Puppeteer/Mouse.html +1 -1
  60. data/docs/Puppeteer/Mouse/Button.html +1 -1
  61. data/docs/Puppeteer/NetworkManager.html +1 -1
  62. data/docs/Puppeteer/NetworkManager/Credentials.html +1 -1
  63. data/docs/Puppeteer/Page.html +841 -349
  64. data/docs/Puppeteer/Page/FileChooserTimeoutError.html +206 -0
  65. data/docs/Puppeteer/Page/ScreenshotOptions.html +1 -1
  66. data/docs/Puppeteer/Page/ScriptTag.html +24 -24
  67. data/docs/Puppeteer/Page/StyleTag.html +19 -19
  68. data/docs/Puppeteer/Page/TargetCrashedError.html +1 -1
  69. data/docs/Puppeteer/RemoteObject.html +68 -3
  70. data/docs/Puppeteer/Target.html +1 -1
  71. data/docs/Puppeteer/Target/InitializeFailure.html +1 -1
  72. data/docs/Puppeteer/Target/TargetInfo.html +1 -1
  73. data/docs/Puppeteer/TimeoutError.html +1 -1
  74. data/docs/Puppeteer/TimeoutSettings.html +1 -1
  75. data/docs/Puppeteer/TouchScreen.html +1 -1
  76. data/docs/Puppeteer/Viewport.html +1 -1
  77. data/docs/Puppeteer/WaitTask.html +1 -1
  78. data/docs/Puppeteer/WaitTask/TerminatedError.html +1 -1
  79. data/docs/Puppeteer/WaitTask/TimeoutError.html +1 -1
  80. data/docs/Puppeteer/WebSocket.html +1 -1
  81. data/docs/Puppeteer/WebSocket/DriverImpl.html +1 -1
  82. data/docs/Puppeteer/WebSocketTransport.html +1 -1
  83. data/docs/Puppeteer/WebSocktTransportError.html +1 -1
  84. data/docs/_index.html +19 -5
  85. data/docs/class_list.html +1 -1
  86. data/docs/file.README.html +5 -3
  87. data/docs/index.html +5 -3
  88. data/docs/method_list.html +644 -508
  89. data/docs/top-level-namespace.html +1 -1
  90. data/lib/puppeteer.rb +7 -1
  91. data/lib/puppeteer/browser_runner.rb +1 -1
  92. data/lib/puppeteer/dom_world.rb +9 -12
  93. data/lib/puppeteer/element_handle.rb +82 -61
  94. data/lib/puppeteer/execution_context.rb +13 -0
  95. data/lib/puppeteer/file_chooser.rb +29 -0
  96. data/lib/puppeteer/frame_manager.rb +0 -2
  97. data/lib/puppeteer/launcher/chrome.rb +48 -2
  98. data/lib/puppeteer/page.rb +85 -52
  99. data/lib/puppeteer/remote_object.rb +6 -1
  100. data/lib/puppeteer/version.rb +1 -1
  101. metadata +5 -2
@@ -116,7 +116,7 @@
116
116
  </div>
117
117
 
118
118
  <div id="footer">
119
- Generated on Mon May 25 23:22:48 2020 by
119
+ Generated on Thu Jun 4 23:54:40 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>
data/lib/puppeteer.rb CHANGED
@@ -25,6 +25,7 @@ require 'puppeteer/devices'
25
25
  require 'puppeteer/dom_world'
26
26
  require 'puppeteer/emulation_manager'
27
27
  require 'puppeteer/execution_context'
28
+ require 'puppeteer/file_chooser'
28
29
  require 'puppeteer/frame'
29
30
  require 'puppeteer/frame_manager'
30
31
  require 'puppeteer/js_handle'
@@ -142,7 +143,12 @@ class Puppeteer
142
143
  default_viewport: default_viewport,
143
144
  slow_mo: slow_mo,
144
145
  }.compact
145
- launcher.connect(options)
146
+ browser = launcher.connect(options)
147
+ if block_given?
148
+ yield(browser)
149
+ else
150
+ browser
151
+ end
146
152
  end
147
153
 
148
154
  # @return {string}
@@ -147,7 +147,7 @@ class Puppeteer::BrowserRunner
147
147
  end
148
148
 
149
149
  private def wait_for_ws_endpoint(browser_process, timeout, preferred_revision)
150
- Timeout.timeout(timeout / 1000) do
150
+ Timeout.timeout(timeout / 1000.0) do
151
151
  loop do
152
152
  line = browser_process.stderr.readline
153
153
  /^DevTools listening on (ws:\/\/.*)$/.match(line) do |m|
@@ -355,18 +355,15 @@ class Puppeteer::DOMWorld
355
355
  # await handle.dispose();
356
356
  # }
357
357
 
358
- # /**
359
- # * @param {string} selector
360
- # * @param {!Array<string>} values
361
- # * @return {!Promise<!Array<string>>}
362
- # */
363
- # async select(selector, ...values) {
364
- # const handle = await this.$(selector);
365
- # assert(handle, 'No node found for selector: ' + selector);
366
- # const result = await handle.select(...values);
367
- # await handle.dispose();
368
- # return result;
369
- # }
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
370
367
 
371
368
  # @param selector [String]
372
369
  def tap(selector)
@@ -1,3 +1,5 @@
1
+ require 'mime/types'
2
+
1
3
  class Puppeteer::ElementHandle < Puppeteer::JSHandle
2
4
  include Puppeteer::IfPresent
3
5
  using Puppeteer::AsyncAwaitBehavior
@@ -155,74 +157,77 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
155
157
  click(delay: delay, button: button, click_count: click_count)
156
158
  end
157
159
 
158
- # /**
159
- # * @param {!Array<string>} values
160
- # * @return {!Promise<!Array<string>>}
161
- # */
162
- # async select(...values) {
163
- # for (const value of values)
164
- # assert(helper.isString(value), 'Values must be strings. Found value "' + value + '" of type "' + (typeof value) + '"');
165
- # return this.evaluate((element, values) => {
166
- # if (element.nodeName.toLowerCase() !== 'select')
167
- # throw new Error('Element is not a <select> element.');
168
-
169
- # const options = Array.from(element.options);
170
- # element.value = undefined;
171
- # for (const option of options) {
172
- # option.selected = values.includes(option.value);
173
- # if (option.selected && !element.multiple)
174
- # break;
175
- # }
176
- # element.dispatchEvent(new Event('input', { bubbles: true }));
177
- # element.dispatchEvent(new Event('change', { bubbles: true }));
178
- # return options.filter(option => option.selected).map(option => option.value);
179
- # }, values);
180
- # }
160
+ # @return [Array<String>]
161
+ def select(*values)
162
+ if nonstring = values.find { |value| !value.is_a?(String) }
163
+ raise ArgumentError.new("Values must be strings. Found value \"#{nonstring}\" of type \"#{nonstring.class}\"")
164
+ end
181
165
 
182
- # /**
183
- # * @param {!Array<string>} filePaths
184
- # */
185
- # async uploadFile(...filePaths) {
186
- # const isMultiple = await this.evaluate(element => element.multiple);
187
- # assert(filePaths.length <= 1 || isMultiple, 'Multiple file uploads only work with <input type=file multiple>');
188
- # // These imports are only needed for `uploadFile`, so keep them
189
- # // scoped here to avoid paying the cost unnecessarily.
190
- # const path = require('path');
191
- # const mime = require('mime-types');
192
- # const fs = require('fs');
193
- # const readFileAsync = helper.promisify(fs.readFile);
194
-
195
- # const promises = filePaths.map(filePath => readFileAsync(filePath));
196
- # const files = [];
197
- # for (let i = 0; i < filePaths.length; i++) {
198
- # const buffer = await promises[i];
199
- # const filePath = path.basename(filePaths[i]);
200
- # const file = {
201
- # name: filePath,
202
- # content: buffer.toString('base64'),
203
- # mimeType: mime.lookup(filePath),
204
- # };
205
- # files.push(file);
206
- # }
207
- # await this.evaluateHandle(async(element, files) => {
208
- # const dt = new DataTransfer();
209
- # for (const item of files) {
210
- # const response = await fetch(`data:${item.mimeType};base64,${item.content}`);
211
- # const file = new File([await response.blob()], item.name);
212
- # dt.items.add(file);
213
- # }
214
- # element.files = dt.files;
215
- # element.dispatchEvent(new Event('input', { bubbles: true }));
216
- # element.dispatchEvent(new Event('change', { bubbles: true }));
217
- # }, files);
218
- # }
166
+ fn = <<~JAVASCRIPT
167
+ (element, values) => {
168
+ if (element.nodeName.toLowerCase() !== 'select') {
169
+ throw new Error('Element is not a <select> element.');
170
+ }
171
+
172
+ const options = Array.from(element.options);
173
+ element.value = undefined;
174
+ for (const option of options) {
175
+ option.selected = values.includes(option.value);
176
+ if (option.selected && !element.multiple) {
177
+ break;
178
+ }
179
+ }
180
+ element.dispatchEvent(new Event('input', { bubbles: true }));
181
+ element.dispatchEvent(new Event('change', { bubbles: true }));
182
+ return options.filter(option => option.selected).map(option => option.value);
183
+ }
184
+ JAVASCRIPT
185
+ evaluate(fn, values)
186
+ end
187
+
188
+ # @param file_paths [Array<String>]
189
+ def upload_file(*file_paths)
190
+ is_multiple = evaluate("el => el.multiple")
191
+ if !is_multiple && file_paths.length >= 2
192
+ raise ArgumentError.new('Multiple file uploads only work with <input type=file multiple>')
193
+ end
194
+
195
+ if error_path = file_paths.find { |file_path| !File.exist?(file_path) }
196
+ raise ArgmentError.new("#{error_path} does not exist or is not readable")
197
+ end
198
+
199
+ backend_node_id = @remote_object.node_info(@client)["node"]["backendNodeId"]
200
+
201
+ # The zero-length array is a special case, it seems that DOM.setFileInputFiles does
202
+ # not actually update the files in that case, so the solution is to eval the element
203
+ # value to a new FileList directly.
204
+ if file_paths.empty?
205
+ fn = <<~JAVASCRIPT
206
+ (element) => {
207
+ element.files = new DataTransfer().files;
208
+
209
+ // Dispatch events for this case because it should behave akin to a user action.
210
+ element.dispatchEvent(new Event('input', { bubbles: true }));
211
+ element.dispatchEvent(new Event('change', { bubbles: true }));
212
+ }
213
+ JAVASCRIPT
214
+ await this.evaluate(fn)
215
+ else
216
+ @remote_object.set_file_input_files(@client, file_paths, backend_node_id)
217
+ end
218
+ end
219
+
220
+ def tap(&block)
221
+ return super(&block) if block
219
222
 
220
- def tap
221
223
  scroll_into_view_if_needed
222
224
  point = clickable_point
223
225
  @page.touchscreen.tap(point.x, point.y)
224
226
  end
225
227
 
228
+ async def async_tap
229
+ tap
230
+ end
226
231
 
227
232
  def focus
228
233
  evaluate('element => element.focus()')
@@ -393,6 +398,14 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
393
398
  result
394
399
  end
395
400
 
401
+ # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
402
+ # @param selector [String]
403
+ # @param page_function [String]
404
+ # @return [Object]
405
+ async def async_Seval(selector, page_function, *args)
406
+ Seval(selector, page_function, *args)
407
+ end
408
+
396
409
  # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
397
410
  # @param selector [String]
398
411
  # @param page_function [String]
@@ -408,6 +421,14 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
408
421
  result
409
422
  end
410
423
 
424
+ # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
425
+ # @param selector [String]
426
+ # @param page_function [String]
427
+ # @return [Object]
428
+ async def async_SSeval(selector, page_function, *args)
429
+ SSeval(selector, page_function, *args)
430
+ end
431
+
411
432
  # `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
412
433
  # @param expression [String]
413
434
  # @return [Array<ElementHandle>]
@@ -216,6 +216,19 @@ class Puppeteer::ExecutionContext
216
216
  # return createJSHandle(this, response.objects);
217
217
  # }
218
218
 
219
+ # @param backend_node_id [Integer]
220
+ # @return [Puppeteer::ElementHandle]
221
+ def adopt_backend_node_id(backend_node_id)
222
+ response = @client.send_message('DOM.resolveNode',
223
+ backendNodeId: backend_node_id,
224
+ executionContextId: @context_id,
225
+ )
226
+ Puppeteer::JSHandle.create(
227
+ context: self,
228
+ remote_object: Puppeteer::RemoteObject.new(response["object"]),
229
+ )
230
+ end
231
+
219
232
  # @param element_handle [Puppeteer::ElementHandle]
220
233
  # @return [Puppeteer::ElementHandle]
221
234
  def adopt_element_handle(element_handle)
@@ -0,0 +1,29 @@
1
+ class Puppeteer::FileChooser
2
+ # @param element [Puppeteer::ElementHandle]
3
+ # @param event [Hash]
4
+ def initialize(element, event)
5
+ @element = element
6
+ @multiple = event['mode'] != 'selectSingle'
7
+ @handled = false
8
+ end
9
+
10
+ def multiple?
11
+ @multiple
12
+ end
13
+
14
+ # @param file_paths [Array<String>]
15
+ def accept(file_paths)
16
+ if @handled
17
+ raise 'Cannot accept FileChooser which is already handled!'
18
+ end
19
+ @handled = true
20
+ @element.upload_file(*file_paths)
21
+ end
22
+
23
+ def cancel
24
+ if @handled
25
+ raise 'Cannot cancel FileChooser which is already handled!'
26
+ end
27
+ @handled = true
28
+ end
29
+ end
@@ -285,8 +285,6 @@ class Puppeteer::FrameManager
285
285
  frame.navigated_within_document(url)
286
286
  emit_event 'Events.FrameManager.FrameNavigatedWithinDocument', frame
287
287
  emit_event 'Events.FrameManager.FrameNavigated', frame
288
- handle_frame_manager_frame_navigated_within_document(frame)
289
- handle_frame_manager_frame_navigated(frame)
290
288
  end
291
289
 
292
290
  # @param frame_id [String]
@@ -149,8 +149,54 @@ module Puppeteer::Launcher
149
149
 
150
150
  # @param {!(Launcher.BrowserOptions & {browserWSEndpoint?: string, browserURL?: string, transport?: !Puppeteer.ConnectionTransport})} options
151
151
  # @return {!Promise<!Browser>}
152
- def connect(options)
153
- raise NotImplementedError.new('Puppeteer.connect is not implemented yet')
152
+ def connect(options = {})
153
+ @browser_options = BrowserOptions.new(options)
154
+ browser_ws_endpoint = options[:browser_ws_endpoint]
155
+ browser_url = options[:browser_url]
156
+ transport = options[:transport]
157
+
158
+ connection =
159
+ if browser_ws_endpoint && browser_url.nil? && transport.nil?
160
+ connect_with_browser_ws_endpoint(browser_ws_endpoint)
161
+ elsif browser_ws_endpoint.nil? && browser_url && transport.nil?
162
+ connect_with_browser_url(browser_url)
163
+ elsif browser_ws_endpoint.nil? && browser_url.nil? && transport
164
+ connect_with_transport(transport)
165
+ else
166
+ raise ArgumentError.new("Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect")
167
+ end
168
+
169
+ result = connection.send_message('Target.getBrowserContexts')
170
+ browser_context_ids = result['browserContextIds']
171
+
172
+ Puppeteer::Browser.create(
173
+ connection: connection,
174
+ context_ids: browser_context_ids,
175
+ ignore_https_errors: @browser_options.ignore_https_errors?,
176
+ default_viewport: @browser_options.default_viewport,
177
+ process: nil,
178
+ close_callback: -> { connection.send_message('Browser.close') },
179
+ )
180
+ end
181
+
182
+ # @return [Puppeteer::Connection]
183
+ private def connect_with_browser_ws_endpoint(browser_ws_endpoint)
184
+ transport = Puppeteer::WebSocketTransport.create(browser_ws_endpoint)
185
+ Puppeteer::Connection.new(browser_ws_endpoint, transport, @browser_options.slow_mo)
186
+ end
187
+
188
+ # @return [Puppeteer::Connection]
189
+ private def connect_with_browser_url(browser_url)
190
+ raise NotImplementedError.new('Puppeteer#connect with browserUrl is not implemented yet.')
191
+ # const connectionURL = await getWSEndpoint(browserURL);
192
+ # const connectionTransport = await WebSocketTransport.create(
193
+ # connectionURL
194
+ # );
195
+ end
196
+
197
+ # @return [Puppeteer::Connection]
198
+ private def connect_with_transport(transport)
199
+ Puppeteer::Connection.new('', transport, @browser_options.slow_mo)
154
200
  end
155
201
 
156
202
  # @return {string}
@@ -88,8 +88,8 @@ class Puppeteer::Page
88
88
  network_manager.on_event 'Events.NetworkManager.RequestFinished' do |event|
89
89
  emit_event 'Events.Page.RequestFinished', event
90
90
  end
91
- # this._fileChooserInterceptionIsDisabled = false;
92
- # this._fileChooserInterceptors = new Set();
91
+ @file_chooser_interception_is_disabled = false
92
+ @file_chooser_interceptors = Set.new
93
93
 
94
94
  @client.on_event 'Page.domContentEventFired' do |event|
95
95
  emit_event 'Events.Page.DOMContentLoaded'
@@ -106,7 +106,9 @@ class Puppeteer::Page
106
106
  @client.on_event 'Log.entryAdded' do |event|
107
107
  handle_log_entry_added(event)
108
108
  end
109
- # client.on('Page.fileChooserOpened', event => this._onFileChooser(event));
109
+ @client.on_event 'Page.fileChooserOpened' do |event|
110
+ handle_file_chooser(event)
111
+ end
110
112
  @target.on_close do
111
113
  emit_event 'Events.Page.Close'
112
114
  @closed = true
@@ -122,41 +124,53 @@ class Puppeteer::Page
122
124
  )
123
125
  end
124
126
 
125
- # /**
126
- # * @param {!Protocol.Page.fileChooserOpenedPayload} event
127
- # */
128
- # async _onFileChooser(event) {
129
- # if (!this._fileChooserInterceptors.size)
130
- # return;
131
- # const frame = this._frameManager.frame(event.frameId);
132
- # const context = await frame.executionContext();
133
- # const element = await context._adoptBackendNodeId(event.backendNodeId);
134
- # const interceptors = Array.from(this._fileChooserInterceptors);
135
- # this._fileChooserInterceptors.clear();
136
- # const fileChooser = new FileChooser(this._client, element, event);
137
- # for (const interceptor of interceptors)
138
- # interceptor.call(null, fileChooser);
139
- # }
127
+ def handle_file_chooser(event)
128
+ return if @file_chooser_interceptors.empty?
129
+
130
+ frame = @frame_manager.frame(event['frameId'])
131
+ context = frame.execution_context
132
+ element = context.adopt_backend_node_id(event['backendNodeId'])
133
+ interceptors = @file_chooser_interceptors.to_a
134
+ @file_chooser_interceptors.clear
135
+ file_chooser = Puppeteer::FileChooser.new(element, event)
136
+ interceptors.each do |promise|
137
+ promise.fulfill(file_chooser)
138
+ end
139
+ end
140
140
 
141
- # /**
142
- # * @param {!{timeout?: number}=} options
143
- # * @return !Promise<!FileChooser>}
144
- # */
145
- # async waitForFileChooser(options = {}) {
146
- # if (!this._fileChooserInterceptors.size)
147
- # await this._client.send('Page.setInterceptFileChooserDialog', {enabled: true});
141
+ class FileChooserTimeoutError < StandardError
142
+ def initialize(timeout:)
143
+ super("waiting for filechooser failed: timeout #{timeout}ms exceeded")
144
+ end
145
+ end
148
146
 
149
- # const {
150
- # timeout = this._timeoutSettings.timeout(),
151
- # } = options;
152
- # let callback;
153
- # const promise = new Promise(x => callback = x);
154
- # this._fileChooserInterceptors.add(callback);
155
- # return helper.waitWithTimeout(promise, 'waiting for file chooser', timeout).catch(e => {
156
- # this._fileChooserInterceptors.delete(callback);
157
- # throw e;
158
- # });
159
- # }
147
+ # @param timeout [Integer]
148
+ # @return [Puppeteer::FileChooser]
149
+ def wait_for_file_chooser(timeout: nil)
150
+ if @file_chooser_interceptors.empty?
151
+ @client.send_message('Page.setInterceptFileChooserDialog', enabled: true)
152
+ end
153
+
154
+ option_timeout = timeout || @timeout_settings.timeout
155
+ promise = resolvable_future
156
+ @file_chooser_interceptors << promise
157
+
158
+ begin
159
+ Timeout.timeout(option_timeout / 1000.0) do
160
+ promise.value!
161
+ end
162
+ rescue Timeout::Error
163
+ raise FileChooserTimeoutError.new(timeout: option_timeout)
164
+ ensure
165
+ @file_chooser_interceptors.delete(promise)
166
+ end
167
+ end
168
+
169
+ # @param timeout [Integer]
170
+ # @return [Future<Puppeteer::FileChooser>]
171
+ async def async_wait_for_file_chooser(timeout: nil)
172
+ wait_for_file_chooser(timeout: timeout)
173
+ end
160
174
 
161
175
 
162
176
  # /**
@@ -275,23 +289,37 @@ class Puppeteer::Page
275
289
  end
276
290
 
277
291
  # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
278
- # @param {string} selector
279
- # @param {Function|string} pageFunction
280
- # @param {!Array<*>} args
281
- # @return {!Promise<(!Object|undefined)>}
292
+ # @param selector [String]
293
+ # @param page_function [String]
294
+ # @return [Object]
282
295
  def Seval(selector, page_function, *args)
283
296
  main_frame.Seval(selector, page_function, *args)
284
297
  end
285
298
 
299
+ # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
300
+ # @param selector [String]
301
+ # @param page_function [String]
302
+ # @return [Future]
303
+ async def async_Seval(selector, page_function, *args)
304
+ Seval(selector, page_function, *args)
305
+ end
306
+
286
307
  # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
287
- # @param {string} selector
288
- # @param {Function|string} pageFunction
289
- # @param {!Array<*>} args
290
- # @return {!Promise<(!Object|undefined)>}
308
+ # @param selector [String]
309
+ # @param page_function [String]
310
+ # @return [Object]
291
311
  def SSeval(selector, page_function, *args)
292
312
  main_frame.SSeval(selector, page_function, *args)
293
313
  end
294
314
 
315
+ # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
316
+ # @param selector [String]
317
+ # @param page_function [String]
318
+ # @return [Future]
319
+ async def async_SSeval(selector, page_function, *args)
320
+ SSeval(selector, page_function, *args)
321
+ end
322
+
295
323
  # `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
296
324
  # @param {string} expression
297
325
  # @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
@@ -610,14 +638,14 @@ class Puppeteer::Page
610
638
  main_frame.goto(url, referer: referer, timeout: timeout, wait_until: wait_until)
611
639
  end
612
640
 
613
- # @param {!{timeout?: number, waitUntil?: string|!Array<string>}=} options
614
- # @return {!Promise<?Puppeteer.Response>}
641
+ # @param timeout [number|nil]
642
+ # @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
643
+ # @return [Puppeteer::Response]
615
644
  def reload(timeout: nil, wait_until: nil)
616
- # const [response] = await Promise.all([
617
- # this.waitForNavigation(options),
618
- # this._client.send('Page.reload')
619
- # ]);
620
- # return response;
645
+ await_all(
646
+ async_wait_for_navigation(timeout: timeout, wait_until: wait_until),
647
+ @client.async_send_message('Page.reload'),
648
+ ).first
621
649
  end
622
650
 
623
651
  # @param timeout [number|nil]
@@ -968,11 +996,16 @@ class Puppeteer::Page
968
996
  main_frame.select(selector, *values)
969
997
  end
970
998
 
971
- # @param {string} selector
999
+ # @param selector [String]
972
1000
  def tap(selector)
973
1001
  main_frame.tap(selector)
974
1002
  end
975
1003
 
1004
+ # @param selector [String]
1005
+ async def async_tap(selector)
1006
+ tap(selector)
1007
+ end
1008
+
976
1009
  # @param selector [String]
977
1010
  # @param text [String]
978
1011
  # @param delay [Number]