puppeteer-ruby 0.0.19 → 0.0.25

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.
@@ -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
@@ -12,9 +12,9 @@ module Puppeteer::Launcher
12
12
 
13
13
  firefox_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
@@ -127,7 +127,7 @@ module Puppeteer::Launcher
127
127
  resolve_executable_path
128
128
  end
129
129
 
130
- private def product
130
+ def product
131
131
  'firefox'
132
132
  end
133
133
 
@@ -173,11 +173,7 @@ module Puppeteer::Launcher
173
173
 
174
174
  # @return [DefaultArgs]
175
175
  def default_args(options = nil)
176
- if options.nil?
177
- @default_args ||= DefaultArgs.new(@chrome_arg_options)
178
- else
179
- DefaultArgs.new(ChromeArgOptions.new(options))
180
- end
176
+ DefaultArgs.new(ChromeArgOptions.new(options || {}))
181
177
  end
182
178
 
183
179
  private def create_profile(extra_prefs = {})
@@ -203,7 +199,7 @@ module Puppeteer::Launcher
203
199
  # https://bugzilla.mozilla.org/show_bug.cgi?id=1543115
204
200
  'browser.dom.window.dump.enabled': true,
205
201
  # Disable topstories
206
- 'browser.newtabpage.activity-stream.feeds.section.topstories': false,
202
+ 'browser.newtabpage.activity-stream.feeds.system.topstories': false,
207
203
  # Always display a blank page
208
204
  'browser.newtabpage.enabled': false,
209
205
  # Background thumbnails in particular cause grief: and disabling
@@ -250,16 +246,15 @@ module Puppeteer::Launcher
250
246
  # Do not warn on quitting Firefox
251
247
  'browser.warnOnQuit': false,
252
248
 
253
- # Do not show datareporting policy notifications which can
254
- # interfere with tests
255
- 'datareporting.healthreport.about.reportUrl': "http://#{server}/dummy/abouthealthreport/",
249
+ # Defensively disable data reporting systems
256
250
  'datareporting.healthreport.documentServerURI': "http://#{server}/dummy/healthreport/",
257
251
  'datareporting.healthreport.logging.consoleEnabled': false,
258
252
  'datareporting.healthreport.service.enabled': false,
259
253
  'datareporting.healthreport.service.firstRun': false,
260
254
  'datareporting.healthreport.uploadEnabled': false,
255
+
256
+ # Do not show datareporting policy notifications which can interfere with tests
261
257
  'datareporting.policy.dataSubmissionEnabled': false,
262
- 'datareporting.policy.dataSubmissionPolicyAccepted': false,
263
258
  'datareporting.policy.dataSubmissionPolicyBypassNotification': true,
264
259
 
265
260
  # DevTools JSONViewer sometimes fails to load dependencies with its require.js.
@@ -372,8 +367,6 @@ module Puppeteer::Launcher
372
367
  # Disable browser animations (tabs, fullscreen, sliding alerts)
373
368
  'toolkit.cosmeticAnimations.enabled': false,
374
369
 
375
- # We want to collect telemetry, but we don't want to send in the results
376
- 'toolkit.telemetry.server': "https://#{server}/dummy/telemetry/",
377
370
  # Prevent starting into safe mode after application crashes
378
371
  'toolkit.startup.max_resumed_crashes': -1,
379
372
  }
@@ -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
@@ -46,7 +46,7 @@ class Puppeteer::Page
46
46
  @screenshot_task_queue = screenshot_task_queue
47
47
 
48
48
  @workers = {}
49
- @client.on_event 'Target.attachedToTarget' do |event|
49
+ @client.on_event('Target.attachedToTarget') do |event|
50
50
  if event['targetInfo']['type'] != 'worker'
51
51
  # If we don't detach from service workers, they will never die.
52
52
  await @client.send_message('Target.detachFromTarget', sessionId: event['sessionId'])
@@ -56,63 +56,69 @@ class Puppeteer::Page
56
56
  session = Puppeteer::Connection.from_session(@client).session(event['sessionId']) # rubocop:disable Lint/UselessAssignment
57
57
  # const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this));
58
58
  # this._workers.set(event.sessionId, worker);
59
- # this.emit(Events.Page.WorkerCreated, worker);
59
+ # this.emit(PageEmittedEvents::WorkerCreated, worker);
60
60
  end
61
- @client.on_event 'Target.detachedFromTarget' do |event|
61
+ @client.on_event('Target.detachedFromTarget') do |event|
62
62
  session_id = event['sessionId']
63
63
  worker = @workers[session_id]
64
64
  next unless worker
65
65
 
66
- emit_event('Events.Page.WorkerDestroyed', worker)
66
+ emit_event(PageEmittedEvents::WorkerDestroyed, worker)
67
67
  @workers.delete(session_id)
68
68
  end
69
69
 
70
- @frame_manager.on_event 'Events.FrameManager.FrameAttached' do |event|
71
- emit_event 'Events.Page.FrameAttached', event
70
+ @frame_manager.on_event(FrameManagerEmittedEvents::FrameAttached) do |event|
71
+ emit_event(PageEmittedEvents::FrameAttached, event)
72
72
  end
73
- @frame_manager.on_event 'Events.FrameManager.FrameDetached' do |event|
74
- emit_event 'Events.Page.FrameDetached', event
73
+ @frame_manager.on_event(FrameManagerEmittedEvents::FrameDetached) do |event|
74
+ emit_event(PageEmittedEvents::FrameDetached, event)
75
75
  end
76
- @frame_manager.on_event 'Events.FrameManager.FrameNavigated' do |event|
77
- emit_event 'Events.Page.FrameNavigated', event
76
+ @frame_manager.on_event(FrameManagerEmittedEvents::FrameNavigated) do |event|
77
+ emit_event(PageEmittedEvents::FrameNavigated, event)
78
78
  end
79
79
 
80
80
  network_manager = @frame_manager.network_manager
81
- network_manager.on_event 'Events.NetworkManager.Request' do |event|
82
- emit_event 'Events.Page.Request', event
81
+ network_manager.on_event(NetworkManagerEmittedEvents::Request) do |event|
82
+ emit_event(PageEmittedEvents::Request, event)
83
83
  end
84
- network_manager.on_event 'Events.NetworkManager.Response' do |event|
85
- emit_event 'Events.Page.Response', event
84
+ network_manager.on_event(NetworkManagerEmittedEvents::Response) do |event|
85
+ emit_event(PageEmittedEvents::Response, event)
86
86
  end
87
- network_manager.on_event 'Events.NetworkManager.RequestFailed' do |event|
88
- emit_event 'Events.Page.RequestFailed', event
87
+ network_manager.on_event(NetworkManagerEmittedEvents::RequestFailed) do |event|
88
+ emit_event(PageEmittedEvents::RequestFailed, event)
89
89
  end
90
- network_manager.on_event 'Events.NetworkManager.RequestFinished' do |event|
91
- emit_event 'Events.Page.RequestFinished', event
90
+ network_manager.on_event(NetworkManagerEmittedEvents::RequestFinished) do |event|
91
+ emit_event(PageEmittedEvents::RequestFinished, event)
92
92
  end
93
93
  @file_chooser_interception_is_disabled = false
94
94
  @file_chooser_interceptors = Set.new
95
95
 
96
- @client.on_event 'Page.domContentEventFired' do |event|
97
- emit_event 'Events.Page.DOMContentLoaded'
96
+ @client.on_event('Page.domContentEventFired') do |event|
97
+ emit_event(PageEmittedEvents::DOMContentLoaded)
98
98
  end
99
- @client.on_event 'Page.loadEventFired' do |event|
100
- emit_event 'Events.Page.Load'
99
+ @client.on_event('Page.loadEventFired') do |event|
100
+ emit_event(PageEmittedEvents::Load)
101
101
  end
102
102
  # client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
103
103
  # client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
104
- # client.on('Page.javascriptDialogOpening', event => this._onDialog(event));
105
- # client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
106
- # client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
104
+ @client.on_event('Page.javascriptDialogOpening') do |event|
105
+ handle_dialog_opening(event)
106
+ end
107
+ @client.on_event('Runtime.exceptionThrown') do |exception|
108
+ handle_exception(exception['exceptionDetails'])
109
+ end
110
+ @client.on_event('Inspector.targetCrashed') do |event|
111
+ handle_target_crashed
112
+ end
107
113
  # client.on('Performance.metrics', event => this._emitMetrics(event));
108
- @client.on_event 'Log.entryAdded' do |event|
114
+ @client.on_event('Log.entryAdded') do |event|
109
115
  handle_log_entry_added(event)
110
116
  end
111
- @client.on_event 'Page.fileChooserOpened' do |event|
117
+ @client.on_event('Page.fileChooserOpened') do |event|
112
118
  handle_file_chooser(event)
113
119
  end
114
120
  @target.is_closed_promise.then do
115
- emit_event 'Events.Page.Close'
121
+ emit_event(PageEmittedEvents::Close)
116
122
  @closed = true
117
123
  end
118
124
  end
@@ -126,43 +132,22 @@ class Puppeteer::Page
126
132
  )
127
133
  end
128
134
 
129
- EVENT_MAPPINGS = {
130
- close: 'Events.Page.Close',
131
- # console: 'Events.Page.Console',
132
- # dialog: 'Events.Page.Dialog',
133
- domcontentloaded: 'Events.Page.DOMContentLoaded',
134
- # error:
135
- frameattached: 'Events.Page.FrameAttached',
136
- framedetached: 'Events.Page.FrameDetached',
137
- framenavigated: 'Events.Page.FrameNavigated',
138
- load: 'Events.Page.Load',
139
- # metrics: 'Events.Page.Metrics',
140
- # pageerror: 'Events.Page.PageError',
141
- popup: 'Events.Page.Popup',
142
- request: 'Events.Page.Request',
143
- requestfailed: 'Events.Page.RequestFailed',
144
- requestfinished: 'Events.Page.RequestFinished',
145
- response: 'Events.Page.Response',
146
- # workercreated: 'Events.Page.WorkerCreated',
147
- # workerdestroyed: 'Events.Page.WorkerDestroyed',
148
- }
149
-
150
135
  # @param event_name [Symbol]
151
136
  def on(event_name, &block)
152
- unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
153
- raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
137
+ unless PageEmittedEvents.values.include?(event_name.to_s)
138
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}")
154
139
  end
155
140
 
156
- add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block)
141
+ super(event_name.to_s, &block)
157
142
  end
158
143
 
159
144
  # @param event_name [Symbol]
160
145
  def once(event_name, &block)
161
- unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
162
- raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
146
+ unless PageEmittedEvents.values.include?(event_name.to_s)
147
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}")
163
148
  end
164
149
 
165
- observe_first(EVENT_MAPPINGS[event_name.to_sym], &block)
150
+ super(event_name.to_s, &block)
166
151
  end
167
152
 
168
153
  def handle_file_chooser(event)
@@ -209,19 +194,10 @@ class Puppeteer::Page
209
194
 
210
195
  define_async_method :async_wait_for_file_chooser
211
196
 
212
- # /**
213
- # * @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}} options
214
- # */
215
- # async setGeolocation(options) {
216
- # const { longitude, latitude, accuracy = 0} = options;
217
- # if (longitude < -180 || longitude > 180)
218
- # throw new Error(`Invalid longitude "${longitude}": precondition -180 <= LONGITUDE <= 180 failed.`);
219
- # if (latitude < -90 || latitude > 90)
220
- # throw new Error(`Invalid latitude "${latitude}": precondition -90 <= LATITUDE <= 90 failed.`);
221
- # if (accuracy < 0)
222
- # throw new Error(`Invalid accuracy "${accuracy}": precondition 0 <= ACCURACY failed.`);
223
- # await this._client.send('Emulation.setGeolocationOverride', {longitude, latitude, accuracy});
224
- # }
197
+ # @param [Puppeteer::Geolocation]
198
+ def geolocation=(geolocation)
199
+ @client.send_message('Emulation.setGeolocationOverride', geolocation.to_h)
200
+ end
225
201
 
226
202
  attr_reader :javascript_enabled, :target
227
203
 
@@ -236,7 +212,7 @@ class Puppeteer::Page
236
212
  class TargetCrashedError < StandardError; end
237
213
 
238
214
  private def handle_target_crashed
239
- emit_event 'error', TargetCrashedError.new('Page crashed!')
215
+ emit_event(PageEmittedEvents::Error, TargetCrashedError.new('Page crashed!'))
240
216
  end
241
217
 
242
218
  private def handle_log_entry_added(event)
@@ -257,7 +233,7 @@ class Puppeteer::Page
257
233
  url: url,
258
234
  line_number: line_number,
259
235
  )
260
- emit_event('Events.Page.Console',
236
+ emit_event(PageEmittedEvents::Console,
261
237
  Puppeteer::ConsoleMessage.new(level, text, [], console_message_location))
262
238
  end
263
239
  end
@@ -365,47 +341,34 @@ class Puppeteer::Page
365
341
 
366
342
  define_async_method :async_Sx
367
343
 
368
- # /**
369
- # * @param {!Array<string>} urls
370
- # * @return {!Promise<!Array<Network.Cookie>>}
371
- # */
372
- # async cookies(...urls) {
373
- # return (await this._client.send('Network.getCookies', {
374
- # urls: urls.length ? urls : [this.url()]
375
- # })).cookies;
376
- # }
344
+ # @return [Array<Hash>]
345
+ def cookies(*urls)
346
+ @client.send_message('Network.getCookies', urls: (urls.empty? ? [url] : urls))['cookies']
347
+ end
377
348
 
378
- # /**
379
- # * @param {Array<Protocol.Network.deleteCookiesParameters>} cookies
380
- # */
381
- # async deleteCookie(...cookies) {
382
- # const pageURL = this.url();
383
- # for (const cookie of cookies) {
384
- # const item = Object.assign({}, cookie);
385
- # if (!cookie.url && pageURL.startsWith('http'))
386
- # item.url = pageURL;
387
- # await this._client.send('Network.deleteCookies', item);
388
- # }
389
- # }
349
+ def delete_cookie(*cookies)
350
+ page_url = url
351
+ starts_with_http = page_url.start_with?("http")
352
+ cookies.each do |cookie|
353
+ item = (starts_with_http ? { url: page_url } : {}).merge(cookie)
354
+ @client.send_message("Network.deleteCookies", item)
355
+ end
356
+ end
390
357
 
391
- # /**
392
- # * @param {Array<Network.CookieParam>} cookies
393
- # */
394
- # async setCookie(...cookies) {
395
- # const pageURL = this.url();
396
- # const startsWithHTTP = pageURL.startsWith('http');
397
- # const items = cookies.map(cookie => {
398
- # const item = Object.assign({}, cookie);
399
- # if (!item.url && startsWithHTTP)
400
- # item.url = pageURL;
401
- # assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`);
402
- # assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`);
403
- # return item;
404
- # });
405
- # await this.deleteCookie(...items);
406
- # if (items.length)
407
- # await this._client.send('Network.setCookies', { cookies: items });
408
- # }
358
+ def set_cookie(*cookies)
359
+ page_url = url
360
+ starts_with_http = page_url.start_with?("http")
361
+ items = cookies.map do |cookie|
362
+ (starts_with_http ? { url: page_url } : {}).merge(cookie).tap do |item|
363
+ raise ArgumentError.new("Blank page can not have cookie \"#{item[:name]}\"") if item[:url] == "about:blank"
364
+ raise ArgumetnError.new("Data URL page can not have cookie \"#{item[:name]}\"") if item[:url]&.start_with?("data:")
365
+ end
366
+ end
367
+ delete_cookie(*items)
368
+ unless items.empty?
369
+ @client.send_message("Network.setCookies", cookies: items)
370
+ end
371
+ end
409
372
 
410
373
  class ScriptTag
411
374
  # @param {!{content?: string, path?: string, type?: string, url?: string}} options
@@ -500,7 +463,7 @@ class Puppeteer::Page
500
463
  # * @param {!Protocol.Performance.metricsPayload} event
501
464
  # */
502
465
  # _emitMetrics(event) {
503
- # this.emit(Events.Page.Metrics, {
466
+ # this.emit(PageEmittedEvents::Metrics, {
504
467
  # title: event.title,
505
468
  # metrics: this._buildMetricsObject(event.metrics)
506
469
  # });
@@ -519,15 +482,14 @@ class Puppeteer::Page
519
482
  # return result;
520
483
  # }
521
484
 
522
- # /**
523
- # * @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails
524
- # */
525
- # _handleException(exceptionDetails) {
526
- # const message = helper.getExceptionMessage(exceptionDetails);
527
- # const err = new Error(message);
528
- # err.stack = ''; // Don't report clientside error with a node stack attached
529
- # this.emit(Events.Page.PageError, err);
530
- # }
485
+ class PageError < StandardError ; end
486
+
487
+ private def handle_exception(exception_details)
488
+ message = Puppeteer::ExceptionDetails.new(exception_details).message
489
+ err = PageError.new(message)
490
+ # err.stack = ''; // Don't report clientside error with a node stack attached
491
+ emit_event(PageEmittedEvents::PageError, err)
492
+ end
531
493
 
532
494
  # /**
533
495
  # * @param {!Protocol.Runtime.consoleAPICalledPayload} event
@@ -611,7 +573,7 @@ class Puppeteer::Page
611
573
  # * @param {Protocol.Runtime.StackTrace=} stackTrace
612
574
  # */
613
575
  # _addConsoleMessage(type, args, stackTrace) {
614
- # if (!this.listenerCount(Events.Page.Console)) {
576
+ # if (!this.listenerCount(PageEmittedEvents::Console)) {
615
577
  # args.forEach(arg => arg.dispose());
616
578
  # return;
617
579
  # }
@@ -629,23 +591,20 @@ class Puppeteer::Page
629
591
  # columnNumber: stackTrace.callFrames[0].columnNumber,
630
592
  # } : {};
631
593
  # const message = new ConsoleMessage(type, textTokens.join(' '), args, location);
632
- # this.emit(Events.Page.Console, message);
594
+ # this.emit(PageEmittedEvents::Console, message);
633
595
  # }
634
596
 
635
- # _onDialog(event) {
636
- # let dialogType = null;
637
- # if (event.type === 'alert')
638
- # dialogType = Dialog.Type.Alert;
639
- # else if (event.type === 'confirm')
640
- # dialogType = Dialog.Type.Confirm;
641
- # else if (event.type === 'prompt')
642
- # dialogType = Dialog.Type.Prompt;
643
- # else if (event.type === 'beforeunload')
644
- # dialogType = Dialog.Type.BeforeUnload;
645
- # assert(dialogType, 'Unknown javascript dialog type: ' + event.type);
646
- # const dialog = new Dialog(this._client, dialogType, event.message, event.defaultPrompt);
647
- # this.emit(Events.Page.Dialog, dialog);
648
- # }
597
+ private def handle_dialog_opening(event)
598
+ dialog_type = event['type']
599
+ unless %w(alert confirm prompt beforeunload).include?(dialog_type)
600
+ raise ArgumentError.new("Unknown javascript dialog type: #{dialog_type}")
601
+ end
602
+ dialog = Puppeteer::Dialog.new(@client,
603
+ type: dialog_type,
604
+ message: event['message'],
605
+ default_value: event['defaultPrompt'])
606
+ emit_event(PageEmittedEvents::Dialog, dialog)
607
+ end
649
608
 
650
609
  # @return [String]
651
610
  def url
@@ -727,7 +686,7 @@ class Puppeteer::Page
727
686
 
728
687
  private def session_close_promise
729
688
  @disconnect_promise ||= resolvable_future do |future|
730
- @client.observe_first('Events.CDPSession.Disconnected') do
689
+ @client.observe_first(CDPSessionEmittedEvents::Disconnected) do
731
690
  future.reject(Puppeteer::CDPSession::Error.new('Target Closed'))
732
691
  end
733
692
  end
@@ -747,7 +706,7 @@ class Puppeteer::Page
747
706
  -> (request) { predicate.call(request) }
748
707
  end
749
708
 
750
- wait_for_network_manager_event('Events.NetworkManager.Request',
709
+ wait_for_network_manager_event(NetworkManagerEmittedEvents::Request,
751
710
  predicate: request_predicate,
752
711
  timeout: timeout,
753
712
  )
@@ -781,7 +740,7 @@ class Puppeteer::Page
781
740
  -> (response) { predicate.call(response) }
782
741
  end
783
742
 
784
- wait_for_network_manager_event('Events.NetworkManager.Response',
743
+ wait_for_network_manager_event(NetworkManagerEmittedEvents::Response,
785
744
  predicate: response_predicate,
786
745
  timeout: timeout,
787
746
  )
@@ -940,16 +899,16 @@ class Puppeteer::Page
940
899
  clip = { x: 0, y: 0, width: width, height: height, scale: 1 }
941
900
 
942
901
  screen_orientation =
943
- if @viewport.landscape?
902
+ if @viewport&.landscape?
944
903
  { angle: 90, type: 'landscapePrimary' }
945
904
  else
946
905
  { angle: 0, type: 'portraitPrimary' }
947
906
  end
948
907
  @client.send_message('Emulation.setDeviceMetricsOverride',
949
- mobile: @viewport.mobile?,
908
+ mobile: @viewport&.mobile? || false,
950
909
  width: width,
951
910
  height: height,
952
- deviceScaleFactor: @viewport.device_scale_factor,
911
+ deviceScaleFactor: @viewport&.device_scale_factor || 1,
953
912
  screenOrientation: screen_orientation)
954
913
  end
955
914
 
@@ -1044,6 +1003,12 @@ class Puppeteer::Page
1044
1003
  else
1045
1004
  @client.connection.send_message('Target.closeTarget', targetId: @target.target_id)
1046
1005
  await @target.is_closed_promise
1006
+
1007
+ # @closed sometimes remains false, so wait for @closed = true with 100ms timeout.
1008
+ 25.times do
1009
+ break if @closed
1010
+ sleep 0.004
1011
+ end
1047
1012
  end
1048
1013
  end
1049
1014