puppeteer-ruby 0.0.13 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +2 -14
  3. data/.github/workflows/docs.yml +45 -0
  4. data/.github/workflows/reviewdog.yml +15 -0
  5. data/.rubocop.yml +39 -3
  6. data/README.md +54 -1
  7. data/lib/puppeteer.rb +10 -2
  8. data/lib/puppeteer/browser.rb +53 -34
  9. data/lib/puppeteer/browser_context.rb +35 -5
  10. data/lib/puppeteer/cdp_session.rb +3 -19
  11. data/lib/puppeteer/concurrent_ruby_utils.rb +6 -0
  12. data/lib/puppeteer/connection.rb +9 -16
  13. data/lib/puppeteer/debug_print.rb +1 -1
  14. data/lib/puppeteer/define_async_method.rb +23 -0
  15. data/lib/puppeteer/dom_world.rb +84 -73
  16. data/lib/puppeteer/element_handle.rb +46 -63
  17. data/lib/puppeteer/emulation_manager.rb +2 -6
  18. data/lib/puppeteer/env.rb +18 -0
  19. data/lib/puppeteer/execution_context.rb +1 -6
  20. data/lib/puppeteer/frame.rb +46 -46
  21. data/lib/puppeteer/frame_manager.rb +7 -25
  22. data/lib/puppeteer/js_handle.rb +39 -38
  23. data/lib/puppeteer/keyboard.rb +9 -29
  24. data/lib/puppeteer/mouse.rb +20 -24
  25. data/lib/puppeteer/network_manager.rb +163 -5
  26. data/lib/puppeteer/page.rb +221 -181
  27. data/lib/puppeteer/page/pdf_options.rb +166 -0
  28. data/lib/puppeteer/remote_object.rb +18 -5
  29. data/lib/puppeteer/request.rb +330 -0
  30. data/lib/puppeteer/response.rb +113 -0
  31. data/lib/puppeteer/touch_screen.rb +2 -7
  32. data/lib/puppeteer/version.rb +1 -1
  33. data/lib/puppeteer/wait_task.rb +3 -5
  34. data/lib/puppeteer/web_socket.rb +7 -0
  35. data/puppeteer-ruby.gemspec +2 -1
  36. metadata +25 -103
  37. data/docs/Puppeteer.html +0 -2338
  38. data/docs/Puppeteer/AsyncAwaitBehavior.html +0 -105
  39. data/docs/Puppeteer/Browser.html +0 -2258
  40. data/docs/Puppeteer/BrowserContext.html +0 -809
  41. data/docs/Puppeteer/BrowserFetcher.html +0 -214
  42. data/docs/Puppeteer/BrowserRunner.html +0 -914
  43. data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +0 -477
  44. data/docs/Puppeteer/CDPSession.html +0 -813
  45. data/docs/Puppeteer/CDPSession/Error.html +0 -124
  46. data/docs/Puppeteer/ConcurrentRubyUtils.html +0 -438
  47. data/docs/Puppeteer/Connection.html +0 -964
  48. data/docs/Puppeteer/Connection/MessageCallback.html +0 -434
  49. data/docs/Puppeteer/Connection/ProtocolError.html +0 -216
  50. data/docs/Puppeteer/Connection/RequestDebugPrinter.html +0 -217
  51. data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +0 -244
  52. data/docs/Puppeteer/ConsoleMessage.html +0 -565
  53. data/docs/Puppeteer/ConsoleMessage/Location.html +0 -433
  54. data/docs/Puppeteer/DOMWorld.html +0 -2293
  55. data/docs/Puppeteer/DOMWorld/DetachedError.html +0 -124
  56. data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +0 -124
  57. data/docs/Puppeteer/DebugPrint.html +0 -233
  58. data/docs/Puppeteer/Device.html +0 -470
  59. data/docs/Puppeteer/Devices.html +0 -139
  60. data/docs/Puppeteer/ElementHandle.html +0 -2542
  61. data/docs/Puppeteer/ElementHandle/BoundingBox.html +0 -507
  62. data/docs/Puppeteer/ElementHandle/BoxModel.html +0 -404
  63. data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +0 -206
  64. data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +0 -206
  65. data/docs/Puppeteer/ElementHandle/Point.html +0 -492
  66. data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +0 -124
  67. data/docs/Puppeteer/EmulationManager.html +0 -454
  68. data/docs/Puppeteer/EventCallbackable.html +0 -499
  69. data/docs/Puppeteer/EventCallbackable/EventListeners.html +0 -435
  70. data/docs/Puppeteer/ExecutionContext.html +0 -998
  71. data/docs/Puppeteer/ExecutionContext/EvaluationError.html +0 -124
  72. data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +0 -357
  73. data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +0 -389
  74. data/docs/Puppeteer/FileChooser.html +0 -455
  75. data/docs/Puppeteer/Frame.html +0 -3835
  76. data/docs/Puppeteer/FrameManager.html +0 -2410
  77. data/docs/Puppeteer/FrameManager/NavigationError.html +0 -124
  78. data/docs/Puppeteer/IfPresent.html +0 -222
  79. data/docs/Puppeteer/JSHandle.html +0 -1352
  80. data/docs/Puppeteer/Keyboard.html +0 -1557
  81. data/docs/Puppeteer/Keyboard/KeyDefinition.html +0 -831
  82. data/docs/Puppeteer/Keyboard/KeyDescription.html +0 -603
  83. data/docs/Puppeteer/Launcher.html +0 -237
  84. data/docs/Puppeteer/Launcher/Base.html +0 -385
  85. data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +0 -124
  86. data/docs/Puppeteer/Launcher/BrowserOptions.html +0 -441
  87. data/docs/Puppeteer/Launcher/Chrome.html +0 -674
  88. data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +0 -382
  89. data/docs/Puppeteer/Launcher/ChromeArgOptions.html +0 -531
  90. data/docs/Puppeteer/Launcher/LaunchOptions.html +0 -893
  91. data/docs/Puppeteer/LifecycleWatcher.html +0 -834
  92. data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +0 -363
  93. data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +0 -206
  94. data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +0 -124
  95. data/docs/Puppeteer/Mouse.html +0 -1095
  96. data/docs/Puppeteer/Mouse/Button.html +0 -136
  97. data/docs/Puppeteer/NetworkManager.html +0 -901
  98. data/docs/Puppeteer/NetworkManager/Credentials.html +0 -385
  99. data/docs/Puppeteer/Page.html +0 -6173
  100. data/docs/Puppeteer/Page/FileChooserTimeoutError.html +0 -206
  101. data/docs/Puppeteer/Page/ScreenshotOptions.html +0 -845
  102. data/docs/Puppeteer/Page/ScriptTag.html +0 -555
  103. data/docs/Puppeteer/Page/StyleTag.html +0 -448
  104. data/docs/Puppeteer/Page/TargetCrashedError.html +0 -124
  105. data/docs/Puppeteer/RemoteObject.html +0 -1087
  106. data/docs/Puppeteer/Target.html +0 -1336
  107. data/docs/Puppeteer/Target/InitializeFailure.html +0 -124
  108. data/docs/Puppeteer/Target/TargetInfo.html +0 -729
  109. data/docs/Puppeteer/TimeoutError.html +0 -135
  110. data/docs/Puppeteer/TimeoutSettings.html +0 -496
  111. data/docs/Puppeteer/TouchScreen.html +0 -464
  112. data/docs/Puppeteer/Viewport.html +0 -837
  113. data/docs/Puppeteer/WaitTask.html +0 -637
  114. data/docs/Puppeteer/WaitTask/TerminatedError.html +0 -124
  115. data/docs/Puppeteer/WaitTask/TimeoutError.html +0 -206
  116. data/docs/Puppeteer/WebSocket.html +0 -673
  117. data/docs/Puppeteer/WebSocket/DriverImpl.html +0 -412
  118. data/docs/Puppeteer/WebSocket/TransportError.html +0 -124
  119. data/docs/Puppeteer/WebSocketTransport.html +0 -600
  120. data/docs/Puppeteer/WebSocktTransportError.html +0 -124
  121. data/docs/_index.html +0 -816
  122. data/docs/class_list.html +0 -51
  123. data/docs/css/common.css +0 -1
  124. data/docs/css/full_list.css +0 -58
  125. data/docs/css/style.css +0 -496
  126. data/docs/file.README.html +0 -125
  127. data/docs/file_list.html +0 -56
  128. data/docs/frames.html +0 -17
  129. data/docs/index.html +0 -125
  130. data/docs/js/app.js +0 -314
  131. data/docs/js/full_list.js +0 -216
  132. data/docs/js/jquery.js +0 -4
  133. data/docs/method_list.html +0 -4123
  134. data/docs/top-level-namespace.html +0 -126
  135. data/lib/puppeteer/async_await_behavior.rb +0 -38
@@ -1,11 +1,13 @@
1
1
  require 'base64'
2
+ require "stringio"
2
3
 
4
+ require_relative './page/pdf_options'
3
5
  require_relative './page/screenshot_options'
4
6
 
5
7
  class Puppeteer::Page
6
8
  include Puppeteer::EventCallbackable
7
9
  include Puppeteer::IfPresent
8
- using Puppeteer::AsyncAwaitBehavior
10
+ using Puppeteer::DefineAsyncMethod
9
11
 
10
12
  # @param {!Puppeteer.CDPSession} client
11
13
  # @param {!Puppeteer.Target} target
@@ -205,12 +207,7 @@ class Puppeteer::Page
205
207
  end
206
208
  end
207
209
 
208
- # @param timeout [Integer]
209
- # @return [Future<Puppeteer::FileChooser>]
210
- async def async_wait_for_file_chooser(timeout: nil)
211
- wait_for_file_chooser(timeout: timeout)
212
- end
213
-
210
+ define_async_method :async_wait_for_file_chooser
214
211
 
215
212
  # /**
216
213
  # * @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}} options
@@ -305,6 +302,8 @@ class Puppeteer::Page
305
302
  main_frame.S(selector)
306
303
  end
307
304
 
305
+ define_async_method :async_S
306
+
308
307
  # `$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
309
308
  # @param {string} selector
310
309
  # @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
@@ -312,6 +311,8 @@ class Puppeteer::Page
312
311
  main_frame.SS(selector)
313
312
  end
314
313
 
314
+ define_async_method :async_SS
315
+
315
316
  # @param {Function|string} pageFunction
316
317
  # @param {!Array<*>} args
317
318
  # @return {!Promise<!Puppeteer.JSHandle>}
@@ -320,6 +321,8 @@ class Puppeteer::Page
320
321
  context.evaluate_handle(page_function, *args)
321
322
  end
322
323
 
324
+ define_async_method :async_evaluate_handle
325
+
323
326
  # @param {!Puppeteer.JSHandle} prototypeHandle
324
327
  # @return {!Promise<!Puppeteer.JSHandle>}
325
328
  def query_objects(prototype_handle)
@@ -335,13 +338,7 @@ class Puppeteer::Page
335
338
  main_frame.Seval(selector, page_function, *args)
336
339
  end
337
340
 
338
- # `$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
339
- # @param selector [String]
340
- # @param page_function [String]
341
- # @return [Future]
342
- async def async_Seval(selector, page_function, *args)
343
- Seval(selector, page_function, *args)
344
- end
341
+ define_async_method :async_Seval
345
342
 
346
343
  # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
347
344
  # @param selector [String]
@@ -351,13 +348,7 @@ class Puppeteer::Page
351
348
  main_frame.SSeval(selector, page_function, *args)
352
349
  end
353
350
 
354
- # `$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
355
- # @param selector [String]
356
- # @param page_function [String]
357
- # @return [Future]
358
- async def async_SSeval(selector, page_function, *args)
359
- SSeval(selector, page_function, *args)
360
- end
351
+ define_async_method :async_SSeval
361
352
 
362
353
  # `$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
363
354
  # @param {string} expression
@@ -366,6 +357,8 @@ class Puppeteer::Page
366
357
  main_frame.Sx(expression)
367
358
  end
368
359
 
360
+ define_async_method :async_Sx
361
+
369
362
  # /**
370
363
  # * @param {!Array<string>} urls
371
364
  # * @return {!Promise<!Array<Network.Cookie>>}
@@ -658,13 +651,14 @@ class Puppeteer::Page
658
651
  main_frame.content
659
652
  end
660
653
 
661
- # @param {string} html
662
- # @param {!{timeout?: number, waitUntil?: string|!Array<string>}=} options
654
+ # @param html [String]
655
+ # @param timeout [Integer]
656
+ # @param wait_until [String|Array<String>]
663
657
  def set_content(html, timeout: nil, wait_until: nil)
664
658
  main_frame.set_content(html, timeout: timeout, wait_until: wait_until)
665
659
  end
666
660
 
667
- # @param {string} html
661
+ # @param html [String]
668
662
  def content=(html)
669
663
  main_frame.set_content(html)
670
664
  end
@@ -687,54 +681,111 @@ class Puppeteer::Page
687
681
  ).first
688
682
  end
689
683
 
690
- # @param timeout [number|nil]
691
- # @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
692
684
  private def wait_for_navigation(timeout: nil, wait_until: nil)
693
685
  main_frame.send(:wait_for_navigation, timeout: timeout, wait_until: wait_until)
694
686
  end
695
687
 
688
+ # @!method async_wait_for_navigation(timeout: nil, wait_until: nil)
689
+ #
696
690
  # @param timeout [number|nil]
697
691
  # @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
698
- # @return [Future]
699
- async def async_wait_for_navigation(timeout: nil, wait_until: nil)
700
- wait_for_navigation(timeout: timeout, wait_until: wait_until)
692
+ define_async_method :async_wait_for_navigation
693
+
694
+ private def wait_for_network_manager_event(event_name, predicate:, timeout:)
695
+ option_timeout = timeout || @timeout_settings.timeout
696
+
697
+ @wait_for_network_manager_event_listener_ids ||= {}
698
+ if_present(@wait_for_network_manager_event_listener_ids[event_name]) do |listener_id|
699
+ @frame_manager.network_manager.remove_event_listener(listener_id)
700
+ end
701
+
702
+ promise = resolvable_future
703
+
704
+ @wait_for_network_manager_event_listener_ids[event_name] =
705
+ @frame_manager.network_manager.add_event_listener(event_name) do |event_target|
706
+ if predicate.call(event_target)
707
+ promise.fulfill(nil)
708
+ end
709
+ end
710
+
711
+ begin
712
+ Timeout.timeout(option_timeout / 1000.0) do
713
+ await_any(promise, session_close_promise)
714
+ end
715
+ rescue Timeout::Error
716
+ raise Puppeteer::TimeoutError.new("waiting for #{event_name} failed: timeout #{timeout}ms exceeded")
717
+ ensure
718
+ @frame_manager.network_manager.remove_event_listener(@wait_for_network_manager_event_listener_ids[event_name])
719
+ end
701
720
  end
702
721
 
703
- # /**
704
- # * @param {(string|Function)} urlOrPredicate
705
- # * @param {!{timeout?: number}=} options
706
- # * @return {!Promise<!Puppeteer.Request>}
707
- # */
708
- # async waitForRequest(urlOrPredicate, options = {}) {
709
- # const {
710
- # timeout = this._timeoutSettings.timeout(),
711
- # } = options;
712
- # return helper.waitForEvent(this._frameManager.networkManager(), Events.NetworkManager.Request, request => {
713
- # if (helper.isString(urlOrPredicate))
714
- # return (urlOrPredicate === request.url());
715
- # if (typeof urlOrPredicate === 'function')
716
- # return !!(urlOrPredicate(request));
717
- # return false;
718
- # }, timeout, this._sessionClosePromise());
719
- # }
722
+ private def session_close_promise
723
+ @disconnect_promise ||= resolvable_future do |future|
724
+ @client.observe_first('Events.CDPSession.Disconnected') do
725
+ future.reject(Puppeteer::CDPSession::Error.new('Target Closed'))
726
+ end
727
+ end
728
+ end
720
729
 
721
- # /**
722
- # * @param {(string|Function)} urlOrPredicate
723
- # * @param {!{timeout?: number}=} options
724
- # * @return {!Promise<!Puppeteer.Response>}
725
- # */
726
- # async waitForResponse(urlOrPredicate, options = {}) {
727
- # const {
728
- # timeout = this._timeoutSettings.timeout(),
729
- # } = options;
730
- # return helper.waitForEvent(this._frameManager.networkManager(), Events.NetworkManager.Response, response => {
731
- # if (helper.isString(urlOrPredicate))
732
- # return (urlOrPredicate === response.url());
733
- # if (typeof urlOrPredicate === 'function')
734
- # return !!(urlOrPredicate(response));
735
- # return false;
736
- # }, timeout, this._sessionClosePromise());
737
- # }
730
+ private def wait_for_request(url: nil, predicate: nil, timeout: nil)
731
+ if !url && !predicate
732
+ raise ArgumentError.new('url or predicate must be specified')
733
+ end
734
+ if predicate && !predicate.is_a?(Proc)
735
+ raise ArgumentError.new('predicate must be a proc.')
736
+ end
737
+ request_predicate =
738
+ if url
739
+ -> (request) { request.url == url }
740
+ else
741
+ -> (request) { predicate.call(request) }
742
+ end
743
+
744
+ wait_for_network_manager_event('Events.NetworkManager.Request',
745
+ predicate: request_predicate,
746
+ timeout: timeout,
747
+ )
748
+ end
749
+
750
+ # @!method async_wait_for_request(url: nil, predicate: nil, timeout: nil)
751
+ #
752
+ # Waits until request URL matches or request matches the given predicate.
753
+ #
754
+ # Waits until request URL matches
755
+ # wait_for_request(url: 'https://example.com/awesome')
756
+ #
757
+ # Waits until request matches the given predicate
758
+ # wait_for_request(predicate: -> (req){ req.url.start_with?('https://example.com/search') })
759
+ #
760
+ # @param url [String]
761
+ # @param predicate [Proc(Puppeteer::Request -> Boolean)]
762
+ define_async_method :async_wait_for_request
763
+
764
+ private def wait_for_response(url: nil, predicate: nil, timeout: nil)
765
+ if !url && !predicate
766
+ raise ArgumentError.new('url or predicate must be specified')
767
+ end
768
+ if predicate && !predicate.is_a?(Proc)
769
+ raise ArgumentError.new('predicate must be a proc.')
770
+ end
771
+ response_predicate =
772
+ if url
773
+ -> (response) { response.url == url }
774
+ else
775
+ -> (response) { predicate.call(response) }
776
+ end
777
+
778
+ wait_for_network_manager_event('Events.NetworkManager.Response',
779
+ predicate: response_predicate,
780
+ timeout: timeout,
781
+ )
782
+ end
783
+
784
+ # @!method async_wait_for_response(url: nil, predicate: nil, timeout: nil)
785
+ #
786
+ # @param url [String]
787
+ # @param predicate [Proc(Puppeteer::Request -> Boolean)]
788
+ define_async_method :async_wait_for_response
738
789
 
739
790
  # @param timeout [number|nil]
740
791
  # @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
@@ -773,20 +824,19 @@ class Puppeteer::Page
773
824
  @client.send_message('Emulation.setScriptExecutionDisabled', value: !enabled)
774
825
  end
775
826
 
776
- # /**
777
- # * @param {boolean} enabled
778
- # */
779
- # async setBypassCSP(enabled) {
780
- # await this._client.send('Page.setBypassCSP', { enabled });
781
- # }
827
+ # @param enabled [Boolean]
828
+ def bypass_csp=(enabled)
829
+ @client.send_message('Page.setBypassCSP', enabled: enabled)
830
+ end
782
831
 
783
- # /**
784
- # * @param {?string} type
785
- # */
786
- # async emulateMediaType(type) {
787
- # assert(type === 'screen' || type === 'print' || type === null, 'Unsupported media type: ' + type);
788
- # await this._client.send('Emulation.setEmulatedMedia', {media: type || ''});
789
- # }
832
+ # @param media_type [String|Symbol|nil] either of (media, print, nil)
833
+ def emulate_media_type(media_type)
834
+ media_type_str = media_type.to_s
835
+ unless ['screen', 'print', ''].include?(media_type_str)
836
+ raise ArgumentError.new("Unsupported media type: #{media_type}")
837
+ end
838
+ @client.send_message('Emulation.setEmulatedMedia', media: media_type_str)
839
+ end
790
840
 
791
841
  # /**
792
842
  # * @param {?Array<MediaFeature>} features
@@ -806,7 +856,7 @@ class Puppeteer::Page
806
856
 
807
857
  # @param timezone_id [String?]
808
858
  def emulate_timezone(timezone_id)
809
- @client.send_message('Emulation.setTimezoneOverride', timezoneId: timezoneId || '')
859
+ @client.send_message('Emulation.setTimezoneOverride', timezoneId: timezone_id || '')
810
860
  rescue => err
811
861
  if err.message.include?('Invalid timezone')
812
862
  raise ArgumentError.new("Invalid timezone ID: #{timezone_id}")
@@ -831,6 +881,8 @@ class Puppeteer::Page
831
881
  main_frame.evaluate(page_function, *args)
832
882
  end
833
883
 
884
+ define_async_method :async_evaluate
885
+
834
886
  # /**
835
887
  # * @param {Function|string} pageFunction
836
888
  # * @param {!Array<*>} args
@@ -927,71 +979,66 @@ class Puppeteer::Page
927
979
  buffer
928
980
  end
929
981
 
930
- # /**
931
- # * @param {!PDFOptions=} options
932
- # * @return {!Promise<!Buffer>}
933
- # */
934
- # async pdf(options = {}) {
935
- # const {
936
- # scale = 1,
937
- # displayHeaderFooter = false,
938
- # headerTemplate = '',
939
- # footerTemplate = '',
940
- # printBackground = false,
941
- # landscape = false,
942
- # pageRanges = '',
943
- # preferCSSPageSize = false,
944
- # margin = {},
945
- # path = null
946
- # } = options;
947
-
948
- # let paperWidth = 8.5;
949
- # let paperHeight = 11;
950
- # if (options.format) {
951
- # const format = Page.PaperFormats[options.format.toLowerCase()];
952
- # assert(format, 'Unknown paper format: ' + options.format);
953
- # paperWidth = format.width;
954
- # paperHeight = format.height;
955
- # } else {
956
- # paperWidth = convertPrintParameterToInches(options.width) || paperWidth;
957
- # paperHeight = convertPrintParameterToInches(options.height) || paperHeight;
958
- # }
982
+ class ProtocolStreamReader
983
+ def initialize(client:, handle:, path:)
984
+ @client = client
985
+ @handle = handle
986
+ @path = path
987
+ end
959
988
 
960
- # const marginTop = convertPrintParameterToInches(margin.top) || 0;
961
- # const marginLeft = convertPrintParameterToInches(margin.left) || 0;
962
- # const marginBottom = convertPrintParameterToInches(margin.bottom) || 0;
963
- # const marginRight = convertPrintParameterToInches(margin.right) || 0;
964
-
965
- # const result = await this._client.send('Page.printToPDF', {
966
- # transferMode: 'ReturnAsStream',
967
- # landscape,
968
- # displayHeaderFooter,
969
- # headerTemplate,
970
- # footerTemplate,
971
- # printBackground,
972
- # scale,
973
- # paperWidth,
974
- # paperHeight,
975
- # marginTop,
976
- # marginBottom,
977
- # marginLeft,
978
- # marginRight,
979
- # pageRanges,
980
- # preferCSSPageSize
981
- # });
982
- # return await helper.readProtocolStream(this._client, result.stream, path);
983
- # }
989
+ def read
990
+ out = StringIO.new
991
+ File.open(@path, 'w') do |file|
992
+ eof = false
993
+ until eof
994
+ response = @client.send_message('IO.read', handle: @handle)
995
+ eof = response['eof']
996
+ data =
997
+ if response['base64Encoded']
998
+ Base64.decode64(response['data'])
999
+ else
1000
+ response['data']
1001
+ end
1002
+ out.write(data)
1003
+ file.write(data)
1004
+ end
1005
+ end
1006
+ @client.send_message('IO.close', handle: @handle)
1007
+ out.read
1008
+ end
1009
+ end
1010
+
1011
+ class PrintToPdfIsNotImplementedError < StandardError
1012
+ def initialize
1013
+ super('pdf() is only available in headless mode. See https://github.com/puppeteer/puppeteer/issues/1829')
1014
+ end
1015
+ end
1016
+
1017
+ # @return [String]
1018
+ def pdf(options = {})
1019
+ pdf_options = PDFOptions.new(options)
1020
+ result = @client.send_message('Page.printToPDF', pdf_options.page_print_args)
1021
+ ProtocolStreamReader.new(client: @client, handle: result['stream'], path: pdf_options.path).read
1022
+ rescue => err
1023
+ if err.message.include?('PrintToPDF is not implemented')
1024
+ raise PrintToPdfIsNotImplementedError.new
1025
+ else
1026
+ raise
1027
+ end
1028
+ end
1029
+
1030
+ # @param run_before_unload [Boolean]
1031
+ def close(run_before_unload: false)
1032
+ unless @client.connection
1033
+ raise 'Protocol error: Connection closed. Most likely the page has been closed.'
1034
+ end
984
1035
 
985
- # @param {!{runBeforeUnload: (boolean|undefined)}=} options
986
- def close
987
- # assert(!!this._client._connection, 'Protocol error: Connection closed. Most likely the page has been closed.');
988
- # const runBeforeUnload = !!options.runBeforeUnload;
989
- # if (runBeforeUnload) {
990
- # await this._client.send('Page.close');
991
- # } else {
992
- # await this._client._connection.send('Target.closeTarget', { targetId: this._target._targetId });
993
- # await this._target._isClosedPromise;
994
- # }
1036
+ if run_before_unload
1037
+ @client.send_message('Page.close')
1038
+ else
1039
+ @client.connection.send_message('Target.closeTarget', targetId: @target.target_id)
1040
+ await @target.is_closed_promise
1041
+ end
995
1042
  end
996
1043
 
997
1044
  # @return [boolean]
@@ -1009,20 +1056,15 @@ class Puppeteer::Page
1009
1056
  main_frame.click(selector, delay: delay, button: button, click_count: click_count)
1010
1057
  end
1011
1058
 
1012
- # @param selector [String]
1013
- # @param delay [Number]
1014
- # @param button [String] "left"|"right"|"middle"
1015
- # @param click_count [Number]
1016
- # @return [Future]
1017
- async def async_click(selector, delay: nil, button: nil, click_count: nil)
1018
- click(selector, delay: delay, button: button, click_count: click_count)
1019
- end
1059
+ define_async_method :async_click
1020
1060
 
1021
1061
  # @param {string} selector
1022
1062
  def focus(selector)
1023
1063
  main_frame.focus(selector)
1024
1064
  end
1025
1065
 
1066
+ define_async_method :async_focus
1067
+
1026
1068
  # @param {string} selector
1027
1069
  def hover(selector)
1028
1070
  main_frame.hover(selector)
@@ -1035,16 +1077,26 @@ class Puppeteer::Page
1035
1077
  main_frame.select(selector, *values)
1036
1078
  end
1037
1079
 
1038
- # @param selector [String]
1039
- def tap(selector)
1040
- main_frame.tap(selector)
1041
- end
1080
+ define_async_method :async_select
1042
1081
 
1043
1082
  # @param selector [String]
1044
- async def async_tap(selector)
1045
- tap(selector)
1083
+ def tap(selector: nil, &block)
1084
+ # resolves double meaning of tap.
1085
+ if selector.nil? && block
1086
+ # Original usage of Object#tap.
1087
+ #
1088
+ # browser.new_page.tap do |page|
1089
+ # ...
1090
+ # end
1091
+ super(&block)
1092
+ else
1093
+ # Puppeteer's Page#tap.
1094
+ main_frame.tap(selector)
1095
+ end
1046
1096
  end
1047
1097
 
1098
+ define_async_method :async_tap
1099
+
1048
1100
  # @param selector [String]
1049
1101
  # @param text [String]
1050
1102
  # @param delay [Number]
@@ -1052,15 +1104,7 @@ class Puppeteer::Page
1052
1104
  main_frame.type_text(selector, text, delay: delay)
1053
1105
  end
1054
1106
 
1055
- # /**
1056
- # * @param {(string|number|Function)} selectorOrFunctionOrTimeout
1057
- # * @param {!{visible?: boolean, hidden?: boolean, timeout?: number, polling?: string|number}=} options
1058
- # * @param {!Array<*>} args
1059
- # * @return {!Promise<!Puppeteer.JSHandle>}
1060
- # */
1061
- # waitFor(selectorOrFunctionOrTimeout, options = {}, ...args) {
1062
- # return this.mainFrame().waitFor(selectorOrFunctionOrTimeout, options, ...args);
1063
- # }
1107
+ define_async_method :async_type_text
1064
1108
 
1065
1109
  # @param selector [String]
1066
1110
  # @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
@@ -1070,12 +1114,11 @@ class Puppeteer::Page
1070
1114
  main_frame.wait_for_selector(selector, visible: visible, hidden: hidden, timeout: timeout)
1071
1115
  end
1072
1116
 
1073
- # @param selector [String]
1074
- # @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
1075
- # @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
1076
- # @param timeout [Integer]
1077
- async def async_wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil)
1078
- wait_for_selector(selector, visible: visible, hidden: hidden, timeout: timeout)
1117
+ define_async_method :async_wait_for_selector
1118
+
1119
+ # @param milliseconds [Integer] the number of milliseconds to wait.
1120
+ def wait_for_timeout(milliseconds)
1121
+ main_frame.wait_for_timeout(milliseconds)
1079
1122
  end
1080
1123
 
1081
1124
  # @param xpath [String]
@@ -1086,19 +1129,16 @@ class Puppeteer::Page
1086
1129
  main_frame.wait_for_xpath(xpath, visible: visible, hidden: hidden, timeout: timeout)
1087
1130
  end
1088
1131
 
1089
- # @param xpath [String]
1090
- # @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
1091
- # @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
1132
+ define_async_method :async_wait_for_xpath
1133
+
1134
+ # @param page_function [String]
1135
+ # @param args [Integer|Array]
1136
+ # @param polling [String]
1092
1137
  # @param timeout [Integer]
1093
- async def async_wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil)
1094
- wait_for_xpath(xpath, visible: visible, hidden: hidden, timeout: timeout)
1138
+ # @return [Puppeteer::JSHandle]
1139
+ def wait_for_function(page_function, args: [], polling: nil, timeout: nil)
1140
+ main_frame.wait_for_function(page_function, args: args, polling: polling, timeout: timeout)
1095
1141
  end
1096
1142
 
1097
- # @param {Function|string} pageFunction
1098
- # @param {!{polling?: string|number, timeout?: number}=} options
1099
- # @param {!Array<*>} args
1100
- # @return {!Promise<!Puppeteer.JSHandle>}
1101
- def wait_for_function(page_function, options = {}, *args)
1102
- main_frame.wait_for_function(page_function, options, *args)
1103
- end
1143
+ define_async_method :async_wait_for_function
1104
1144
  end