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.
@@ -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
@@ -3,6 +3,7 @@ require "stringio"
3
3
 
4
4
  require_relative './page/pdf_options'
5
5
  require_relative './page/screenshot_options'
6
+ require_relative './page/screenshot_task_queue'
6
7
 
7
8
  class Puppeteer::Page
8
9
  include Puppeteer::EventCallbackable
@@ -13,10 +14,9 @@ class Puppeteer::Page
13
14
  # @param {!Puppeteer.Target} target
14
15
  # @param {boolean} ignoreHTTPSErrors
15
16
  # @param {?Puppeteer.Viewport} defaultViewport
16
- # @param {!Puppeteer.TaskQueue} screenshotTaskQueue
17
17
  # @return {!Promise<!Page>}
18
- def self.create(client, target, ignore_https_errors, default_viewport, screenshot_task_queue)
19
- page = Puppeteer::Page.new(client, target, ignore_https_errors, screenshot_task_queue)
18
+ def self.create(client, target, ignore_https_errors, default_viewport)
19
+ page = Puppeteer::Page.new(client, target, ignore_https_errors)
20
20
  page.init
21
21
  if default_viewport
22
22
  page.viewport = default_viewport
@@ -27,8 +27,7 @@ class Puppeteer::Page
27
27
  # @param {!Puppeteer.CDPSession} client
28
28
  # @param {!Puppeteer.Target} target
29
29
  # @param {boolean} ignoreHTTPSErrors
30
- # @param {!Puppeteer.TaskQueue} screenshotTaskQueue
31
- def initialize(client, target, ignore_https_errors, screenshot_task_queue)
30
+ def initialize(client, target, ignore_https_errors)
32
31
  @closed = false
33
32
  @client = client
34
33
  @target = target
@@ -43,10 +42,10 @@ class Puppeteer::Page
43
42
  @page_bindings = {}
44
43
  # @coverage = Coverage.new(client)
45
44
  @javascript_enabled = true
46
- @screenshot_task_queue = screenshot_task_queue
45
+ @screenshot_task_queue = ScreenshotTaskQueue.new
47
46
 
48
47
  @workers = {}
49
- @client.on_event 'Target.attachedToTarget' do |event|
48
+ @client.on_event('Target.attachedToTarget') do |event|
50
49
  if event['targetInfo']['type'] != 'worker'
51
50
  # If we don't detach from service workers, they will never die.
52
51
  await @client.send_message('Target.detachFromTarget', sessionId: event['sessionId'])
@@ -56,65 +55,69 @@ class Puppeteer::Page
56
55
  session = Puppeteer::Connection.from_session(@client).session(event['sessionId']) # rubocop:disable Lint/UselessAssignment
57
56
  # const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this));
58
57
  # this._workers.set(event.sessionId, worker);
59
- # this.emit(Events.Page.WorkerCreated, worker);
58
+ # this.emit(PageEmittedEvents::WorkerCreated, worker);
60
59
  end
61
- @client.on_event 'Target.detachedFromTarget' do |event|
60
+ @client.on_event('Target.detachedFromTarget') do |event|
62
61
  session_id = event['sessionId']
63
62
  worker = @workers[session_id]
64
63
  next unless worker
65
64
 
66
- emit_event('Events.Page.WorkerDestroyed', worker)
65
+ emit_event(PageEmittedEvents::WorkerDestroyed, worker)
67
66
  @workers.delete(session_id)
68
67
  end
69
68
 
70
- @frame_manager.on_event 'Events.FrameManager.FrameAttached' do |event|
71
- emit_event 'Events.Page.FrameAttached', event
69
+ @frame_manager.on_event(FrameManagerEmittedEvents::FrameAttached) do |event|
70
+ emit_event(PageEmittedEvents::FrameAttached, event)
72
71
  end
73
- @frame_manager.on_event 'Events.FrameManager.FrameDetached' do |event|
74
- emit_event 'Events.Page.FrameDetached', event
72
+ @frame_manager.on_event(FrameManagerEmittedEvents::FrameDetached) do |event|
73
+ emit_event(PageEmittedEvents::FrameDetached, event)
75
74
  end
76
- @frame_manager.on_event 'Events.FrameManager.FrameNavigated' do |event|
77
- emit_event 'Events.Page.FrameNavigated', event
75
+ @frame_manager.on_event(FrameManagerEmittedEvents::FrameNavigated) do |event|
76
+ emit_event(PageEmittedEvents::FrameNavigated, event)
78
77
  end
79
78
 
80
79
  network_manager = @frame_manager.network_manager
81
- network_manager.on_event 'Events.NetworkManager.Request' do |event|
82
- emit_event 'Events.Page.Request', event
80
+ network_manager.on_event(NetworkManagerEmittedEvents::Request) do |event|
81
+ emit_event(PageEmittedEvents::Request, event)
83
82
  end
84
- network_manager.on_event 'Events.NetworkManager.Response' do |event|
85
- emit_event 'Events.Page.Response', event
83
+ network_manager.on_event(NetworkManagerEmittedEvents::Response) do |event|
84
+ emit_event(PageEmittedEvents::Response, event)
86
85
  end
87
- network_manager.on_event 'Events.NetworkManager.RequestFailed' do |event|
88
- emit_event 'Events.Page.RequestFailed', event
86
+ network_manager.on_event(NetworkManagerEmittedEvents::RequestFailed) do |event|
87
+ emit_event(PageEmittedEvents::RequestFailed, event)
89
88
  end
90
- network_manager.on_event 'Events.NetworkManager.RequestFinished' do |event|
91
- emit_event 'Events.Page.RequestFinished', event
89
+ network_manager.on_event(NetworkManagerEmittedEvents::RequestFinished) do |event|
90
+ emit_event(PageEmittedEvents::RequestFinished, event)
92
91
  end
93
92
  @file_chooser_interception_is_disabled = false
94
93
  @file_chooser_interceptors = Set.new
95
94
 
96
- @client.on_event 'Page.domContentEventFired' do |event|
97
- emit_event 'Events.Page.DOMContentLoaded'
95
+ @client.on_event('Page.domContentEventFired') do |event|
96
+ emit_event(PageEmittedEvents::DOMContentLoaded)
98
97
  end
99
- @client.on_event 'Page.loadEventFired' do |event|
100
- emit_event 'Events.Page.Load'
98
+ @client.on_event('Page.loadEventFired') do |event|
99
+ emit_event(PageEmittedEvents::Load)
101
100
  end
102
101
  # client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
103
102
  # client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
104
- @client.on_event 'Page.javascriptDialogOpening' do |event|
103
+ @client.on_event('Page.javascriptDialogOpening') do |event|
105
104
  handle_dialog_opening(event)
106
105
  end
107
- # client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
108
- # client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
106
+ @client.on_event('Runtime.exceptionThrown') do |exception|
107
+ handle_exception(exception['exceptionDetails'])
108
+ end
109
+ @client.on_event('Inspector.targetCrashed') do |event|
110
+ handle_target_crashed
111
+ end
109
112
  # client.on('Performance.metrics', event => this._emitMetrics(event));
110
- @client.on_event 'Log.entryAdded' do |event|
113
+ @client.on_event('Log.entryAdded') do |event|
111
114
  handle_log_entry_added(event)
112
115
  end
113
- @client.on_event 'Page.fileChooserOpened' do |event|
116
+ @client.on_event('Page.fileChooserOpened') do |event|
114
117
  handle_file_chooser(event)
115
118
  end
116
119
  @target.is_closed_promise.then do
117
- emit_event 'Events.Page.Close'
120
+ emit_event(PageEmittedEvents::Close)
118
121
  @closed = true
119
122
  end
120
123
  end
@@ -128,43 +131,22 @@ class Puppeteer::Page
128
131
  )
129
132
  end
130
133
 
131
- EVENT_MAPPINGS = {
132
- close: 'Events.Page.Close',
133
- # console: 'Events.Page.Console',
134
- dialog: 'Events.Page.Dialog',
135
- domcontentloaded: 'Events.Page.DOMContentLoaded',
136
- # error:
137
- frameattached: 'Events.Page.FrameAttached',
138
- framedetached: 'Events.Page.FrameDetached',
139
- framenavigated: 'Events.Page.FrameNavigated',
140
- load: 'Events.Page.Load',
141
- # metrics: 'Events.Page.Metrics',
142
- # pageerror: 'Events.Page.PageError',
143
- popup: 'Events.Page.Popup',
144
- request: 'Events.Page.Request',
145
- requestfailed: 'Events.Page.RequestFailed',
146
- requestfinished: 'Events.Page.RequestFinished',
147
- response: 'Events.Page.Response',
148
- # workercreated: 'Events.Page.WorkerCreated',
149
- # workerdestroyed: 'Events.Page.WorkerDestroyed',
150
- }
151
-
152
134
  # @param event_name [Symbol]
153
135
  def on(event_name, &block)
154
- unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
155
- raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
136
+ unless PageEmittedEvents.values.include?(event_name.to_s)
137
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}")
156
138
  end
157
139
 
158
- add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block)
140
+ super(event_name.to_s, &block)
159
141
  end
160
142
 
161
143
  # @param event_name [Symbol]
162
144
  def once(event_name, &block)
163
- unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
164
- raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
145
+ unless PageEmittedEvents.values.include?(event_name.to_s)
146
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}")
165
147
  end
166
148
 
167
- observe_first(EVENT_MAPPINGS[event_name.to_sym], &block)
149
+ super(event_name.to_s, &block)
168
150
  end
169
151
 
170
152
  def handle_file_chooser(event)
@@ -211,19 +193,10 @@ class Puppeteer::Page
211
193
 
212
194
  define_async_method :async_wait_for_file_chooser
213
195
 
214
- # /**
215
- # * @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}} options
216
- # */
217
- # async setGeolocation(options) {
218
- # const { longitude, latitude, accuracy = 0} = options;
219
- # if (longitude < -180 || longitude > 180)
220
- # throw new Error(`Invalid longitude "${longitude}": precondition -180 <= LONGITUDE <= 180 failed.`);
221
- # if (latitude < -90 || latitude > 90)
222
- # throw new Error(`Invalid latitude "${latitude}": precondition -90 <= LATITUDE <= 90 failed.`);
223
- # if (accuracy < 0)
224
- # throw new Error(`Invalid accuracy "${accuracy}": precondition 0 <= ACCURACY failed.`);
225
- # await this._client.send('Emulation.setGeolocationOverride', {longitude, latitude, accuracy});
226
- # }
196
+ # @param [Puppeteer::Geolocation]
197
+ def geolocation=(geolocation)
198
+ @client.send_message('Emulation.setGeolocationOverride', geolocation.to_h)
199
+ end
227
200
 
228
201
  attr_reader :javascript_enabled, :target
229
202
 
@@ -238,7 +211,7 @@ class Puppeteer::Page
238
211
  class TargetCrashedError < StandardError; end
239
212
 
240
213
  private def handle_target_crashed
241
- emit_event 'error', TargetCrashedError.new('Page crashed!')
214
+ emit_event(PageEmittedEvents::Error, TargetCrashedError.new('Page crashed!'))
242
215
  end
243
216
 
244
217
  private def handle_log_entry_added(event)
@@ -259,7 +232,7 @@ class Puppeteer::Page
259
232
  url: url,
260
233
  line_number: line_number,
261
234
  )
262
- emit_event('Events.Page.Console',
235
+ emit_event(PageEmittedEvents::Console,
263
236
  Puppeteer::ConsoleMessage.new(level, text, [], console_message_location))
264
237
  end
265
238
  end
@@ -367,47 +340,34 @@ class Puppeteer::Page
367
340
 
368
341
  define_async_method :async_Sx
369
342
 
370
- # /**
371
- # * @param {!Array<string>} urls
372
- # * @return {!Promise<!Array<Network.Cookie>>}
373
- # */
374
- # async cookies(...urls) {
375
- # return (await this._client.send('Network.getCookies', {
376
- # urls: urls.length ? urls : [this.url()]
377
- # })).cookies;
378
- # }
343
+ # @return [Array<Hash>]
344
+ def cookies(*urls)
345
+ @client.send_message('Network.getCookies', urls: (urls.empty? ? [url] : urls))['cookies']
346
+ end
379
347
 
380
- # /**
381
- # * @param {Array<Protocol.Network.deleteCookiesParameters>} cookies
382
- # */
383
- # async deleteCookie(...cookies) {
384
- # const pageURL = this.url();
385
- # for (const cookie of cookies) {
386
- # const item = Object.assign({}, cookie);
387
- # if (!cookie.url && pageURL.startsWith('http'))
388
- # item.url = pageURL;
389
- # await this._client.send('Network.deleteCookies', item);
390
- # }
391
- # }
348
+ def delete_cookie(*cookies)
349
+ page_url = url
350
+ starts_with_http = page_url.start_with?("http")
351
+ cookies.each do |cookie|
352
+ item = (starts_with_http ? { url: page_url } : {}).merge(cookie)
353
+ @client.send_message("Network.deleteCookies", item)
354
+ end
355
+ end
392
356
 
393
- # /**
394
- # * @param {Array<Network.CookieParam>} cookies
395
- # */
396
- # async setCookie(...cookies) {
397
- # const pageURL = this.url();
398
- # const startsWithHTTP = pageURL.startsWith('http');
399
- # const items = cookies.map(cookie => {
400
- # const item = Object.assign({}, cookie);
401
- # if (!item.url && startsWithHTTP)
402
- # item.url = pageURL;
403
- # assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`);
404
- # assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`);
405
- # return item;
406
- # });
407
- # await this.deleteCookie(...items);
408
- # if (items.length)
409
- # await this._client.send('Network.setCookies', { cookies: items });
410
- # }
357
+ def set_cookie(*cookies)
358
+ page_url = url
359
+ starts_with_http = page_url.start_with?("http")
360
+ items = cookies.map do |cookie|
361
+ (starts_with_http ? { url: page_url } : {}).merge(cookie).tap do |item|
362
+ raise ArgumentError.new("Blank page can not have cookie \"#{item[:name]}\"") if item[:url] == "about:blank"
363
+ raise ArgumetnError.new("Data URL page can not have cookie \"#{item[:name]}\"") if item[:url]&.start_with?("data:")
364
+ end
365
+ end
366
+ delete_cookie(*items)
367
+ unless items.empty?
368
+ @client.send_message("Network.setCookies", cookies: items)
369
+ end
370
+ end
411
371
 
412
372
  class ScriptTag
413
373
  # @param {!{content?: string, path?: string, type?: string, url?: string}} options
@@ -502,7 +462,7 @@ class Puppeteer::Page
502
462
  # * @param {!Protocol.Performance.metricsPayload} event
503
463
  # */
504
464
  # _emitMetrics(event) {
505
- # this.emit(Events.Page.Metrics, {
465
+ # this.emit(PageEmittedEvents::Metrics, {
506
466
  # title: event.title,
507
467
  # metrics: this._buildMetricsObject(event.metrics)
508
468
  # });
@@ -521,15 +481,14 @@ class Puppeteer::Page
521
481
  # return result;
522
482
  # }
523
483
 
524
- # /**
525
- # * @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails
526
- # */
527
- # _handleException(exceptionDetails) {
528
- # const message = helper.getExceptionMessage(exceptionDetails);
529
- # const err = new Error(message);
530
- # err.stack = ''; // Don't report clientside error with a node stack attached
531
- # this.emit(Events.Page.PageError, err);
532
- # }
484
+ class PageError < StandardError ; end
485
+
486
+ private def handle_exception(exception_details)
487
+ message = Puppeteer::ExceptionDetails.new(exception_details).message
488
+ err = PageError.new(message)
489
+ # err.stack = ''; // Don't report clientside error with a node stack attached
490
+ emit_event(PageEmittedEvents::PageError, err)
491
+ end
533
492
 
534
493
  # /**
535
494
  # * @param {!Protocol.Runtime.consoleAPICalledPayload} event
@@ -613,7 +572,7 @@ class Puppeteer::Page
613
572
  # * @param {Protocol.Runtime.StackTrace=} stackTrace
614
573
  # */
615
574
  # _addConsoleMessage(type, args, stackTrace) {
616
- # if (!this.listenerCount(Events.Page.Console)) {
575
+ # if (!this.listenerCount(PageEmittedEvents::Console)) {
617
576
  # args.forEach(arg => arg.dispose());
618
577
  # return;
619
578
  # }
@@ -631,7 +590,7 @@ class Puppeteer::Page
631
590
  # columnNumber: stackTrace.callFrames[0].columnNumber,
632
591
  # } : {};
633
592
  # const message = new ConsoleMessage(type, textTokens.join(' '), args, location);
634
- # this.emit(Events.Page.Console, message);
593
+ # this.emit(PageEmittedEvents::Console, message);
635
594
  # }
636
595
 
637
596
  private def handle_dialog_opening(event)
@@ -643,7 +602,7 @@ class Puppeteer::Page
643
602
  type: dialog_type,
644
603
  message: event['message'],
645
604
  default_value: event['defaultPrompt'])
646
- emit_event('Events.Page.Dialog', dialog)
605
+ emit_event(PageEmittedEvents::Dialog, dialog)
647
606
  end
648
607
 
649
608
  # @return [String]
@@ -726,7 +685,7 @@ class Puppeteer::Page
726
685
 
727
686
  private def session_close_promise
728
687
  @disconnect_promise ||= resolvable_future do |future|
729
- @client.observe_first('Events.CDPSession.Disconnected') do
688
+ @client.observe_first(CDPSessionEmittedEvents::Disconnected) do
730
689
  future.reject(Puppeteer::CDPSession::Error.new('Target Closed'))
731
690
  end
732
691
  end
@@ -746,7 +705,7 @@ class Puppeteer::Page
746
705
  -> (request) { predicate.call(request) }
747
706
  end
748
707
 
749
- wait_for_network_manager_event('Events.NetworkManager.Request',
708
+ wait_for_network_manager_event(NetworkManagerEmittedEvents::Request,
750
709
  predicate: request_predicate,
751
710
  timeout: timeout,
752
711
  )
@@ -780,7 +739,7 @@ class Puppeteer::Page
780
739
  -> (response) { predicate.call(response) }
781
740
  end
782
741
 
783
- wait_for_network_manager_event('Events.NetworkManager.Response',
742
+ wait_for_network_manager_event(NetworkManagerEmittedEvents::Response,
784
743
  predicate: response_predicate,
785
744
  timeout: timeout,
786
745
  )
@@ -907,15 +866,28 @@ class Puppeteer::Page
907
866
  main_frame.title
908
867
  end
909
868
 
910
- # /**
911
- # * @param {!ScreenshotOptions=} options
912
- # * @return {!Promise<!Buffer|!String>}
913
- # */
914
- def screenshot(options = {})
869
+ # @param type [String] "png"|"jpeg"
870
+ # @param path [String]
871
+ # @param full_page [Boolean]
872
+ # @param clip [Hash]
873
+ # @param quality [Integer]
874
+ # @param omit_background [Boolean]
875
+ # @param encoding [String]
876
+ def screenshot(type: nil, path: nil, full_page: nil, clip: nil, quality: nil, omit_background: nil, encoding: nil)
877
+ options = {
878
+ type: type,
879
+ path: path,
880
+ full_page: full_page,
881
+ clip: clip,
882
+ quality: quality,
883
+ omit_background: omit_background,
884
+ encoding: encoding,
885
+ }.compact
915
886
  screenshot_options = ScreenshotOptions.new(options)
916
887
 
917
- # @screenshot_task_queue.post_task(-> { screenshot_task(screenshot_options.type, screenshot_options) })
918
- screenshot_task(screenshot_options.type, screenshot_options)
888
+ @screenshot_task_queue.post_task do
889
+ screenshot_task(screenshot_options.type, screenshot_options)
890
+ end
919
891
  end
920
892
 
921
893
  # @param {"png"|"jpeg"} format
@@ -939,16 +911,16 @@ class Puppeteer::Page
939
911
  clip = { x: 0, y: 0, width: width, height: height, scale: 1 }
940
912
 
941
913
  screen_orientation =
942
- if @viewport.landscape?
914
+ if @viewport&.landscape?
943
915
  { angle: 90, type: 'landscapePrimary' }
944
916
  else
945
917
  { angle: 0, type: 'portraitPrimary' }
946
918
  end
947
919
  @client.send_message('Emulation.setDeviceMetricsOverride',
948
- mobile: @viewport.mobile?,
920
+ mobile: @viewport&.mobile? || false,
949
921
  width: width,
950
922
  height: height,
951
- deviceScaleFactor: @viewport.device_scale_factor,
923
+ deviceScaleFactor: @viewport&.device_scale_factor || 1,
952
924
  screenOrientation: screen_orientation)
953
925
  end
954
926
 
@@ -1043,6 +1015,12 @@ class Puppeteer::Page
1043
1015
  else
1044
1016
  @client.connection.send_message('Target.closeTarget', targetId: @target.target_id)
1045
1017
  await @target.is_closed_promise
1018
+
1019
+ # @closed sometimes remains false, so wait for @closed = true with 100ms timeout.
1020
+ 25.times do
1021
+ break if @closed
1022
+ sleep 0.004
1023
+ end
1046
1024
  end
1047
1025
  end
1048
1026