puppeteer-ruby 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +71 -0
  3. data/.github/stale.yml +16 -0
  4. data/.gitignore +19 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +302 -0
  7. data/.travis.yml +7 -0
  8. data/Dockerfile +6 -0
  9. data/Gemfile +6 -0
  10. data/README.md +54 -0
  11. data/Rakefile +1 -0
  12. data/bin/console +11 -0
  13. data/bin/setup +8 -0
  14. data/docker-compose.yml +15 -0
  15. data/docs/Puppeteer.html +2020 -0
  16. data/docs/Puppeteer/AsyncAwaitBehavior.html +105 -0
  17. data/docs/Puppeteer/Browser.html +2148 -0
  18. data/docs/Puppeteer/BrowserContext.html +809 -0
  19. data/docs/Puppeteer/BrowserFetcher.html +214 -0
  20. data/docs/Puppeteer/BrowserRunner.html +914 -0
  21. data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +477 -0
  22. data/docs/Puppeteer/CDPSession.html +813 -0
  23. data/docs/Puppeteer/CDPSession/Error.html +124 -0
  24. data/docs/Puppeteer/ConcurrentRubyUtils.html +430 -0
  25. data/docs/Puppeteer/Connection.html +960 -0
  26. data/docs/Puppeteer/Connection/MessageCallback.html +434 -0
  27. data/docs/Puppeteer/Connection/ProtocolError.html +216 -0
  28. data/docs/Puppeteer/Connection/RequestDebugPrinter.html +217 -0
  29. data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +244 -0
  30. data/docs/Puppeteer/ConsoleMessage.html +565 -0
  31. data/docs/Puppeteer/ConsoleMessage/Location.html +433 -0
  32. data/docs/Puppeteer/DOMWorld.html +2219 -0
  33. data/docs/Puppeteer/DOMWorld/DetachedError.html +124 -0
  34. data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +124 -0
  35. data/docs/Puppeteer/DebugPrint.html +233 -0
  36. data/docs/Puppeteer/Device.html +470 -0
  37. data/docs/Puppeteer/Devices.html +139 -0
  38. data/docs/Puppeteer/ElementHandle.html +2542 -0
  39. data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +206 -0
  40. data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +206 -0
  41. data/docs/Puppeteer/ElementHandle/Point.html +492 -0
  42. data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +124 -0
  43. data/docs/Puppeteer/EmulationManager.html +454 -0
  44. data/docs/Puppeteer/EventCallbackable.html +433 -0
  45. data/docs/Puppeteer/EventCallbackable/EventListeners.html +435 -0
  46. data/docs/Puppeteer/ExecutionContext.html +998 -0
  47. data/docs/Puppeteer/ExecutionContext/EvaluationError.html +124 -0
  48. data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +357 -0
  49. data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +389 -0
  50. data/docs/Puppeteer/FileChooser.html +455 -0
  51. data/docs/Puppeteer/Frame.html +3677 -0
  52. data/docs/Puppeteer/FrameManager.html +2410 -0
  53. data/docs/Puppeteer/FrameManager/NavigationError.html +124 -0
  54. data/docs/Puppeteer/IfPresent.html +222 -0
  55. data/docs/Puppeteer/JSHandle.html +1352 -0
  56. data/docs/Puppeteer/Keyboard.html +1557 -0
  57. data/docs/Puppeteer/Keyboard/KeyDefinition.html +831 -0
  58. data/docs/Puppeteer/Keyboard/KeyDescription.html +603 -0
  59. data/docs/Puppeteer/Launcher.html +237 -0
  60. data/docs/Puppeteer/Launcher/Base.html +385 -0
  61. data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +124 -0
  62. data/docs/Puppeteer/Launcher/BrowserOptions.html +441 -0
  63. data/docs/Puppeteer/Launcher/Chrome.html +669 -0
  64. data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +382 -0
  65. data/docs/Puppeteer/Launcher/ChromeArgOptions.html +531 -0
  66. data/docs/Puppeteer/Launcher/LaunchOptions.html +893 -0
  67. data/docs/Puppeteer/LifecycleWatcher.html +834 -0
  68. data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +363 -0
  69. data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +206 -0
  70. data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +124 -0
  71. data/docs/Puppeteer/Mouse.html +1105 -0
  72. data/docs/Puppeteer/Mouse/Button.html +136 -0
  73. data/docs/Puppeteer/NetworkManager.html +901 -0
  74. data/docs/Puppeteer/NetworkManager/Credentials.html +385 -0
  75. data/docs/Puppeteer/Page.html +5970 -0
  76. data/docs/Puppeteer/Page/FileChooserTimeoutError.html +206 -0
  77. data/docs/Puppeteer/Page/ScreenshotOptions.html +845 -0
  78. data/docs/Puppeteer/Page/ScriptTag.html +555 -0
  79. data/docs/Puppeteer/Page/StyleTag.html +448 -0
  80. data/docs/Puppeteer/Page/TargetCrashedError.html +124 -0
  81. data/docs/Puppeteer/RemoteObject.html +1087 -0
  82. data/docs/Puppeteer/Target.html +1336 -0
  83. data/docs/Puppeteer/Target/InitializeFailure.html +124 -0
  84. data/docs/Puppeteer/Target/TargetInfo.html +729 -0
  85. data/docs/Puppeteer/TimeoutError.html +135 -0
  86. data/docs/Puppeteer/TimeoutSettings.html +496 -0
  87. data/docs/Puppeteer/TouchScreen.html +464 -0
  88. data/docs/Puppeteer/Viewport.html +837 -0
  89. data/docs/Puppeteer/WaitTask.html +637 -0
  90. data/docs/Puppeteer/WaitTask/TerminatedError.html +124 -0
  91. data/docs/Puppeteer/WaitTask/TimeoutError.html +206 -0
  92. data/docs/Puppeteer/WebSocket.html +673 -0
  93. data/docs/Puppeteer/WebSocket/DriverImpl.html +412 -0
  94. data/docs/Puppeteer/WebSocketTransport.html +600 -0
  95. data/docs/Puppeteer/WebSocktTransportError.html +124 -0
  96. data/docs/_index.html +823 -0
  97. data/docs/class_list.html +51 -0
  98. data/docs/css/common.css +1 -0
  99. data/docs/css/full_list.css +58 -0
  100. data/docs/css/style.css +496 -0
  101. data/docs/file.README.html +123 -0
  102. data/docs/file_list.html +56 -0
  103. data/docs/frames.html +17 -0
  104. data/docs/index.html +123 -0
  105. data/docs/js/app.js +314 -0
  106. data/docs/js/full_list.js +216 -0
  107. data/docs/js/jquery.js +4 -0
  108. data/docs/method_list.html +4075 -0
  109. data/docs/top-level-namespace.html +126 -0
  110. data/lib/puppeteer.rb +200 -0
  111. data/lib/puppeteer/async_await_behavior.rb +38 -0
  112. data/lib/puppeteer/browser.rb +259 -0
  113. data/lib/puppeteer/browser_context.rb +90 -0
  114. data/lib/puppeteer/browser_fetcher.rb +6 -0
  115. data/lib/puppeteer/browser_runner.rb +161 -0
  116. data/lib/puppeteer/cdp_session.rb +100 -0
  117. data/lib/puppeteer/concurrent_ruby_utils.rb +37 -0
  118. data/lib/puppeteer/connection.rb +254 -0
  119. data/lib/puppeteer/console_message.rb +24 -0
  120. data/lib/puppeteer/debug_print.rb +20 -0
  121. data/lib/puppeteer/device.rb +12 -0
  122. data/lib/puppeteer/devices.rb +885 -0
  123. data/lib/puppeteer/dom_world.rb +484 -0
  124. data/lib/puppeteer/element_handle.rb +433 -0
  125. data/lib/puppeteer/element_handle/bounding_box.rb +12 -0
  126. data/lib/puppeteer/element_handle/box_model.rb +19 -0
  127. data/lib/puppeteer/element_handle/point.rb +26 -0
  128. data/lib/puppeteer/emulation_manager.rb +46 -0
  129. data/lib/puppeteer/errors.rb +2 -0
  130. data/lib/puppeteer/event_callbackable.rb +88 -0
  131. data/lib/puppeteer/execution_context.rb +254 -0
  132. data/lib/puppeteer/file_chooser.rb +29 -0
  133. data/lib/puppeteer/frame.rb +286 -0
  134. data/lib/puppeteer/frame_manager.rb +378 -0
  135. data/lib/puppeteer/if_present.rb +18 -0
  136. data/lib/puppeteer/js_handle.rb +142 -0
  137. data/lib/puppeteer/keyboard.rb +183 -0
  138. data/lib/puppeteer/keyboard/key_description.rb +19 -0
  139. data/lib/puppeteer/keyboard/us_keyboard_layout.rb +283 -0
  140. data/lib/puppeteer/launcher.rb +25 -0
  141. data/lib/puppeteer/launcher/base.rb +48 -0
  142. data/lib/puppeteer/launcher/browser_options.rb +41 -0
  143. data/lib/puppeteer/launcher/chrome.rb +211 -0
  144. data/lib/puppeteer/launcher/chrome_arg_options.rb +49 -0
  145. data/lib/puppeteer/launcher/launch_options.rb +68 -0
  146. data/lib/puppeteer/lifecycle_watcher.rb +171 -0
  147. data/lib/puppeteer/mouse.rb +123 -0
  148. data/lib/puppeteer/network_manager.rb +122 -0
  149. data/lib/puppeteer/page.rb +1065 -0
  150. data/lib/puppeteer/page/screenshot_options.rb +78 -0
  151. data/lib/puppeteer/remote_object.rb +143 -0
  152. data/lib/puppeteer/target.rb +150 -0
  153. data/lib/puppeteer/timeout_settings.rb +15 -0
  154. data/lib/puppeteer/touch_screen.rb +43 -0
  155. data/lib/puppeteer/version.rb +3 -0
  156. data/lib/puppeteer/viewport.rb +54 -0
  157. data/lib/puppeteer/wait_task.rb +188 -0
  158. data/lib/puppeteer/web_socket.rb +122 -0
  159. data/lib/puppeteer/web_socket_transport.rb +49 -0
  160. data/puppeteer-ruby.gemspec +32 -0
  161. metadata +355 -0
@@ -0,0 +1,26 @@
1
+ class Puppeteer::ElementHandle < Puppeteer::JSHandle
2
+ # A class to represent (x, y)-coordinates
3
+ # supporting + and / operators.
4
+ class Point
5
+ def initialize(x:, y:)
6
+ @x = x
7
+ @y = y
8
+ end
9
+
10
+ def +(other)
11
+ Point.new(
12
+ x: @x + other.x,
13
+ y: @y + other.y,
14
+ )
15
+ end
16
+
17
+ def /(num)
18
+ Point.new(
19
+ x: @x / num,
20
+ y: @y / num,
21
+ )
22
+ end
23
+
24
+ attr_reader :x, :y
25
+ end
26
+ end
@@ -0,0 +1,46 @@
1
+ class Puppeteer::EmulationManager
2
+ using Puppeteer::AsyncAwaitBehavior
3
+
4
+ # @param {!Puppeteer.CDPSession} client
5
+ def initialize(client)
6
+ @client = client
7
+ @emulating_mobile = false
8
+ @has_touch = false
9
+ end
10
+
11
+ # @param viewport [Puppeteer::Viewport]
12
+ # @return [true|false]
13
+ def emulate_viewport(viewport)
14
+ mobile = viewport.mobile?
15
+ width = viewport.width
16
+ height = viewport.height
17
+ device_scale_factor = viewport.device_scale_factor
18
+ # /** @type {Protocol.Emulation.ScreenOrientation} */
19
+ # const screenOrientation = viewport.isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' };
20
+ has_touch = viewport.has_touch?
21
+
22
+ await_all(
23
+ @client.async_send_message('Emulation.setDeviceMetricsOverride',
24
+ mobile: mobile,
25
+ width: width,
26
+ height: height,
27
+ deviceScaleFactor: device_scale_factor,
28
+ # screenOrientation: screen_orientation,
29
+ ),
30
+ @client.async_send_message('Emulation.setTouchEmulationEnabled',
31
+ enabled: has_touch,
32
+ ),
33
+ )
34
+
35
+ reload_needed = @emulating_mobile != mobile || @hasTouch != has_touch
36
+ @emulating_mobile = mobile
37
+ @has_touch = has_touch
38
+ reload_needed
39
+ end
40
+
41
+ # @param viewport [Puppeteer::Viewport]
42
+ # @return [Future<true|false>]
43
+ async def async_emulate_viewport(viewport)
44
+ emulate_viewport(viewport)
45
+ end
46
+ end
@@ -0,0 +1,2 @@
1
+ # ref: https://github.com/puppeteer/puppeteer/blob/master/src/Errors.ts
2
+ class Puppeteer::TimeoutError < StandardError; end
@@ -0,0 +1,88 @@
1
+ require 'securerandom'
2
+
3
+ module Puppeteer::EventCallbackable
4
+ class EventListeners
5
+ include Enumerable
6
+
7
+ def initialize
8
+ @listeners = {}
9
+ end
10
+
11
+ # @return [String] Listener ID
12
+ def add(&block)
13
+ id = SecureRandom.hex(8)
14
+ @listeners[id] = block
15
+ id
16
+ end
17
+
18
+ # @param id [String] Listener ID returned on #add
19
+ def delete(id)
20
+ @listeners.delete(id)
21
+ end
22
+
23
+ # @implement Enumerable#each
24
+ def each(&block)
25
+ @listeners.values.each(&block)
26
+ end
27
+ end
28
+
29
+ def add_event_listener(event_name, &block)
30
+ @event_listeners ||= {}
31
+ (@event_listeners[event_name] ||= EventListeners.new).add(&block)
32
+ end
33
+
34
+ def remove_event_listener(*id_args)
35
+ (@event_listeners ||= {}).each do |event_name, listeners|
36
+ id_args.each do |id|
37
+ listeners.delete(id)
38
+ end
39
+ end
40
+ end
41
+
42
+ def on_event(event_name, &block)
43
+ @event_callbackable_handlers ||= {}
44
+ @event_callbackable_handlers[event_name] = block
45
+ end
46
+
47
+ def emit_event(event_name, *args, **kwargs)
48
+ @event_callbackable_handlers ||= {}
49
+ @event_listeners ||= {}
50
+
51
+ if kwargs.empty?
52
+ # In Ruby's specification (version < 2.7),
53
+ # `method(:x).call(*args, **kwargs)` is equivalent to `x(*args, {})`
54
+ # It often causes unexpected ArgumentError.
55
+ #
56
+ # ----------------
57
+ # def greet
58
+ # puts 'Hello!'
59
+ # end
60
+ #
61
+ # def call_me(*args, **kwargs)
62
+ # greet(*args, **kwargs) # => 'Hello!'
63
+ #
64
+ # method(:greet).call(*args, **kwargs) # => `greet': wrong number of arguments (given 1, expected 0) (ArgumentError)
65
+ # end
66
+ #
67
+ # call_me
68
+ # ----------------
69
+ #
70
+ # This behavior is really annoying, and should be avoided, because we often want to set event handler as below:
71
+ #
72
+ # `on_event 'Some.Event.awesome', &method(:handle_awesome_event)`
73
+ #
74
+ # So Let's avoid it by checking kwargs.
75
+ @event_callbackable_handlers[event_name]&.call(*args)
76
+ @event_listeners[event_name]&.each do |proc|
77
+ proc.call(*args)
78
+ end
79
+ else
80
+ @event_callbackable_handlers[event_name]&.call(*args, **kwargs)
81
+ @event_listeners[event_name]&.each do |proc|
82
+ proc.call(*args, **kwargs)
83
+ end
84
+ end
85
+
86
+ event_name
87
+ end
88
+ end
@@ -0,0 +1,254 @@
1
+ class Puppeteer::ExecutionContext
2
+ include Puppeteer::IfPresent
3
+ using Puppeteer::AsyncAwaitBehavior
4
+
5
+ EVALUATION_SCRIPT_URL = '__puppeteer_evaluation_script__'
6
+ SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m
7
+
8
+ # @param client [Puppeteer::CDPSession]
9
+ # @param context_payload [Hash]
10
+ # @param world [Puppeteer::DOMWorld?]
11
+ def initialize(client, context_payload, world)
12
+ @client = client
13
+ @world = world
14
+ @context_id = context_payload['id']
15
+ end
16
+
17
+ attr_reader :client, :world
18
+
19
+ # only used in DomWorld#delete_context
20
+ def _context_id
21
+ @context_id
22
+ end
23
+
24
+ # @return [Puppeteer::Frame]
25
+ def frame
26
+ if_present(@world) do |world|
27
+ world.frame
28
+ end
29
+ end
30
+
31
+ # @param page_function [String]
32
+ # @return [Object]
33
+ def evaluate(page_function, *args)
34
+ evaluate_internal(true, page_function, *args)
35
+ end
36
+
37
+ # @param page_function [String]
38
+ # @return [Puppeteer::JSHandle]
39
+ def evaluate_handle(page_function, *args)
40
+ evaluate_internal(false, page_function, *args)
41
+ end
42
+
43
+ class JavaScriptExpression
44
+ def initialize(execution_context, expression, return_by_value)
45
+ @execution_context = execution_context
46
+ @expression = expression
47
+ @return_by_value = return_by_value
48
+ end
49
+
50
+ # @param client [Puppeteer::CDPSession]
51
+ # @param context_id [String]
52
+ # @return [Object|JSHandle]
53
+ def evaluate_with(client:, context_id:)
54
+ result = client.send_message('Runtime.evaluate',
55
+ expression: expression_with_source_url,
56
+ contextId: context_id,
57
+ returnByValue: @return_by_value,
58
+ awaitPromise: true,
59
+ userGesture: true,
60
+ )
61
+ # }).catch(rewriteError);
62
+
63
+ exception_details = result['exceptionDetails']
64
+ if exception_details
65
+ raise EvaluationError.new("Evaluation failed: #{exception_details}")
66
+ end
67
+
68
+ remote_object = Puppeteer::RemoteObject.new(result['result'])
69
+ if @return_by_value
70
+ remote_object.value
71
+ else
72
+ Puppeteer::JSHandle.create(
73
+ context: @execution_context,
74
+ remote_object: remote_object,
75
+ )
76
+ end
77
+ end
78
+
79
+ private def suffix
80
+ "//# sourceURL=#{EVALUATION_SCRIPT_URL}"
81
+ end
82
+
83
+ private def expression_with_source_url
84
+ if SOURCE_URL_REGEX.match?(@expression)
85
+ @expression
86
+ else
87
+ "#{@expression}\n#{suffix}"
88
+ end
89
+ end
90
+ end
91
+
92
+ class JavaScriptFunction
93
+ include Puppeteer::IfPresent
94
+
95
+ def initialize(execution_context, expression, args, return_by_value)
96
+ @execution_context = execution_context
97
+ @expression = expression
98
+ @return_by_value = return_by_value
99
+ @args = args
100
+ end
101
+
102
+ # @param client [Puppeteer::CDPSession]
103
+ # @param context_id [String]
104
+ # @return [Object|JSHandle]
105
+ def evaluate_with(client:, context_id:)
106
+ # `function` can be omitted in JS after ES2015.
107
+ # https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer
108
+ #
109
+ # Original puppeteer implementation take it into consideration.
110
+ # But we don't support the syntax here.
111
+
112
+ result = client.send_message('Runtime.callFunctionOn',
113
+ functionDeclaration: "#{@expression}\n#{suffix}\n",
114
+ executionContextId: context_id,
115
+ arguments: converted_args,
116
+ returnByValue: @return_by_value,
117
+ awaitPromise: true,
118
+ userGesture: true,
119
+ ) # .catch(rewriteError);
120
+
121
+ exception_details = result['exceptionDetails']
122
+ remote_object = Puppeteer::RemoteObject.new(result['result'])
123
+
124
+ if exception_details
125
+ raise EvaluationError.new("Evaluation failed: #{exception_details}")
126
+ end
127
+
128
+ if @return_by_value
129
+ remote_object.value
130
+ else
131
+ Puppeteer::JSHandle.create(
132
+ context: @execution_context,
133
+ remote_object: remote_object,
134
+ )
135
+ end
136
+ end
137
+
138
+ private def converted_args
139
+ # if (typeof arg === 'bigint') // eslint-disable-line valid-typeof
140
+ # return { unserializableValue: `${arg.toString()}n` };
141
+ # if (Object.is(arg, -0))
142
+ # return { unserializableValue: '-0' };
143
+ # if (Object.is(arg, Infinity))
144
+ # return { unserializableValue: 'Infinity' };
145
+ # if (Object.is(arg, -Infinity))
146
+ # return { unserializableValue: '-Infinity' };
147
+ # if (Object.is(arg, NaN))
148
+ # return { unserializableValue: 'NaN' };
149
+ @args.map do |arg|
150
+ if arg && arg.is_a?(Puppeteer::JSHandle)
151
+ if arg.context != @execution_context
152
+ raise EvaluationError.new('JSHandles can be evaluated only in the context they were created!')
153
+ elsif arg.disposed?
154
+ raise EvaluationError.new('JSHandles is disposed!')
155
+ end
156
+
157
+ arg.remote_object.converted_arg
158
+ else
159
+ { value: arg }
160
+ end
161
+ end
162
+ end
163
+
164
+ # /**
165
+ # * @param {!Error} error
166
+ # * @return {!Protocol.Runtime.evaluateReturnValue}
167
+ # */
168
+ # function rewriteError(error) {
169
+ # if (error.message.includes('Object reference chain is too long'))
170
+ # return {result: {type: 'undefined'}};
171
+ # if (error.message.includes('Object couldn\'t be returned by value'))
172
+ # return {result: {type: 'undefined'}};
173
+
174
+ # if (error.message.endsWith('Cannot find context with specified id') || error.message.endsWith('Inspected target navigated or closed'))
175
+ # throw new Error('Execution context was destroyed, most likely because of a navigation.');
176
+ # throw error;
177
+ # }
178
+
179
+ private def suffix
180
+ "//# sourceURL=#{EVALUATION_SCRIPT_URL}"
181
+ end
182
+ end
183
+
184
+ class EvaluationError < StandardError; end
185
+
186
+ # @param return_by_value [Boolean]
187
+ # @param page_function [String]
188
+ # @return [Object|Puppeteer::JSHandle]
189
+ private def evaluate_internal(return_by_value, page_function, *args)
190
+ # `function` can be omitted in JS after ES2015.
191
+ # https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer
192
+ # But we don't support the syntax here.
193
+ js_object =
194
+ if ['=>', 'async', 'function'].any? { |keyword| page_function.include?(keyword) }
195
+ JavaScriptFunction.new(self, page_function, args, return_by_value)
196
+ else
197
+ JavaScriptExpression.new(self, page_function, return_by_value)
198
+ end
199
+
200
+ js_object.evaluate_with(
201
+ client: @client,
202
+ context_id: @context_id,
203
+ )
204
+ end
205
+
206
+ # /**
207
+ # * @param {!JSHandle} prototypeHandle
208
+ # * @return {!Promise<!JSHandle>}
209
+ # */
210
+ # async queryObjects(prototypeHandle) {
211
+ # assert(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!');
212
+ # assert(prototypeHandle._remoteObject.objectId, 'Prototype JSHandle must not be referencing primitive value');
213
+ # const response = await this._client.send('Runtime.queryObjects', {
214
+ # prototypeObjectId: prototypeHandle._remoteObject.objectId
215
+ # });
216
+ # return createJSHandle(this, response.objects);
217
+ # }
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
+
232
+ # @param element_handle [Puppeteer::ElementHandle]
233
+ # @return [Puppeteer::ElementHandle]
234
+ def adopt_element_handle(element_handle)
235
+ if element_handle.execution_context == self
236
+ raise ArgumentError.new('Cannot adopt handle that already belongs to this execution context')
237
+ end
238
+
239
+ unless @world
240
+ raise 'Cannot adopt handle without DOMWorld'
241
+ end
242
+
243
+ node_info = element_handle.remote_object.node_info(@client)
244
+ response = @client.send_message('DOM.resolveNode',
245
+ backendNodeId: node_info["node"]["backendNodeId"],
246
+ executionContextId: @context_id,
247
+ )
248
+
249
+ Puppeteer::JSHandle.create(
250
+ context: self,
251
+ remote_object: Puppeteer::RemoteObject.new(response["object"]),
252
+ )
253
+ end
254
+ end
@@ -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