puppeteer-ruby 0.0.18 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +24 -1
  3. data/.github/workflows/reviewdog.yml +1 -1
  4. data/.rubocop.yml +50 -3
  5. data/Dockerfile +9 -0
  6. data/README.md +38 -0
  7. data/docker-compose.yml +34 -0
  8. data/lib/puppeteer.rb +15 -11
  9. data/lib/puppeteer/browser.rb +19 -26
  10. data/lib/puppeteer/browser_context.rb +48 -49
  11. data/lib/puppeteer/browser_runner.rb +20 -6
  12. data/lib/puppeteer/cdp_session.rb +21 -7
  13. data/lib/puppeteer/concurrent_ruby_utils.rb +18 -5
  14. data/lib/puppeteer/connection.rb +32 -13
  15. data/lib/puppeteer/debug_print.rb +1 -1
  16. data/lib/puppeteer/define_async_method.rb +1 -1
  17. data/lib/puppeteer/devices.rb +998 -849
  18. data/lib/puppeteer/dialog.rb +34 -0
  19. data/lib/puppeteer/dom_world.rb +2 -2
  20. data/lib/puppeteer/element_handle.rb +18 -1
  21. data/lib/puppeteer/env.rb +5 -0
  22. data/lib/puppeteer/event_callbackable.rb +4 -0
  23. data/lib/puppeteer/events.rb +184 -0
  24. data/lib/puppeteer/exception_details.rb +38 -0
  25. data/lib/puppeteer/frame.rb +1 -3
  26. data/lib/puppeteer/frame_manager.rb +20 -16
  27. data/lib/puppeteer/geolocation.rb +24 -0
  28. data/lib/puppeteer/keyboard/us_keyboard_layout.rb +2 -2
  29. data/lib/puppeteer/launcher.rb +11 -2
  30. data/lib/puppeteer/launcher/base.rb +14 -4
  31. data/lib/puppeteer/launcher/browser_options.rb +2 -1
  32. data/lib/puppeteer/launcher/chrome.rb +5 -9
  33. data/lib/puppeteer/launcher/firefox.rb +385 -0
  34. data/lib/puppeteer/lifecycle_watcher.rb +6 -6
  35. data/lib/puppeteer/network_manager.rb +6 -6
  36. data/lib/puppeteer/page.rb +87 -103
  37. data/lib/puppeteer/remote_object.rb +12 -1
  38. data/lib/puppeteer/target.rb +2 -2
  39. data/lib/puppeteer/version.rb +1 -1
  40. data/puppeteer-ruby.gemspec +1 -1
  41. metadata +11 -4
@@ -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
@@ -266,7 +242,13 @@ class Puppeteer::Page
266
242
  @frame_manager.main_frame
267
243
  end
268
244
 
269
- attr_reader :keyboard, :touch_screen, :coverage, :accessibility
245
+ attr_reader :touch_screen, :coverage, :accessibility
246
+
247
+ def keyboard(&block)
248
+ @keyboard.instance_eval(&block) unless block.nil?
249
+
250
+ @keyboard
251
+ end
270
252
 
271
253
  def frames
272
254
  @frame_manager.frames
@@ -494,7 +476,7 @@ class Puppeteer::Page
494
476
  # * @param {!Protocol.Performance.metricsPayload} event
495
477
  # */
496
478
  # _emitMetrics(event) {
497
- # this.emit(Events.Page.Metrics, {
479
+ # this.emit(PageEmittedEvents::Metrics, {
498
480
  # title: event.title,
499
481
  # metrics: this._buildMetricsObject(event.metrics)
500
482
  # });
@@ -513,15 +495,14 @@ class Puppeteer::Page
513
495
  # return result;
514
496
  # }
515
497
 
516
- # /**
517
- # * @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails
518
- # */
519
- # _handleException(exceptionDetails) {
520
- # const message = helper.getExceptionMessage(exceptionDetails);
521
- # const err = new Error(message);
522
- # err.stack = ''; // Don't report clientside error with a node stack attached
523
- # this.emit(Events.Page.PageError, err);
524
- # }
498
+ class PageError < StandardError ; end
499
+
500
+ private def handle_exception(exception_details)
501
+ message = Puppeteer::ExceptionDetails.new(exception_details).message
502
+ err = PageError.new(message)
503
+ # err.stack = ''; // Don't report clientside error with a node stack attached
504
+ emit_event(PageEmittedEvents::PageError, err)
505
+ end
525
506
 
526
507
  # /**
527
508
  # * @param {!Protocol.Runtime.consoleAPICalledPayload} event
@@ -605,7 +586,7 @@ class Puppeteer::Page
605
586
  # * @param {Protocol.Runtime.StackTrace=} stackTrace
606
587
  # */
607
588
  # _addConsoleMessage(type, args, stackTrace) {
608
- # if (!this.listenerCount(Events.Page.Console)) {
589
+ # if (!this.listenerCount(PageEmittedEvents::Console)) {
609
590
  # args.forEach(arg => arg.dispose());
610
591
  # return;
611
592
  # }
@@ -623,23 +604,20 @@ class Puppeteer::Page
623
604
  # columnNumber: stackTrace.callFrames[0].columnNumber,
624
605
  # } : {};
625
606
  # const message = new ConsoleMessage(type, textTokens.join(' '), args, location);
626
- # this.emit(Events.Page.Console, message);
607
+ # this.emit(PageEmittedEvents::Console, message);
627
608
  # }
628
609
 
629
- # _onDialog(event) {
630
- # let dialogType = null;
631
- # if (event.type === 'alert')
632
- # dialogType = Dialog.Type.Alert;
633
- # else if (event.type === 'confirm')
634
- # dialogType = Dialog.Type.Confirm;
635
- # else if (event.type === 'prompt')
636
- # dialogType = Dialog.Type.Prompt;
637
- # else if (event.type === 'beforeunload')
638
- # dialogType = Dialog.Type.BeforeUnload;
639
- # assert(dialogType, 'Unknown javascript dialog type: ' + event.type);
640
- # const dialog = new Dialog(this._client, dialogType, event.message, event.defaultPrompt);
641
- # this.emit(Events.Page.Dialog, dialog);
642
- # }
610
+ private def handle_dialog_opening(event)
611
+ dialog_type = event['type']
612
+ unless %w(alert confirm prompt beforeunload).include?(dialog_type)
613
+ raise ArgumentError.new("Unknown javascript dialog type: #{dialog_type}")
614
+ end
615
+ dialog = Puppeteer::Dialog.new(@client,
616
+ type: dialog_type,
617
+ message: event['message'],
618
+ default_value: event['defaultPrompt'])
619
+ emit_event(PageEmittedEvents::Dialog, dialog)
620
+ end
643
621
 
644
622
  # @return [String]
645
623
  def url
@@ -721,7 +699,7 @@ class Puppeteer::Page
721
699
 
722
700
  private def session_close_promise
723
701
  @disconnect_promise ||= resolvable_future do |future|
724
- @client.observe_first('Events.CDPSession.Disconnected') do
702
+ @client.observe_first(CDPSessionEmittedEvents::Disconnected) do
725
703
  future.reject(Puppeteer::CDPSession::Error.new('Target Closed'))
726
704
  end
727
705
  end
@@ -741,7 +719,7 @@ class Puppeteer::Page
741
719
  -> (request) { predicate.call(request) }
742
720
  end
743
721
 
744
- wait_for_network_manager_event('Events.NetworkManager.Request',
722
+ wait_for_network_manager_event(NetworkManagerEmittedEvents::Request,
745
723
  predicate: request_predicate,
746
724
  timeout: timeout,
747
725
  )
@@ -775,7 +753,7 @@ class Puppeteer::Page
775
753
  -> (response) { predicate.call(response) }
776
754
  end
777
755
 
778
- wait_for_network_manager_event('Events.NetworkManager.Response',
756
+ wait_for_network_manager_event(NetworkManagerEmittedEvents::Response,
779
757
  predicate: response_predicate,
780
758
  timeout: timeout,
781
759
  )
@@ -934,16 +912,16 @@ class Puppeteer::Page
934
912
  clip = { x: 0, y: 0, width: width, height: height, scale: 1 }
935
913
 
936
914
  screen_orientation =
937
- if @viewport.landscape?
915
+ if @viewport&.landscape?
938
916
  { angle: 90, type: 'landscapePrimary' }
939
917
  else
940
918
  { angle: 0, type: 'portraitPrimary' }
941
919
  end
942
920
  @client.send_message('Emulation.setDeviceMetricsOverride',
943
- mobile: @viewport.mobile?,
921
+ mobile: @viewport&.mobile? || false,
944
922
  width: width,
945
923
  height: height,
946
- deviceScaleFactor: @viewport.device_scale_factor,
924
+ deviceScaleFactor: @viewport&.device_scale_factor || 1,
947
925
  screenOrientation: screen_orientation)
948
926
  end
949
927
 
@@ -1038,6 +1016,12 @@ class Puppeteer::Page
1038
1016
  else
1039
1017
  @client.connection.send_message('Target.closeTarget', targetId: @target.target_id)
1040
1018
  await @target.is_closed_promise
1019
+
1020
+ # @closed sometimes remains false, so wait for @closed = true with 100ms timeout.
1021
+ 25.times do
1022
+ break if @closed
1023
+ sleep 0.004
1024
+ end
1041
1025
  end
1042
1026
  end
1043
1027
 
@@ -80,7 +80,18 @@ class Puppeteer::RemoteObject
80
80
 
81
81
  # used in ElementHandle#_box_model
82
82
  def box_model(client)
83
- client.send_message('DOM.getBoxModel', objectId: @object_id)
83
+ result = client.send_message('DOM.getBoxModel', objectId: @object_id)
84
+
85
+ # Firefox returns width/height = 0, content/padding/border/margin = [nil, nil, nil, nil, nil, nil, nil, nil]
86
+ # while Chrome throws Error(Could not compute box model)
87
+ model = result['model']
88
+ if model['width'] == 0 && model['height'] == 0 &&
89
+ %w(content padding border margin).all? { |key| model[key].all?(&:nil?) }
90
+
91
+ debug_puts('Could not compute box model in Firefox.')
92
+ return nil
93
+ end
94
+ result
84
95
  rescue => err
85
96
  debug_puts(err)
86
97
  nil
@@ -68,10 +68,10 @@ class Puppeteer::Target
68
68
  if opener_page.nil? || type != 'page'
69
69
  return true
70
70
  end
71
- # if (!openerPage.listenerCount(Events.Page.Popup))
71
+ # if (!openerPage.listenerCount(PageEmittedEvents::Popup))
72
72
  # return true;
73
73
  popup_page = page
74
- opener_page.emit_event('Events.Page.Popup', popup_page)
74
+ opener_page.emit_event(PageEmittedEvents::Popup, popup_page)
75
75
 
76
76
  true
77
77
  end