puppeteer-ruby 0.52.1 → 0.53.0
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.
- checksums.yaml +4 -4
- data/docs/api_coverage.md +16 -15
- data/lib/puppeteer/accessibility.rb +300 -0
- data/lib/puppeteer/browser.rb +107 -8
- data/lib/puppeteer/browser_connector.rb +1 -0
- data/lib/puppeteer/browser_context.rb +0 -1
- data/lib/puppeteer/cdp_session.rb +29 -8
- data/lib/puppeteer/chrome_target_manager.rb +145 -34
- data/lib/puppeteer/connection.rb +19 -0
- data/lib/puppeteer/coverage.rb +5 -0
- data/lib/puppeteer/css_coverage.rb +4 -0
- data/lib/puppeteer/dialog.rb +5 -0
- data/lib/puppeteer/element_handle.rb +2 -3
- data/lib/puppeteer/emulation_manager.rb +70 -9
- data/lib/puppeteer/events.rb +2 -0
- data/lib/puppeteer/execution_context.rb +7 -0
- data/lib/puppeteer/extension.rb +20 -6
- data/lib/puppeteer/frame.rb +7 -3
- data/lib/puppeteer/frame_manager.rb +71 -26
- data/lib/puppeteer/http_response.rb +15 -1
- data/lib/puppeteer/isolated_world.rb +10 -4
- data/lib/puppeteer/js_coverage.rb +4 -0
- data/lib/puppeteer/keyboard.rb +6 -0
- data/lib/puppeteer/launcher/browser_options.rb +13 -1
- data/lib/puppeteer/launcher/chrome.rb +48 -4
- data/lib/puppeteer/lifecycle_watcher.rb +1 -6
- data/lib/puppeteer/locators.rb +54 -26
- data/lib/puppeteer/mouse.rb +12 -24
- data/lib/puppeteer/network_manager.rb +16 -4
- data/lib/puppeteer/page.rb +259 -33
- data/lib/puppeteer/puppeteer.rb +6 -5
- data/lib/puppeteer/screen_recorder.rb +269 -0
- data/lib/puppeteer/target.rb +7 -3
- data/lib/puppeteer/touch_screen.rb +6 -0
- data/lib/puppeteer/tracing.rb +4 -0
- data/lib/puppeteer/version.rb +2 -2
- data/lib/puppeteer/wait_task.rb +1 -2
- data/lib/puppeteer/web_mcp.rb +227 -0
- data/lib/puppeteer/web_worker.rb +135 -9
- data/lib/puppeteer.rb +11 -1
- data/puppeteer-ruby.gemspec +1 -0
- data/sig/_supplementary.rbs +33 -1
- data/sig/puppeteer/accessibility.rbs +73 -0
- data/sig/puppeteer/browser.rbs +27 -3
- data/sig/puppeteer/cdp_session.rbs +4 -0
- data/sig/puppeteer/dialog.rbs +3 -0
- data/sig/puppeteer/element_handle.rbs +1 -2
- data/sig/puppeteer/execution_context.rbs +5 -0
- data/sig/puppeteer/extension.rbs +4 -0
- data/sig/puppeteer/frame.rbs +4 -2
- data/sig/puppeteer/http_response.rbs +4 -0
- data/sig/puppeteer/keyboard.rbs +4 -0
- data/sig/puppeteer/locators.rbs +3 -4
- data/sig/puppeteer/mouse.rbs +5 -6
- data/sig/puppeteer/page.rbs +48 -4
- data/sig/puppeteer/puppeteer.rbs +4 -5
- data/sig/puppeteer/screen_recorder.rbs +48 -0
- data/sig/puppeteer/touch_screen.rbs +4 -0
- data/sig/puppeteer/web_mcp.rbs +112 -0
- data/sig/puppeteer/web_worker.rbs +39 -0
- metadata +22 -2
|
@@ -99,6 +99,7 @@ class Puppeteer::NetworkManager
|
|
|
99
99
|
@extra_http_headers = {}
|
|
100
100
|
@user_agent = nil
|
|
101
101
|
@user_agent_metadata = nil
|
|
102
|
+
@accept_language = nil
|
|
102
103
|
|
|
103
104
|
@attempted_authentications = Set.new
|
|
104
105
|
@user_request_interception_enabled = false
|
|
@@ -146,12 +147,12 @@ class Puppeteer::NetworkManager
|
|
|
146
147
|
end
|
|
147
148
|
|
|
148
149
|
private def ignore_client_error?(error)
|
|
150
|
+
return true if error.is_a?(Puppeteer::TargetCloseError)
|
|
151
|
+
|
|
149
152
|
message = error&.message
|
|
150
153
|
return false unless message
|
|
151
154
|
|
|
152
155
|
lowered = message.downcase
|
|
153
|
-
return true if lowered.include?('target closed')
|
|
154
|
-
return true if lowered.include?('session closed')
|
|
155
156
|
return true if lowered.include?('not supported')
|
|
156
157
|
return true if lowered.include?("wasn't found")
|
|
157
158
|
|
|
@@ -175,10 +176,12 @@ class Puppeteer::NetworkManager
|
|
|
175
176
|
end
|
|
176
177
|
|
|
177
178
|
private def apply_user_agent(client)
|
|
178
|
-
|
|
179
|
+
user_agent = @user_agent || @frame_manager.page.browser.user_agent
|
|
180
|
+
return unless user_agent
|
|
179
181
|
|
|
180
182
|
safe_send_message(client, 'Network.setUserAgentOverride', {
|
|
181
|
-
userAgent:
|
|
183
|
+
userAgent: user_agent,
|
|
184
|
+
acceptLanguage: @accept_language,
|
|
182
185
|
userAgentMetadata: @user_agent_metadata,
|
|
183
186
|
}.compact)
|
|
184
187
|
end
|
|
@@ -212,6 +215,8 @@ class Puppeteer::NetworkManager
|
|
|
212
215
|
if @internal_network_condition.active?
|
|
213
216
|
safe_send_message(client, 'Network.emulateNetworkConditions', @internal_network_condition.params)
|
|
214
217
|
end
|
|
218
|
+
rescue => err
|
|
219
|
+
raise unless ignore_client_error?(err)
|
|
215
220
|
end
|
|
216
221
|
|
|
217
222
|
# @param username [String|NilClass]
|
|
@@ -281,6 +286,13 @@ class Puppeteer::NetworkManager
|
|
|
281
286
|
end
|
|
282
287
|
alias_method :user_agent=, :set_user_agent
|
|
283
288
|
|
|
289
|
+
# @rbs accept_language: String? -- Accept-Language override
|
|
290
|
+
# @rbs return: void -- No return value
|
|
291
|
+
def set_accept_language(accept_language)
|
|
292
|
+
@accept_language = accept_language
|
|
293
|
+
apply_to_clients { |client| apply_user_agent(client) }
|
|
294
|
+
end
|
|
295
|
+
|
|
284
296
|
def cache_enabled=(enabled)
|
|
285
297
|
@user_cache_disabled = !enabled
|
|
286
298
|
update_protocol_cache_disabled
|
data/lib/puppeteer/page.rb
CHANGED
|
@@ -40,32 +40,46 @@ class Puppeteer::Page
|
|
|
40
40
|
@closed = false
|
|
41
41
|
@client = client
|
|
42
42
|
@target = target
|
|
43
|
-
@
|
|
43
|
+
@tab_session = client.parent_session || client
|
|
44
|
+
@tab_target = @tab_session.target || target
|
|
45
|
+
@tab_id = @tab_target.target_id
|
|
44
46
|
@keyboard = Puppeteer::Keyboard.new(client)
|
|
45
47
|
@mouse = Puppeteer::Mouse.new(client, @keyboard)
|
|
46
48
|
@timeout_settings = Puppeteer::TimeoutSettings.new
|
|
47
49
|
@touchscreen = Puppeteer::TouchScreen.new(client, @keyboard)
|
|
48
|
-
# @accessibility = Accessibility.new(client)
|
|
49
50
|
@frame_manager = Puppeteer::FrameManager.new(client, self, ignore_https_errors, @timeout_settings, network_enabled: network_enabled)
|
|
50
51
|
@emulation_manager = Puppeteer::EmulationManager.new(client)
|
|
51
52
|
@tracing = Puppeteer::Tracing.new(client)
|
|
53
|
+
@webmcp = Puppeteer::WebMCP.new(client, @frame_manager)
|
|
52
54
|
@page_bindings = {}
|
|
53
55
|
@page_binding_ids = {}
|
|
54
56
|
@coverage = Puppeteer::Coverage.new(client)
|
|
55
57
|
@javascript_enabled = true
|
|
56
58
|
@screenshot_task_queue = ScreenshotTaskQueue.new
|
|
59
|
+
@screencast_session_count = 0
|
|
60
|
+
@screencast_start_promise = nil
|
|
61
|
+
@screencast_mutex = Mutex.new
|
|
57
62
|
@inflight_requests = Set.new
|
|
58
63
|
@request_intercepted_listener_map = ObjectSpace::WeakMap.new
|
|
59
64
|
@attached_sessions = Set.new
|
|
65
|
+
@primary_session_listener_ids = []
|
|
60
66
|
|
|
61
67
|
@workers = {}
|
|
62
68
|
@user_drag_interception_enabled = false
|
|
63
69
|
@service_worker_bypassed = false
|
|
64
70
|
|
|
65
|
-
@
|
|
66
|
-
|
|
71
|
+
@swapped_session_listener_id = @tab_session.add_event_listener(CDPSessionEmittedEvents::Swapped) do |session|
|
|
72
|
+
Async do
|
|
73
|
+
handle_activation(session)
|
|
74
|
+
rescue => err
|
|
75
|
+
debug_puts(err)
|
|
76
|
+
end
|
|
67
77
|
end
|
|
68
|
-
@
|
|
78
|
+
@secondary_session_listener_id = @tab_session.add_event_listener(CDPSessionEmittedEvents::Ready) do |session|
|
|
79
|
+
handle_secondary_target(session)
|
|
80
|
+
end
|
|
81
|
+
@target_manager = @target.target_manager
|
|
82
|
+
@target_gone_listener_id = @target_manager.add_event_listener(
|
|
69
83
|
TargetManagerEmittedEvents::TargetGone,
|
|
70
84
|
&method(:handle_detached_from_target)
|
|
71
85
|
)
|
|
@@ -102,47 +116,95 @@ class Puppeteer::Page
|
|
|
102
116
|
@file_chooser_interception_is_disabled = false
|
|
103
117
|
@file_chooser_interceptors = Set.new
|
|
104
118
|
|
|
105
|
-
@client
|
|
119
|
+
setup_primary_target_listeners(@client)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private def setup_primary_target_listeners(client)
|
|
123
|
+
listener_id = client.add_event_listener(CDPSessionEmittedEvents::Ready) do |session|
|
|
124
|
+
handle_attached_to_session(session)
|
|
125
|
+
end
|
|
126
|
+
@primary_session_listener_ids << [client, listener_id]
|
|
127
|
+
|
|
128
|
+
client.on_event('Page.domContentEventFired') do |event|
|
|
106
129
|
emit_event(PageEmittedEvents::DOMContentLoaded)
|
|
107
130
|
end
|
|
108
|
-
|
|
131
|
+
client.on_event('Page.loadEventFired') do |event|
|
|
109
132
|
emit_event(PageEmittedEvents::Load)
|
|
110
133
|
end
|
|
111
|
-
|
|
134
|
+
client.add_event_listener('Runtime.consoleAPICalled') do |event|
|
|
112
135
|
handle_console_api(event)
|
|
113
136
|
end
|
|
114
|
-
|
|
137
|
+
client.add_event_listener('Runtime.bindingCalled') do |event|
|
|
115
138
|
handle_binding_called(event)
|
|
116
139
|
end
|
|
117
|
-
|
|
140
|
+
client.on_event('Page.javascriptDialogOpening') do |event|
|
|
118
141
|
handle_dialog_opening(event)
|
|
119
142
|
end
|
|
120
|
-
|
|
143
|
+
client.on_event('Runtime.exceptionThrown') do |exception|
|
|
121
144
|
handle_exception(exception['exceptionDetails'])
|
|
122
145
|
end
|
|
123
|
-
|
|
146
|
+
client.on_event('Inspector.targetCrashed') do |event|
|
|
124
147
|
handle_target_crashed
|
|
125
148
|
end
|
|
126
|
-
|
|
149
|
+
client.on_event('Performance.metrics') do |event|
|
|
127
150
|
emit_event(PageEmittedEvents::Metrics, MetricsEvent.new(event))
|
|
128
151
|
end
|
|
129
|
-
|
|
152
|
+
client.on_event('Log.entryAdded') do |event|
|
|
130
153
|
handle_log_entry_added(event)
|
|
131
154
|
end
|
|
132
|
-
|
|
155
|
+
client.on_event('Page.fileChooserOpened') do |event|
|
|
133
156
|
handle_file_chooser(event)
|
|
134
157
|
end
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private def handle_activation(session)
|
|
161
|
+
@client = session
|
|
162
|
+
@target = session.target
|
|
163
|
+
@target.instance_variable_set(:@page, self)
|
|
164
|
+
@keyboard.update_client(session)
|
|
165
|
+
@mouse.update_client(session)
|
|
166
|
+
@touchscreen.update_client(session)
|
|
167
|
+
@emulation_manager.update_client(session)
|
|
168
|
+
@tracing.update_client(session)
|
|
169
|
+
@webmcp.update_client(session)
|
|
170
|
+
@coverage.update_client(session)
|
|
171
|
+
@frame_manager.swap_frame_tree(session)
|
|
172
|
+
setup_primary_target_listeners(session)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
private def handle_secondary_target(session)
|
|
176
|
+
target = session.target
|
|
177
|
+
return unless target&.target_info&.subtype == 'prerender'
|
|
139
178
|
|
|
140
|
-
|
|
141
|
-
|
|
179
|
+
@frame_manager.register_speculative_session(session)
|
|
180
|
+
@emulation_manager.register_speculative_session(session)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
private def mark_closed
|
|
184
|
+
return if @closed
|
|
185
|
+
|
|
186
|
+
cleanup_page_listeners
|
|
187
|
+
@closed = true
|
|
188
|
+
emit_event(PageEmittedEvents::Close)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
private def cleanup_page_listeners
|
|
192
|
+
return if @page_listeners_cleaned
|
|
193
|
+
|
|
194
|
+
@page_listeners_cleaned = true
|
|
195
|
+
@primary_session_listener_ids.each do |session, listener_id|
|
|
196
|
+
session.remove_event_listener(listener_id)
|
|
142
197
|
end
|
|
198
|
+
@tab_session.remove_event_listener(@swapped_session_listener_id, @secondary_session_listener_id)
|
|
199
|
+
@target_manager.remove_event_listener(@target_gone_listener_id)
|
|
143
200
|
end
|
|
144
201
|
|
|
145
202
|
private def handle_detached_from_target(target)
|
|
203
|
+
if target == @tab_target
|
|
204
|
+
mark_closed
|
|
205
|
+
return
|
|
206
|
+
end
|
|
207
|
+
|
|
146
208
|
session_id = target.session&.id
|
|
147
209
|
@frame_manager.handle_detached_from_target(target)
|
|
148
210
|
return unless session_id
|
|
@@ -201,6 +263,7 @@ class Puppeteer::Page
|
|
|
201
263
|
@frame_manager.async_init(@target.target_id),
|
|
202
264
|
@client.async_send_message('Performance.enable'),
|
|
203
265
|
@client.async_send_message('Log.enable'),
|
|
266
|
+
@webmcp.async_initialize_domain,
|
|
204
267
|
)
|
|
205
268
|
end
|
|
206
269
|
|
|
@@ -360,10 +423,23 @@ class Puppeteer::Page
|
|
|
360
423
|
end
|
|
361
424
|
|
|
362
425
|
# @rbs return: bool -- Whether DevTools is attached to this page
|
|
363
|
-
def
|
|
426
|
+
def has_dev_tools
|
|
364
427
|
!!browser._has_devtools_target(@target.target_id)
|
|
365
428
|
end
|
|
366
429
|
|
|
430
|
+
# @rbs return: Puppeteer::Page -- Existing or newly opened DevTools page
|
|
431
|
+
def open_dev_tools
|
|
432
|
+
page_target_id = @target.target_id
|
|
433
|
+
devtools_target_id = browser._has_devtools_target(page_target_id)
|
|
434
|
+
if devtools_target_id
|
|
435
|
+
return browser._get_devtools_target_page(devtools_target_id)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
browser._create_devtools_page(page_target_id)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
define_async_method :async_open_dev_tools
|
|
442
|
+
|
|
367
443
|
# @rbs extension: Puppeteer::Extension -- Extension to trigger
|
|
368
444
|
# @rbs return: void -- No return value
|
|
369
445
|
def trigger_extension_action(extension)
|
|
@@ -409,9 +485,14 @@ class Puppeteer::Page
|
|
|
409
485
|
@frame_manager.main_frame
|
|
410
486
|
end
|
|
411
487
|
|
|
412
|
-
attr_reader :touchscreen, :coverage, :tracing, :
|
|
488
|
+
attr_reader :touchscreen, :coverage, :tracing, :webmcp
|
|
413
489
|
alias_method :touch_screen, :touchscreen
|
|
414
490
|
|
|
491
|
+
# @rbs return: Puppeteer::Accessibility -- Main-frame accessibility tree
|
|
492
|
+
def accessibility
|
|
493
|
+
main_frame.accessibility
|
|
494
|
+
end
|
|
495
|
+
|
|
415
496
|
# @rbs block: Proc? -- Optional block for instance_eval
|
|
416
497
|
# @rbs return: Puppeteer::Keyboard -- Keyboard instance
|
|
417
498
|
def keyboard(&block)
|
|
@@ -1324,6 +1405,13 @@ class Puppeteer::Page
|
|
|
1324
1405
|
end
|
|
1325
1406
|
end
|
|
1326
1407
|
|
|
1408
|
+
# @rbs locale: String? -- Locale to emulate, or nil to disable emulation
|
|
1409
|
+
# @rbs return: void -- No return value
|
|
1410
|
+
def emulate_locale(locale = nil)
|
|
1411
|
+
@emulation_manager.emulate_locale(locale)
|
|
1412
|
+
@frame_manager.network_manager.set_accept_language(locale)
|
|
1413
|
+
end
|
|
1414
|
+
|
|
1327
1415
|
VISION_DEFICIENCY_TYPES = %w[
|
|
1328
1416
|
none
|
|
1329
1417
|
achromatopsia
|
|
@@ -1369,6 +1457,151 @@ class Puppeteer::Page
|
|
|
1369
1457
|
|
|
1370
1458
|
attr_reader :viewport
|
|
1371
1459
|
|
|
1460
|
+
# @rbs path: String? -- Output file path
|
|
1461
|
+
# @rbs overwrite: bool -- Overwrite an existing output file
|
|
1462
|
+
# @rbs format: String? -- webm, gif, or mp4
|
|
1463
|
+
# @rbs crop: Hash[Symbol, Numeric]? -- Viewport crop rectangle
|
|
1464
|
+
# @rbs scale: Numeric? -- Output scale
|
|
1465
|
+
# @rbs speed: Numeric? -- Playback speed
|
|
1466
|
+
# @rbs fps: Numeric? -- Output frame rate
|
|
1467
|
+
# @rbs loop: Numeric? -- GIF loop count
|
|
1468
|
+
# @rbs delay: Numeric? -- GIF loop delay
|
|
1469
|
+
# @rbs quality: Numeric? -- VP9 CRF value
|
|
1470
|
+
# @rbs colors: Numeric? -- GIF palette size
|
|
1471
|
+
# @rbs ffmpeg_path: String? -- FFmpeg executable path
|
|
1472
|
+
# @rbs return: Puppeteer::ScreenRecorder -- Active recorder
|
|
1473
|
+
def screencast(
|
|
1474
|
+
path: nil,
|
|
1475
|
+
overwrite: true,
|
|
1476
|
+
format: nil,
|
|
1477
|
+
crop: nil,
|
|
1478
|
+
scale: nil,
|
|
1479
|
+
speed: nil,
|
|
1480
|
+
fps: nil,
|
|
1481
|
+
loop: nil,
|
|
1482
|
+
delay: nil,
|
|
1483
|
+
quality: nil,
|
|
1484
|
+
colors: nil,
|
|
1485
|
+
ffmpeg_path: nil
|
|
1486
|
+
)
|
|
1487
|
+
raise ArgumentError.new('`speed` must be greater than 0.') if speed && speed <= 0
|
|
1488
|
+
raise ArgumentError.new('`scale` must be greater than 0.') if scale && scale <= 0
|
|
1489
|
+
width, height, device_pixel_ratio = native_pixel_dimensions
|
|
1490
|
+
normalized_crop = normalize_screencast_crop(crop, width, height, device_pixel_ratio)
|
|
1491
|
+
options = {
|
|
1492
|
+
path: path,
|
|
1493
|
+
overwrite: overwrite,
|
|
1494
|
+
format: format,
|
|
1495
|
+
crop: normalized_crop,
|
|
1496
|
+
scale: scale,
|
|
1497
|
+
speed: speed,
|
|
1498
|
+
fps: fps,
|
|
1499
|
+
loop: loop,
|
|
1500
|
+
delay: delay,
|
|
1501
|
+
quality: quality,
|
|
1502
|
+
colors: colors,
|
|
1503
|
+
ffmpeg_path: ffmpeg_path,
|
|
1504
|
+
}.compact
|
|
1505
|
+
recorder = Puppeteer::ScreenRecorder.new(self, width, height, options)
|
|
1506
|
+
begin
|
|
1507
|
+
_start_screencast
|
|
1508
|
+
rescue
|
|
1509
|
+
recorder.stop
|
|
1510
|
+
raise
|
|
1511
|
+
end
|
|
1512
|
+
recorder
|
|
1513
|
+
end
|
|
1514
|
+
|
|
1515
|
+
# @rbs return: void -- Start a shared CDP screencast session
|
|
1516
|
+
def _start_screencast
|
|
1517
|
+
start_promise, first_session = @screencast_mutex.synchronize do
|
|
1518
|
+
@screencast_session_count += 1
|
|
1519
|
+
next [@screencast_start_promise, false] if @screencast_start_promise
|
|
1520
|
+
|
|
1521
|
+
@screencast_start_promise = Async::Promise.new
|
|
1522
|
+
[@screencast_start_promise, true]
|
|
1523
|
+
end
|
|
1524
|
+
if first_session
|
|
1525
|
+
first_frame = Async::Promise.new
|
|
1526
|
+
client = main_frame.client
|
|
1527
|
+
listener_id = client.once('Page.screencastFrame') do
|
|
1528
|
+
first_frame.resolve(nil) unless first_frame.resolved?
|
|
1529
|
+
end
|
|
1530
|
+
begin
|
|
1531
|
+
client.send_message('Page.startScreencast', format: 'png')
|
|
1532
|
+
first_frame.wait
|
|
1533
|
+
start_promise.resolve(nil)
|
|
1534
|
+
rescue => error
|
|
1535
|
+
start_promise.reject(error) unless start_promise.resolved?
|
|
1536
|
+
ensure
|
|
1537
|
+
client.remove_event_listener(listener_id) if listener_id
|
|
1538
|
+
end
|
|
1539
|
+
end
|
|
1540
|
+
start_promise.wait
|
|
1541
|
+
end
|
|
1542
|
+
|
|
1543
|
+
# @rbs return: void -- Stop a shared CDP screencast session
|
|
1544
|
+
def _stop_screencast
|
|
1545
|
+
should_stop = @screencast_mutex.synchronize do
|
|
1546
|
+
@screencast_session_count -= 1 if @screencast_session_count.positive?
|
|
1547
|
+
next false unless @screencast_start_promise
|
|
1548
|
+
|
|
1549
|
+
@screencast_start_promise = nil
|
|
1550
|
+
@screencast_session_count.zero?
|
|
1551
|
+
end
|
|
1552
|
+
main_frame.client.send_message('Page.stopScreencast') if should_stop
|
|
1553
|
+
end
|
|
1554
|
+
|
|
1555
|
+
private def native_pixel_dimensions
|
|
1556
|
+
original_viewport = @viewport
|
|
1557
|
+
if original_viewport && original_viewport.device_scale_factor != 0
|
|
1558
|
+
self.viewport = original_viewport.merge(device_scale_factor: 0)
|
|
1559
|
+
end
|
|
1560
|
+
main_frame.puppeteer_world.evaluate(<<~JAVASCRIPT)
|
|
1561
|
+
() => [
|
|
1562
|
+
window.visualViewport.width * window.devicePixelRatio,
|
|
1563
|
+
window.visualViewport.height * window.devicePixelRatio,
|
|
1564
|
+
window.devicePixelRatio,
|
|
1565
|
+
]
|
|
1566
|
+
JAVASCRIPT
|
|
1567
|
+
ensure
|
|
1568
|
+
self.viewport = original_viewport if original_viewport && @viewport != original_viewport
|
|
1569
|
+
end
|
|
1570
|
+
|
|
1571
|
+
private def normalize_screencast_crop(crop, width, height, device_pixel_ratio)
|
|
1572
|
+
return nil unless crop
|
|
1573
|
+
|
|
1574
|
+
value = ->(name) do
|
|
1575
|
+
crop.respond_to?(name) ? crop.public_send(name) : crop[name] || crop[name.to_s]
|
|
1576
|
+
end
|
|
1577
|
+
x = value.call(:x).floor
|
|
1578
|
+
y = value.call(:y).floor
|
|
1579
|
+
crop_width = value.call(:width).ceil
|
|
1580
|
+
crop_height = value.call(:height).ceil
|
|
1581
|
+
if x.negative? || y.negative?
|
|
1582
|
+
raise ArgumentError.new('`crop.x` and `crop.y` must be greater than or equal to 0.')
|
|
1583
|
+
end
|
|
1584
|
+
if crop_width <= 0 || crop_height <= 0
|
|
1585
|
+
raise ArgumentError.new(
|
|
1586
|
+
'`crop.height` and `crop.width` must be greater than or equal to 0.',
|
|
1587
|
+
)
|
|
1588
|
+
end
|
|
1589
|
+
viewport_width = width / device_pixel_ratio
|
|
1590
|
+
viewport_height = height / device_pixel_ratio
|
|
1591
|
+
if x + crop_width > viewport_width
|
|
1592
|
+
raise ArgumentError.new("`crop.width` cannot be larger than the viewport width (#{viewport_width}).")
|
|
1593
|
+
end
|
|
1594
|
+
if y + crop_height > viewport_height
|
|
1595
|
+
raise ArgumentError.new("`crop.height` cannot be larger than the viewport height (#{viewport_height}).")
|
|
1596
|
+
end
|
|
1597
|
+
{
|
|
1598
|
+
x: x * device_pixel_ratio,
|
|
1599
|
+
y: y * device_pixel_ratio,
|
|
1600
|
+
width: crop_width * device_pixel_ratio,
|
|
1601
|
+
height: crop_height * device_pixel_ratio,
|
|
1602
|
+
}
|
|
1603
|
+
end
|
|
1604
|
+
|
|
1372
1605
|
# @rbs page_function: String -- page_function parameter
|
|
1373
1606
|
# @rbs args: Array[untyped] -- args parameter
|
|
1374
1607
|
# @rbs return: untyped -- Result
|
|
@@ -1619,13 +1852,7 @@ class Puppeteer::Page
|
|
|
1619
1852
|
@client.send_message('Page.close')
|
|
1620
1853
|
else
|
|
1621
1854
|
@client.connection.send_message('Target.closeTarget', targetId: @target.target_id)
|
|
1622
|
-
@
|
|
1623
|
-
|
|
1624
|
-
# @closed sometimes remains false, so wait for @closed = true with 100ms timeout.
|
|
1625
|
-
25.times do
|
|
1626
|
-
break if @closed
|
|
1627
|
-
Puppeteer::AsyncUtils.sleep_seconds(0.004)
|
|
1628
|
-
end
|
|
1855
|
+
@tab_target.is_closed_promise.wait
|
|
1629
1856
|
end
|
|
1630
1857
|
rescue Puppeteer::Connection::ProtocolError => err
|
|
1631
1858
|
raise unless err.message.match?(/Target closed/i)
|
|
@@ -1644,11 +1871,10 @@ class Puppeteer::Page
|
|
|
1644
1871
|
# @rbs selector: String -- CSS selector
|
|
1645
1872
|
# @rbs delay: Numeric? -- Delay between down and up (ms)
|
|
1646
1873
|
# @rbs button: String? -- Mouse button
|
|
1647
|
-
# @rbs click_count: Integer? -- Deprecated: use count (click_count only sets clickCount)
|
|
1648
1874
|
# @rbs count: Integer? -- Number of clicks to perform
|
|
1649
1875
|
# @rbs return: void -- No return value
|
|
1650
|
-
def click(selector, delay: nil, button: nil,
|
|
1651
|
-
main_frame.click(selector, delay: delay, button: button,
|
|
1876
|
+
def click(selector, delay: nil, button: nil, count: nil)
|
|
1877
|
+
main_frame.click(selector, delay: delay, button: button, count: count)
|
|
1652
1878
|
end
|
|
1653
1879
|
|
|
1654
1880
|
define_async_method :async_click
|
data/lib/puppeteer/puppeteer.rb
CHANGED
|
@@ -33,6 +33,7 @@ class Puppeteer::Puppeteer
|
|
|
33
33
|
# @rbs network_enabled: bool? -- Enable network domain
|
|
34
34
|
# @rbs issues_enabled: bool? -- Enable issues domain
|
|
35
35
|
# @rbs block_list: Array[String]? -- URL block list patterns
|
|
36
|
+
# @rbs allow_list: Array[String]? -- URL allow list patterns
|
|
36
37
|
# @rbs enable_extensions: (bool | Array[String])? -- Enable extensions or load unpacked extensions
|
|
37
38
|
# @rbs default_viewport: Puppeteer::Viewport? -- Default viewport
|
|
38
39
|
# @rbs slow_mo: Integer? -- Delay between operations (ms)
|
|
@@ -61,6 +62,7 @@ class Puppeteer::Puppeteer
|
|
|
61
62
|
network_enabled: true,
|
|
62
63
|
issues_enabled: true,
|
|
63
64
|
block_list: nil,
|
|
65
|
+
allow_list: nil,
|
|
64
66
|
enable_extensions: false,
|
|
65
67
|
default_viewport: NoViewport.new,
|
|
66
68
|
slow_mo: nil,
|
|
@@ -93,6 +95,7 @@ class Puppeteer::Puppeteer
|
|
|
93
95
|
network_enabled: network_enabled,
|
|
94
96
|
issues_enabled: issues_enabled,
|
|
95
97
|
block_list: block_list,
|
|
98
|
+
allow_list: allow_list,
|
|
96
99
|
enable_extensions: enable_extensions,
|
|
97
100
|
default_viewport: default_viewport,
|
|
98
101
|
slow_mo: slow_mo,
|
|
@@ -145,6 +148,7 @@ class Puppeteer::Puppeteer
|
|
|
145
148
|
# @rbs network_enabled: bool? -- Enable network domain
|
|
146
149
|
# @rbs issues_enabled: bool? -- Enable issues domain
|
|
147
150
|
# @rbs block_list: Array[String]? -- URL block list patterns
|
|
151
|
+
# @rbs allow_list: Array[String]? -- URL allow list patterns
|
|
148
152
|
# @rbs default_viewport: Puppeteer::Viewport? -- Default viewport
|
|
149
153
|
# @rbs slow_mo: Integer? -- Delay between operations (ms)
|
|
150
154
|
# @rbs protocol_timeout: Integer? -- CDP protocol timeout in milliseconds
|
|
@@ -159,6 +163,7 @@ class Puppeteer::Puppeteer
|
|
|
159
163
|
network_enabled: true,
|
|
160
164
|
issues_enabled: true,
|
|
161
165
|
block_list: nil,
|
|
166
|
+
allow_list: nil,
|
|
162
167
|
default_viewport: NoViewport.new,
|
|
163
168
|
slow_mo: nil,
|
|
164
169
|
protocol_timeout: nil,
|
|
@@ -173,6 +178,7 @@ class Puppeteer::Puppeteer
|
|
|
173
178
|
network_enabled: network_enabled,
|
|
174
179
|
issues_enabled: issues_enabled,
|
|
175
180
|
block_list: block_list,
|
|
181
|
+
allow_list: allow_list,
|
|
176
182
|
slow_mo: slow_mo,
|
|
177
183
|
protocol_timeout: protocol_timeout,
|
|
178
184
|
}.compact
|
|
@@ -226,11 +232,6 @@ class Puppeteer::Puppeteer
|
|
|
226
232
|
)
|
|
227
233
|
end
|
|
228
234
|
|
|
229
|
-
# @rbs return: String -- Product name
|
|
230
|
-
def product
|
|
231
|
-
launcher.product
|
|
232
|
-
end
|
|
233
|
-
|
|
234
235
|
private def async_context?
|
|
235
236
|
task = Async::Task.current
|
|
236
237
|
!task.nil?
|