puppeteer-ruby 0.0.22 → 0.0.23

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.
@@ -134,7 +134,7 @@ class Puppeteer::DOMWorld
134
134
 
135
135
  # @return [String]
136
136
  def content
137
- evaluate <<-JAVASCRIPT
137
+ evaluate(<<-JAVASCRIPT)
138
138
  () => {
139
139
  let retVal = '';
140
140
  if (document.doctype)
@@ -151,7 +151,7 @@ class Puppeteer::DOMWorld
151
151
  # @param wait_until [String|Array<String>]
152
152
  def set_content(html, timeout: nil, wait_until: nil)
153
153
  option_wait_until = [wait_until || 'load'].flatten
154
- option_timeout = @timeout_settings.navigation_timeout
154
+ option_timeout = timeout || @timeout_settings.navigation_timeout
155
155
 
156
156
  # We rely upon the fact that document.open() will reset frame lifecycle with "init"
157
157
  # lifecycle event. @see https://crrev.com/608658
@@ -31,6 +31,8 @@ module Puppeteer::EventCallbackable
31
31
  (@event_listeners[event_name] ||= EventListeners.new).add(&block)
32
32
  end
33
33
 
34
+ alias_method :on, :add_event_listener
35
+
34
36
  def remove_event_listener(*id_args)
35
37
  (@event_listeners ||= {}).each do |event_name, listeners|
36
38
  id_args.each do |id|
@@ -50,6 +52,8 @@ module Puppeteer::EventCallbackable
50
52
  end
51
53
  end
52
54
 
55
+ alias_method :once, :observe_first
56
+
53
57
  def on_event(event_name, &block)
54
58
  @event_callbackable_handlers ||= {}
55
59
  @event_callbackable_handlers[event_name] = block
@@ -0,0 +1,184 @@
1
+ require 'digest/md5'
2
+
3
+ module EventsDefinitionUtils
4
+ refine Kernel do
5
+ # Symbol is used to prevent external parties listening to these events
6
+ def Symbol(str)
7
+ Digest::MD5.hexdigest(str)
8
+ end
9
+ end
10
+
11
+ refine Hash do
12
+ def define_const_into(target_module)
13
+ each do |key, value|
14
+ target_module.const_set(key, value)
15
+ target_module.define_singleton_method(key) { value }
16
+ end
17
+ keyset = Set.new(keys)
18
+ valueset = Set.new(values)
19
+ target_module.define_singleton_method(:keys) { keyset }
20
+ target_module.define_singleton_method(:values) { valueset }
21
+ end
22
+ end
23
+ end
24
+
25
+ using EventsDefinitionUtils
26
+
27
+ # Internal events that the Connection class emits.
28
+ module ConnectionEmittedEvents ; end
29
+
30
+ {
31
+ Disconnected: Symbol('Connection.Disconnected'),
32
+ }.define_const_into(ConnectionEmittedEvents)
33
+
34
+ # Internal events that the CDPSession class emits.
35
+ module CDPSessionEmittedEvents ; end
36
+
37
+ {
38
+ Disconnected: Symbol('CDPSession.Disconnected'),
39
+ }.define_const_into(CDPSessionEmittedEvents)
40
+
41
+ # All the events a Browser may emit.
42
+ module BrowserEmittedEvents ; end
43
+
44
+ {
45
+ # Emitted when Puppeteer gets disconnected from the Chromium instance. This might happen because of one of the following:
46
+ # - Chromium is closed or crashed
47
+ # - The Browser#disconnect method was called.
48
+ Disconnected: 'disconnected',
49
+
50
+ # Emitted when the url of a target changes. Contains a {@link Target} instance.
51
+ TargetChanged: 'targetchanged',
52
+
53
+ # Emitted when a target is created, for example when a new page is opened by
54
+ # window.open or by Browser#newPage
55
+ # Contains a Target instance.
56
+ TargetCreated: 'targetcreated',
57
+
58
+ # Emitted when a target is destroyed, for example when a page is closed.
59
+ # Contains a Target instance.
60
+ TargetDestroyed: 'targetdestroyed',
61
+ }.define_const_into(BrowserEmittedEvents)
62
+
63
+ module BrowserContextEmittedEvents ; end
64
+
65
+ {
66
+ # Emitted when the url of a target inside the browser context changes.
67
+ # Contains a Target instance.
68
+ TargetChanged: 'targetchanged',
69
+
70
+ # Emitted when a target is created, for example when a new page is opened by
71
+ # window.open or by BrowserContext#newPage
72
+ # Contains a Target instance.
73
+ TargetCreated: 'targetcreated',
74
+
75
+ # Emitted when a target is destroyed within the browser context, for example when a page is closed.
76
+ # Contains a Target instance.
77
+ TargetDestroyed: 'targetdestroyed',
78
+ }.define_const_into(BrowserContextEmittedEvents)
79
+
80
+ # We use symbols to prevent any external parties listening to these events.
81
+ # They are internal to Puppeteer.
82
+ module NetworkManagerEmittedEvents ; end
83
+
84
+ {
85
+ Request: Symbol('NetworkManager.Request'),
86
+ Response: Symbol('NetworkManager.Response'),
87
+ RequestFailed: Symbol('NetworkManager.RequestFailed'),
88
+ RequestFinished: Symbol('NetworkManager.RequestFinished'),
89
+ }.define_const_into(NetworkManagerEmittedEvents)
90
+
91
+
92
+ # We use symbols to prevent external parties listening to these events.
93
+ # They are internal to Puppeteer.
94
+ module FrameManagerEmittedEvents ; end
95
+
96
+ {
97
+ FrameAttached: Symbol('FrameManager.FrameAttached'),
98
+ FrameNavigated: Symbol('FrameManager.FrameNavigated'),
99
+ FrameDetached: Symbol('FrameManager.FrameDetached'),
100
+ LifecycleEvent: Symbol('FrameManager.LifecycleEvent'),
101
+ FrameNavigatedWithinDocument: Symbol('FrameManager.FrameNavigatedWithinDocument'),
102
+ ExecutionContextCreated: Symbol('FrameManager.ExecutionContextCreated'),
103
+ ExecutionContextDestroyed: Symbol('FrameManager.ExecutionContextDestroyed'),
104
+ }.define_const_into(FrameManagerEmittedEvents)
105
+
106
+ # All the events that a page instance may emit.
107
+ module PageEmittedEvents ; end
108
+
109
+ {
110
+ # Emitted when the page closes.
111
+ Close: 'close',
112
+
113
+ # Emitted when JavaScript within the page calls one of console API methods,
114
+ # e.g. `console.log` or `console.dir`. Also emitted if the page throws an
115
+ # error or a warning.
116
+ Console: 'console',
117
+
118
+ # Emitted when a JavaScript dialog appears, such as `alert`, `prompt`,
119
+ # `confirm` or `beforeunload`. Puppeteer can respond to the dialog via
120
+ # Dialog#accept or Dialog#dismiss.
121
+ Dialog: 'dialog',
122
+
123
+ # Emitted when the JavaScript
124
+ # {https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded DOMContentLoaded} event is dispatched.
125
+ DOMContentLoaded: 'domcontentloaded',
126
+
127
+ # Emitted when the page crashes. Will contain an `Error`.
128
+ Error: 'error',
129
+
130
+ # Emitted when a frame is attached. Will contain a Frame.
131
+ FrameAttached: 'frameattached',
132
+ # Emitted when a frame is detached. Will contain a Frame.
133
+ FrameDetached: 'framedetached',
134
+ # Emitted when a frame is navigated to a new URL. Will contain a {@link Frame}.
135
+ FrameNavigated: 'framenavigated',
136
+
137
+ # Emitted when the JavaScript
138
+ # {https://developer.mozilla.org/en-US/docs/Web/Events/load | load} event is dispatched.
139
+ Load: 'load',
140
+
141
+ # Emitted when the JavaScript code makes a call to `console.timeStamp`. For
142
+ # the list of metrics see {@link Page.metrics | page.metrics}.
143
+ #
144
+ # Contains an object with two properties:
145
+ # - `title`: the title passed to `console.timeStamp`
146
+ # - `metrics`: objec containing metrics as key/value pairs. The values will be `number`s.
147
+ Metrics: 'metrics',
148
+
149
+ # Emitted when an uncaught exception happens within the page.
150
+ # Contains an `Error`.
151
+ PageError: 'pageerror',
152
+
153
+ # Emitted when the page opens a new tab or window.
154
+ # Contains a Page corresponding to the popup window.
155
+ Popup: 'popup',
156
+
157
+ # Emitted when a page issues a request and contains a HTTPRequest.
158
+ #
159
+ # The object is readonly. See Page#setRequestInterception for intercepting and mutating requests.
160
+ Request: 'request',
161
+
162
+ # Emitted when a request fails, for example by timing out.
163
+ #
164
+ # Contains a HTTPRequest.
165
+ #
166
+ # NOTE: HTTP Error responses, such as 404 or 503, are still successful
167
+ # responses from HTTP standpoint, so request will complete with
168
+ # `requestfinished` event and not with `requestfailed`.
169
+ RequestFailed: 'requestfailed',
170
+
171
+ # Emitted when a request finishes successfully. Contains a HTTPRequest.
172
+ RequestFinished: 'requestfinished',
173
+
174
+ # Emitted when a response is received. Contains a HTTPResponse.
175
+ Response: 'response',
176
+
177
+ # Emitted when a dedicated
178
+ # {https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API WebWorker} is spawned by the page.
179
+ WorkerCreated: 'workercreated',
180
+
181
+ # Emitted when a dedicated
182
+ # {https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API WebWorker} is destroyed by the page.
183
+ WorkerDestroyed: 'workerdestroyed',
184
+ }.define_const_into(PageEmittedEvents)
@@ -0,0 +1,38 @@
1
+ # Original implementation, helpers.getExceptionMessage
2
+ class Puppeteer::ExceptionDetails
3
+ # @param exception_details [Hash]
4
+ def initialize(exception_details)
5
+ @exception_details = exception_details
6
+ end
7
+
8
+ def message
9
+ # "exceptionDetails"=>{"exceptionId"=>1, "text"=>"Uncaught", "lineNumber"=>12, "columnNumber"=>10, "url"=>"http://127.0.0.1:4567/error.html",
10
+ # "stackTrace"=>{"callFrames"=>[
11
+ # {"functionName"=>"c", "scriptId"=>"6", "url"=>"http://127.0.0.1:4567/error.html", "lineNumber"=>12, "columnNumber"=>10},
12
+ # {"functionName"=>"b", "scriptId"=>"6", "url"=>"http://127.0.0.1:4567/error.html", "lineNumber"=>8, "columnNumber"=>4},
13
+ # {"functionName"=>"a", "scriptId"=>"6", "url"=>"http://127.0.0.1:4567/error.html", "lineNumber"=>4, "columnNumber"=>4},
14
+ # {"functionName"=>"", "scriptId"=>"6", "url"=>"http://127.0.0.1:4567/error.html", "lineNumber"=>1, "columnNumber"=>0}
15
+ # ]},
16
+ # "exception"=>{"type"=>"object", "subtype"=>"error", "className"=>"Error", "description"=>"Error: Fancy error!\n at c (http://127.0.0.1:4567/error.html:13:11)\n at b (http://127.0.0.1:4567/error.html:9:5)\n at a (http://127.0.0.1:4567/error.html:5:5)\n at http://127.0.0.1:4567/error.html:2:1", "objectId"=>"{\"injectedScriptId\":3,\"id\":1}", "preview"=>{"type"=>"object", "subtype"=>"error", "description"=>"Error: Fancy error!\n at c (http://127.0.0.1:4567/error.html:13:11)\n at b (http://127.0.0.1:4567/error.html:9:5)\n at a (http://127.0.0.1:4567/error.html:5:5)\n at http://127.0.0.1:4567/error.html:2:1", "overflow"=>false, "properties"=>[{"name"=>"stack", "type"=>"string", "value"=>"Error: Fancy error!\n at c (http://127.0.0.1:456…:5:5)\n at http://127.0.0.1:4567/error.html:2:1"}, {"name"=>"message", "type"=>"string", "value"=>"Fancy error!"}]}}
17
+ if @exception_details['exception']
18
+ return exception_description_or_value(@exception_details['exception'])
19
+ end
20
+
21
+ messages = []
22
+ messages << @exception_details['text']
23
+
24
+ if @exception_details['stackTrace']
25
+ @exception_details['stackTrace']['callFrames'].each do |call_frame|
26
+ location = "#{call_frame['url']}:#{call_frame['lineNumber']}:#{call_frame['columnNumber']}"
27
+ function_name = call_frame['functionName'] || '<anonymous>'
28
+ messages << "at #{function_name} (#{location})"
29
+ end
30
+ end
31
+
32
+ messages.join("\n ")
33
+ end
34
+
35
+ private def exception_description_or_value(exception)
36
+ exception['description'] || exception['value']
37
+ end
38
+ end
@@ -27,31 +27,31 @@ class Puppeteer::FrameManager
27
27
  # @type {!Set<string>}
28
28
  @isolated_worlds = Set.new
29
29
 
30
- @client.on_event 'Page.frameAttached' do |event|
30
+ @client.on_event('Page.frameAttached') do |event|
31
31
  handle_frame_attached(event['frameId'], event['parentFrameId'])
32
32
  end
33
- @client.on_event 'Page.frameNavigated' do |event|
33
+ @client.on_event('Page.frameNavigated') do |event|
34
34
  handle_frame_navigated(event['frame'])
35
35
  end
36
- @client.on_event 'Page.navigatedWithinDocument' do |event|
36
+ @client.on_event('Page.navigatedWithinDocument') do |event|
37
37
  handle_frame_navigated_within_document(event['frameId'], event['url'])
38
38
  end
39
- @client.on_event 'Page.frameDetached' do |event|
39
+ @client.on_event('Page.frameDetached') do |event|
40
40
  handle_frame_detached(event['frameId'])
41
41
  end
42
- @client.on_event 'Page.frameStoppedLoading' do |event|
42
+ @client.on_event('Page.frameStoppedLoading') do |event|
43
43
  handle_frame_stopped_loading(event['frameId'])
44
44
  end
45
- @client.on_event 'Runtime.executionContextCreated' do |event|
45
+ @client.on_event('Runtime.executionContextCreated') do |event|
46
46
  handle_execution_context_created(event['context'])
47
47
  end
48
- @client.on_event 'Runtime.executionContextDestroyed' do |event|
48
+ @client.on_event('Runtime.executionContextDestroyed') do |event|
49
49
  handle_execution_context_destroyed(event['executionContextId'])
50
50
  end
51
- @client.on_event 'Runtime.executionContextsCleared' do |event|
51
+ @client.on_event('Runtime.executionContextsCleared') do |event|
52
52
  handle_execution_contexts_cleared
53
53
  end
54
- @client.on_event 'Page.lifecycleEvent' do |event|
54
+ @client.on_event('Page.lifecycleEvent') do |event|
55
55
  handle_lifecycle_event(event)
56
56
  end
57
57
  end
@@ -121,6 +121,8 @@ class Puppeteer::FrameManager
121
121
  document_navigation_promise,
122
122
  watcher.timeout_or_termination_promise,
123
123
  )
124
+ rescue Puppeteer::TimeoutError => err
125
+ raise NavigationError.new(err)
124
126
  ensure
125
127
  watcher.dispose
126
128
  end
@@ -143,6 +145,8 @@ class Puppeteer::FrameManager
143
145
  watcher.same_document_navigation_promise,
144
146
  watcher.new_document_navigation_promise,
145
147
  )
148
+ rescue Puppeteer::TimeoutError => err
149
+ raise NavigationError.new(err)
146
150
  ensure
147
151
  watcher.dispose
148
152
  end
@@ -155,7 +159,7 @@ class Puppeteer::FrameManager
155
159
  frame = @frames[event['frameId']]
156
160
  return if !frame
157
161
  frame.handle_lifecycle_event(event['loaderId'], event['name'])
158
- emit_event 'Events.FrameManager.LifecycleEvent', frame
162
+ emit_event(FrameManagerEmittedEvents::LifecycleEvent, frame)
159
163
  end
160
164
 
161
165
  # @param {string} frameId
@@ -163,7 +167,7 @@ class Puppeteer::FrameManager
163
167
  frame = @frames[frame_id]
164
168
  return if !frame
165
169
  frame.handle_loading_stopped
166
- emit_event 'Events.FrameManager.LifecycleEvent', frame
170
+ emit_event(FrameManagerEmittedEvents::LifecycleEvent, frame)
167
171
  end
168
172
 
169
173
  # @param frame_tree [Hash]
@@ -211,7 +215,7 @@ class Puppeteer::FrameManager
211
215
  frame = Puppeteer::Frame.new(self, @client, parent_frame, frame_id)
212
216
  @frames[frame_id] = frame
213
217
 
214
- emit_event 'Events.FrameManager.FrameAttached', frame
218
+ emit_event(FrameManagerEmittedEvents::FrameAttached, frame)
215
219
  end
216
220
 
217
221
  # @param frame_payload [Hash]
@@ -252,7 +256,7 @@ class Puppeteer::FrameManager
252
256
  # Update frame payload.
253
257
  frame.navigated(frame_payload)
254
258
 
255
- emit_event 'Events.FrameManager.FrameNavigated', frame
259
+ emit_event(FrameManagerEmittedEvents::FrameNavigated, frame)
256
260
  end
257
261
 
258
262
  # @param name [String]
@@ -280,8 +284,8 @@ class Puppeteer::FrameManager
280
284
  frame = @frames[frame_id]
281
285
  return unless frame
282
286
  frame.navigated_within_document(url)
283
- emit_event 'Events.FrameManager.FrameNavigatedWithinDocument', frame
284
- emit_event 'Events.FrameManager.FrameNavigated', frame
287
+ emit_event(FrameManagerEmittedEvents::FrameNavigatedWithinDocument, frame)
288
+ emit_event(FrameManagerEmittedEvents::FrameNavigated, frame)
285
289
  end
286
290
 
287
291
  # @param frame_id [String]
@@ -349,7 +353,7 @@ class Puppeteer::FrameManager
349
353
  end
350
354
  frame.detach
351
355
  @frames.delete(frame.id)
352
- emit_event 'Events.FrameManager.FrameDetached', frame
356
+ emit_event(FrameManagerEmittedEvents::FrameDetached, frame)
353
357
  end
354
358
 
355
359
  private def assert_no_legacy_navigation_options(wait_until:)
@@ -0,0 +1,24 @@
1
+ class Puppeteer::Geolocation
2
+ # @param latitude [Fixnum]
3
+ # @param longitude [Fixnum]
4
+ # @param accuracy [Fixnum]
5
+ def initialize(latitude:, longitude:, accuracy: 0)
6
+ unless (-180..180).include?(longitude)
7
+ raise ArgumentError.new("Invalid longitude \"#{longitude}\": precondition -180 <= LONGITUDE <= 180 failed.")
8
+ end
9
+ unless (-90..90).include?(latitude)
10
+ raise ArgumentError.new("Invalid latitude \"#{latitude}\": precondition -90 <= LATITUDE <= 90 failed.")
11
+ end
12
+ if accuracy < 0
13
+ raise ArgumentError.new("Invalid accuracy \"#{longitude}\": precondition 0 <= ACCURACY failed.")
14
+ end
15
+
16
+ @latitude = latitude
17
+ @longitude = longitude
18
+ @accuracy = accuracy
19
+ end
20
+
21
+ def to_h
22
+ { latitude: @latitude, longitude: @longitude, accuracy: @accuracy }
23
+ end
24
+ end
@@ -69,17 +69,17 @@ class Puppeteer::LifecycleWatcher
69
69
  @timeout = timeout
70
70
 
71
71
  @listener_ids = {}
72
- @listener_ids['client'] = @frame_manager.client.add_event_listener('Events.CDPSession.Disconnected') do
72
+ @listener_ids['client'] = @frame_manager.client.add_event_listener(CDPSessionEmittedEvents::Disconnected) do
73
73
  terminate(TerminatedError.new('Navigation failed because browser has disconnected!'))
74
74
  end
75
75
  @listener_ids['frame_manager'] = [
76
- @frame_manager.add_event_listener('Events.FrameManager.LifecycleEvent') do |_|
76
+ @frame_manager.add_event_listener(FrameManagerEmittedEvents::LifecycleEvent) do |_|
77
77
  check_lifecycle_complete
78
78
  end,
79
- @frame_manager.add_event_listener('Events.FrameManager.FrameNavigatedWithinDocument', &method(:navigated_within_document)),
80
- @frame_manager.add_event_listener('Events.FrameManager.FrameDetached', &method(:handle_frame_detached)),
79
+ @frame_manager.add_event_listener(FrameManagerEmittedEvents::FrameNavigatedWithinDocument, &method(:navigated_within_document)),
80
+ @frame_manager.add_event_listener(FrameManagerEmittedEvents::FrameDetached, &method(:handle_frame_detached)),
81
81
  ]
82
- @listener_ids['network_manager'] = @frame_manager.network_manager.add_event_listener('Events.NetworkManager.Request', &method(:handle_request))
82
+ @listener_ids['network_manager'] = @frame_manager.network_manager.add_event_listener(NetworkManagerEmittedEvents::Request, &method(:handle_request))
83
83
 
84
84
  @same_document_navigation_promise = resolvable_future
85
85
  @lifecycle_promise = resolvable_future
@@ -128,7 +128,7 @@ class Puppeteer::LifecycleWatcher
128
128
  @termination_promise.value!
129
129
  end
130
130
  rescue Timeout::Error
131
- raise Puppeteer::FrameManager::NavigationError.new("Navigation timeout of #{@timeout}ms exceeded")
131
+ raise Puppeteer::TimeoutError.new("Navigation timeout of #{@timeout}ms exceeded")
132
132
  end
133
133
  else
134
134
  @termination_promise
@@ -212,7 +212,7 @@ class Puppeteer::NetworkManager
212
212
  frame = if_present(event['frameId']) { |frame_id| @frame_manager.frame(frame_id) }
213
213
  request = Puppeteer::Request.new(@client, frame, interception_id, @user_request_interception_enabled, event, redirect_chain)
214
214
  @request_id_to_request[event['requestId']] = request
215
- emit_event 'Events.NetworkManager.Request', request
215
+ emit_event(NetworkManagerEmittedEvents::Request, request)
216
216
  end
217
217
 
218
218
  private def handle_request_served_from_cache(event)
@@ -230,8 +230,8 @@ class Puppeteer::NetworkManager
230
230
  response.internal.body_loaded_promise.reject(Puppeteer::Response::Redirected.new)
231
231
  @request_id_to_request.delete(request.internal.request_id)
232
232
  @attempted_authentications.delete(request.internal.interception_id)
233
- emit_event 'Events.NetworkManager.Response', response
234
- emit_event 'Events.NetworkManager.RequestFinished', request
233
+ emit_event(NetworkManagerEmittedEvents::Response, response)
234
+ emit_event(NetworkManagerEmittedEvents::RequestFinished, request)
235
235
  end
236
236
 
237
237
  # @param event [Hash]
@@ -242,7 +242,7 @@ class Puppeteer::NetworkManager
242
242
 
243
243
  response = Puppeteer::Response.new(@client, request, event['response'])
244
244
  request.internal.response = response
245
- emit_event 'Events.NetworkManager.Response', response
245
+ emit_event(NetworkManagerEmittedEvents::Response, response)
246
246
  end
247
247
 
248
248
  private def handle_loading_finished(event)
@@ -260,7 +260,7 @@ class Puppeteer::NetworkManager
260
260
 
261
261
  @request_id_to_request.delete(request.internal.request_id)
262
262
  @attempted_authentications.delete(request.internal.interception_id)
263
- emit_event 'Events.NetworkManager.RequestFinished', request
263
+ emit_event(NetworkManagerEmittedEvents::RequestFinished, request)
264
264
  end
265
265
 
266
266
  private def handle_loading_failed(event)
@@ -275,6 +275,6 @@ class Puppeteer::NetworkManager
275
275
  end
276
276
  @request_id_to_request.delete(request.internal.request_id)
277
277
  @attempted_authentications.delete(request.internal.interception_id)
278
- emit_event 'Events.NetworkManager.RequestFailed', request
278
+ emit_event(NetworkManagerEmittedEvents::RequestFailed, request)
279
279
  end
280
280
  end