puppeteer-ruby 0.0.19 → 0.0.25

Sign up to get free protection for your applications and to get access to all the features.
@@ -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