puppeteer-ruby 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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