puppeteer-ruby 0.0.13 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
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