puppeteer-ruby 0.0.20 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -89,7 +89,7 @@ class Puppeteer::Keyboard
89
89
  'Digit6': KeyDefinition.new({ 'keyCode': 54, 'code': 'Digit6', 'shiftKey': '^', 'key': '6' }),
90
90
  'Digit7': KeyDefinition.new({ 'keyCode': 55, 'code': 'Digit7', 'shiftKey': '&', 'key': '7' }),
91
91
  'Digit8': KeyDefinition.new({ 'keyCode': 56, 'code': 'Digit8', 'shiftKey': '*', 'key': '8' }),
92
- 'Digit9': KeyDefinition.new({ 'keyCode': 57, 'code': 'Digit9', 'shiftKey': '\(', 'key': '9' }),
92
+ 'Digit9': KeyDefinition.new({ 'keyCode': 57, 'code': 'Digit9', 'shiftKey': '(', 'key': '9' }),
93
93
  'KeyA': KeyDefinition.new({ 'keyCode': 65, 'code': 'KeyA', 'shiftKey': 'A', 'key': 'a' }),
94
94
  'KeyB': KeyDefinition.new({ 'keyCode': 66, 'code': 'KeyB', 'shiftKey': 'B', 'key': 'b' }),
95
95
  'KeyC': KeyDefinition.new({ 'keyCode': 67, 'code': 'KeyC', 'shiftKey': 'C', 'key': 'c' }),
@@ -235,7 +235,7 @@ class Puppeteer::Keyboard
235
235
  '%': KeyDefinition.new({ 'keyCode': 53, 'key': '%', 'code': 'Digit5' }),
236
236
  '^': KeyDefinition.new({ 'keyCode': 54, 'key': '^', 'code': 'Digit6' }),
237
237
  '&': KeyDefinition.new({ 'keyCode': 55, 'key': '&', 'code': 'Digit7' }),
238
- '(': KeyDefinition.new({ 'keyCode': 57, 'key': '\(', 'code': 'Digit9' }),
238
+ '(': KeyDefinition.new({ 'keyCode': 57, 'key': '(', 'code': 'Digit9' }),
239
239
  'A': KeyDefinition.new({ 'keyCode': 65, 'key': 'A', 'code': 'KeyA' }),
240
240
  'B': KeyDefinition.new({ 'keyCode': 66, 'key': 'B', 'code': 'KeyB' }),
241
241
  'C': KeyDefinition.new({ 'keyCode': 67, 'key': 'C', 'code': 'KeyC' }),
@@ -23,7 +23,6 @@ module Puppeteer::Launcher
23
23
  preferred_revision: preferred_revision,
24
24
  is_puppeteer_core: is_puppeteer_core,
25
25
  )
26
- raise NotImplementedError.new('FirefoxLauncher is not implemented yet.')
27
26
  end
28
27
 
29
28
  Chrome.new(
@@ -28,7 +28,8 @@ module Puppeteer::Launcher
28
28
  # @property {number=} slowMo
29
29
  def initialize(options)
30
30
  @ignore_https_errors = options[:ignore_https_errors] || false
31
- @default_viewport = options[:default_viewport] || Puppeteer::Viewport.new(width: 800, height: 600)
31
+ # `default_viewport: nil` must be respected here.
32
+ @default_viewport = options.key?(:default_viewport) ? options[:default_viewport] : Puppeteer::Viewport.new(width: 800, height: 600)
32
33
  @slow_mo = options[:slow_mo] || 0
33
34
  end
34
35
 
@@ -12,9 +12,9 @@ module Puppeteer::Launcher
12
12
 
13
13
  chrome_arguments =
14
14
  if !@launch_options.ignore_default_args
15
- default_args.to_a
15
+ default_args(options).to_a
16
16
  elsif @launch_options.ignore_default_args.is_a?(Enumerable)
17
- default_args.reject do |arg|
17
+ default_args(options).reject do |arg|
18
18
  @launch_options.ignore_default_args.include?(arg)
19
19
  end.to_a
20
20
  else
@@ -141,11 +141,7 @@ module Puppeteer::Launcher
141
141
 
142
142
  # @return [DefaultArgs]
143
143
  def default_args(options = nil)
144
- if options.nil?
145
- @default_args ||= DefaultArgs.new(@chrome_arg_options)
146
- else
147
- DefaultArgs.new(ChromeArgOptions.new(options))
148
- end
144
+ DefaultArgs.new(ChromeArgOptions.new(options || {}))
149
145
  end
150
146
 
151
147
  # @return [Puppeteer::Browser]
@@ -206,7 +202,7 @@ module Puppeteer::Launcher
206
202
  resolve_executable_path
207
203
  end
208
204
 
209
- private def product
205
+ def product
210
206
  'chrome'
211
207
  end
212
208
  end