puppeteer-ruby 0.45.6 → 0.50.0.alpha5

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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -3
  3. data/AGENTS.md +169 -0
  4. data/CLAUDE/README.md +41 -0
  5. data/CLAUDE/architecture.md +253 -0
  6. data/CLAUDE/cdp_protocol.md +230 -0
  7. data/CLAUDE/concurrency.md +216 -0
  8. data/CLAUDE/porting_puppeteer.md +575 -0
  9. data/CLAUDE/rbs_type_checking.md +101 -0
  10. data/CLAUDE/spec_migration_plans.md +1041 -0
  11. data/CLAUDE/testing.md +278 -0
  12. data/CLAUDE.md +242 -0
  13. data/README.md +8 -0
  14. data/Rakefile +7 -0
  15. data/Steepfile +28 -0
  16. data/docs/api_coverage.md +105 -56
  17. data/lib/puppeteer/aria_query_handler.rb +3 -2
  18. data/lib/puppeteer/async_utils.rb +214 -0
  19. data/lib/puppeteer/browser.rb +98 -56
  20. data/lib/puppeteer/browser_connector.rb +18 -3
  21. data/lib/puppeteer/browser_context.rb +196 -3
  22. data/lib/puppeteer/browser_runner.rb +18 -10
  23. data/lib/puppeteer/cdp_session.rb +67 -23
  24. data/lib/puppeteer/chrome_target_manager.rb +65 -40
  25. data/lib/puppeteer/connection.rb +55 -36
  26. data/lib/puppeteer/console_message.rb +9 -1
  27. data/lib/puppeteer/console_patch.rb +47 -0
  28. data/lib/puppeteer/css_coverage.rb +5 -3
  29. data/lib/puppeteer/custom_query_handler.rb +80 -33
  30. data/lib/puppeteer/define_async_method.rb +31 -37
  31. data/lib/puppeteer/dialog.rb +47 -14
  32. data/lib/puppeteer/element_handle.rb +231 -62
  33. data/lib/puppeteer/emulation_manager.rb +1 -1
  34. data/lib/puppeteer/env.rb +1 -1
  35. data/lib/puppeteer/errors.rb +25 -2
  36. data/lib/puppeteer/event_callbackable.rb +15 -0
  37. data/lib/puppeteer/events.rb +4 -0
  38. data/lib/puppeteer/execution_context.rb +148 -3
  39. data/lib/puppeteer/file_chooser.rb +6 -0
  40. data/lib/puppeteer/frame.rb +162 -91
  41. data/lib/puppeteer/frame_manager.rb +69 -48
  42. data/lib/puppeteer/http_request.rb +114 -38
  43. data/lib/puppeteer/http_response.rb +24 -7
  44. data/lib/puppeteer/isolated_world.rb +64 -41
  45. data/lib/puppeteer/js_coverage.rb +5 -3
  46. data/lib/puppeteer/js_handle.rb +58 -16
  47. data/lib/puppeteer/keyboard.rb +30 -17
  48. data/lib/puppeteer/launcher/browser_options.rb +3 -1
  49. data/lib/puppeteer/launcher/chrome.rb +8 -5
  50. data/lib/puppeteer/launcher/launch_options.rb +7 -2
  51. data/lib/puppeteer/launcher.rb +4 -8
  52. data/lib/puppeteer/lifecycle_watcher.rb +38 -22
  53. data/lib/puppeteer/mouse.rb +273 -64
  54. data/lib/puppeteer/network_event_manager.rb +7 -0
  55. data/lib/puppeteer/network_manager.rb +393 -112
  56. data/lib/puppeteer/page/screenshot_task_queue.rb +14 -4
  57. data/lib/puppeteer/page.rb +568 -226
  58. data/lib/puppeteer/puppeteer.rb +171 -64
  59. data/lib/puppeteer/query_handler_manager.rb +112 -16
  60. data/lib/puppeteer/reactor_runner.rb +247 -0
  61. data/lib/puppeteer/remote_object.rb +127 -47
  62. data/lib/puppeteer/target.rb +74 -27
  63. data/lib/puppeteer/task_manager.rb +3 -1
  64. data/lib/puppeteer/timeout_helper.rb +6 -10
  65. data/lib/puppeteer/touch_handle.rb +39 -0
  66. data/lib/puppeteer/touch_screen.rb +72 -22
  67. data/lib/puppeteer/tracing.rb +3 -3
  68. data/lib/puppeteer/version.rb +1 -1
  69. data/lib/puppeteer/wait_task.rb +264 -101
  70. data/lib/puppeteer/web_socket.rb +2 -2
  71. data/lib/puppeteer/web_socket_transport.rb +91 -27
  72. data/lib/puppeteer/web_worker.rb +175 -0
  73. data/lib/puppeteer.rb +20 -4
  74. data/puppeteer-ruby.gemspec +15 -11
  75. data/sig/_external.rbs +8 -0
  76. data/sig/_supplementary.rbs +314 -0
  77. data/sig/puppeteer/browser.rbs +166 -0
  78. data/sig/puppeteer/cdp_session.rbs +64 -0
  79. data/sig/puppeteer/dialog.rbs +41 -0
  80. data/sig/puppeteer/element_handle.rbs +305 -0
  81. data/sig/puppeteer/execution_context.rbs +87 -0
  82. data/sig/puppeteer/frame.rbs +226 -0
  83. data/sig/puppeteer/http_request.rbs +214 -0
  84. data/sig/puppeteer/http_response.rbs +89 -0
  85. data/sig/puppeteer/js_handle.rbs +64 -0
  86. data/sig/puppeteer/keyboard.rbs +40 -0
  87. data/sig/puppeteer/mouse.rbs +113 -0
  88. data/sig/puppeteer/page.rbs +515 -0
  89. data/sig/puppeteer/puppeteer.rbs +98 -0
  90. data/sig/puppeteer/remote_object.rbs +78 -0
  91. data/sig/puppeteer/touch_handle.rbs +21 -0
  92. data/sig/puppeteer/touch_screen.rbs +35 -0
  93. data/sig/puppeteer/web_worker.rbs +83 -0
  94. metadata +116 -45
  95. data/CHANGELOG.md +0 -397
  96. data/lib/puppeteer/concurrent_ruby_utils.rb +0 -81
  97. data/lib/puppeteer/firefox_target_manager.rb +0 -157
  98. data/lib/puppeteer/launcher/firefox.rb +0 -453
@@ -1,453 +0,0 @@
1
- require 'tmpdir'
2
-
3
- # https://github.com/puppeteer/puppeteer/blob/main/src/node/Launcher.ts
4
- module Puppeteer::Launcher
5
- class Firefox
6
- def initialize(project_root:, preferred_revision:, is_puppeteer_core:)
7
- @project_root = project_root
8
- @preferred_revision = preferred_revision
9
- @is_puppeteer_core = is_puppeteer_core
10
- end
11
-
12
- # @param {!(Launcher.LaunchOptions & Launcher.ChromeArgOptions & Launcher.BrowserOptions)=} options
13
- # @return {!Promise<!Browser>}
14
- def launch(options = {})
15
- @chrome_arg_options = ChromeArgOptions.new(options)
16
- @launch_options = LaunchOptions.new(options)
17
- @browser_options = BrowserOptions.new(options)
18
-
19
- firefox_arguments =
20
- if !@launch_options.ignore_default_args
21
- default_args(options).to_a
22
- elsif @launch_options.ignore_default_args.is_a?(Enumerable)
23
- default_args(options).reject do |arg|
24
- @launch_options.ignore_default_args.include?(arg)
25
- end.to_a
26
- else
27
- @chrome_arg_options.args.dup
28
- end
29
-
30
- if firefox_arguments.none? { |arg| arg.start_with?('--remote-debugging-') }
31
- firefox_arguments << "--remote-debugging-port=#{@chrome_arg_options.debugging_port}"
32
- end
33
-
34
- profile_arg_index = firefox_arguments.index { |arg| arg.start_with?('--profile') || arg.start_with?('-profile') }
35
- if profile_arg_index
36
- using_temp_user_data_dir = false
37
- user_data_dir = firefox_arguments[profile_arg_index + 1]
38
- unless File.exist?(user_data_dir)
39
- raise ArgumentError.new("Firefox profile not found at '#{user_data_dir}'")
40
- end
41
- prefs = default_preferences(@launch_options.extra_prefs_firefox)
42
- write_preferences(prefs, user_data_dir)
43
- else
44
- using_temp_user_data_dir = true
45
- user_data_dir = create_profile(@launch_options.extra_prefs_firefox)
46
- firefox_arguments << "--profile"
47
- firefox_arguments << user_data_dir
48
- end
49
-
50
- firefox_executable =
51
- if @launch_options.channel
52
- executable_path_for_channel(@launch_options.channel.to_s)
53
- else
54
- @launch_options.executable_path || fallback_executable_path
55
- end
56
- runner = Puppeteer::BrowserRunner.new(
57
- true,
58
- firefox_executable,
59
- firefox_arguments,
60
- user_data_dir,
61
- using_temp_user_data_dir,
62
- )
63
- runner.start(
64
- handle_SIGHUP: @launch_options.handle_SIGHUP?,
65
- handle_SIGTERM: @launch_options.handle_SIGTERM?,
66
- handle_SIGINT: @launch_options.handle_SIGINT?,
67
- dumpio: @launch_options.dumpio?,
68
- env: @launch_options.env,
69
- pipe: @launch_options.pipe?,
70
- )
71
-
72
- browser =
73
- begin
74
- connection = runner.setup_connection(
75
- use_pipe: @launch_options.pipe?,
76
- timeout: @launch_options.timeout,
77
- slow_mo: @browser_options.slow_mo,
78
- preferred_revision: @preferred_revision,
79
- )
80
-
81
- Puppeteer::Browser.create(
82
- product: product,
83
- connection: connection,
84
- context_ids: [],
85
- ignore_https_errors: @browser_options.ignore_https_errors?,
86
- default_viewport: @browser_options.default_viewport,
87
- process: runner.proc,
88
- close_callback: -> { runner.close },
89
- target_filter_callback: nil,
90
- is_page_target_callback: nil,
91
- )
92
- rescue
93
- runner.kill
94
- raise
95
- end
96
-
97
- begin
98
- browser.wait_for_target(
99
- predicate: ->(target) { target.type == 'page' },
100
- timeout: @launch_options.timeout,
101
- )
102
- rescue
103
- browser.close
104
- raise
105
- end
106
-
107
- browser
108
- end
109
-
110
- # @return {string}
111
- def executable_path(channel: nil)
112
- if channel
113
- executable_path_for_channel(channel.to_s)
114
- else
115
- fallback_executable_path
116
- end
117
- end
118
-
119
- private def fallback_executable_path
120
- executable_path_for_channel('firefox')
121
- end
122
-
123
- FIREFOX_EXECUTABLE_PATHS = {
124
- windows: "#{ENV['PROGRAMFILES']}\\Firefox Nightly\\firefox.exe",
125
- darwin: -> {
126
- ['Firefox Nightly.app', 'Firefox Developer Edition.app'].map do |app|
127
- "/Applications/#{app}/Contents/MacOS/firefox"
128
- end.find { |path| File.exist?(path) }
129
- },
130
- linux: -> { Puppeteer::ExecutablePathFinder.new('firefox').find_first },
131
- }.freeze
132
-
133
- # @param channel [String]
134
- private def executable_path_for_channel(channel)
135
- allowed = ['firefox', 'firefox-nightly', 'nightly']
136
- unless allowed.include?(channel)
137
- raise ArgumentError.new("Invalid channel: '#{channel}'. Allowed channel is #{allowed}")
138
- end
139
-
140
- firefox_path =
141
- if Puppeteer.env.windows?
142
- FIREFOX_EXECUTABLE_PATHS[:windows]
143
- elsif Puppeteer.env.darwin?
144
- FIREFOX_EXECUTABLE_PATHS[:darwin]
145
- else
146
- FIREFOX_EXECUTABLE_PATHS[:linux]
147
- end
148
- if firefox_path.is_a?(Proc)
149
- firefox_path = firefox_path.call
150
- end
151
-
152
- if !firefox_path || !File.exist?(firefox_path)
153
- raise "Nightly version of Firefox is not installed on this system.\nExpected path: #{firefox_path}"
154
- end
155
-
156
- firefox_path
157
- end
158
-
159
- def product
160
- 'firefox'
161
- end
162
-
163
- class DefaultArgs
164
- include Enumerable
165
-
166
- # @param options [Launcher::ChromeArgOptions]
167
- def initialize(chrome_arg_options)
168
- firefox_arguments = []
169
-
170
- if Puppeteer.env.darwin?
171
- firefox_arguments << '--foreground'
172
- elsif Puppeteer.env.windows?
173
- firefox_arguments << '--wait-for-browser'
174
- end
175
-
176
- if chrome_arg_options.user_data_dir
177
- firefox_arguments << "--profile"
178
- firefox_arguments << chrome_arg_options.user_data_dir
179
- end
180
-
181
- if chrome_arg_options.headless?
182
- firefox_arguments << '--headless'
183
- end
184
-
185
- if chrome_arg_options.devtools?
186
- firefox_arguments << '--devtools'
187
- end
188
-
189
- if chrome_arg_options.args.all? { |arg| arg.start_with?('-') }
190
- firefox_arguments << 'about:blank'
191
- end
192
-
193
- firefox_arguments.concat(chrome_arg_options.args)
194
-
195
- @firefox_arguments = firefox_arguments
196
- end
197
-
198
- def each(&block)
199
- @firefox_arguments.each do |opt|
200
- block.call(opt)
201
- end
202
- end
203
- end
204
-
205
- # @return [DefaultArgs]
206
- def default_args(options = nil)
207
- DefaultArgs.new(ChromeArgOptions.new(options || {}))
208
- end
209
-
210
- private def default_preferences(extra_prefs)
211
- server = 'dummy.test'
212
- default_preferences = {
213
- # Make sure Shield doesn't hit the network.
214
- 'app.normandy.api_url': '',
215
- # Disable Firefox old build background check
216
- 'app.update.checkInstallTime': false,
217
- # Disable automatically upgrading Firefox
218
- 'app.update.disabledForTesting': true,
219
-
220
- # Increase the APZ content response timeout to 1 minute
221
- 'apz.content_response_timeout': 60000,
222
-
223
- # Prevent various error message on the console
224
- # jest-puppeteer asserts that no error message is emitted by the console
225
- 'browser.contentblocking.features.standard': '-tp,tpPrivate,cookieBehavior0,-cm,-fp',
226
-
227
- # Enable the dump function: which sends messages to the system
228
- # console
229
- # https://bugzilla.mozilla.org/show_bug.cgi?id=1543115
230
- 'browser.dom.window.dump.enabled': true,
231
- # Disable topstories
232
- 'browser.newtabpage.activity-stream.feeds.system.topstories': false,
233
- # Always display a blank page
234
- 'browser.newtabpage.enabled': false,
235
- # Background thumbnails in particular cause grief: and disabling
236
- # thumbnails in general cannot hurt
237
- 'browser.pagethumbnails.capturing_disabled': true,
238
-
239
- # Disable safebrowsing components.
240
- 'browser.safebrowsing.blockedURIs.enabled': false,
241
- 'browser.safebrowsing.downloads.enabled': false,
242
- 'browser.safebrowsing.malware.enabled': false,
243
- 'browser.safebrowsing.phishing.enabled': false,
244
-
245
- # Disable updates to search engines.
246
- 'browser.search.update': false,
247
- # Do not restore the last open set of tabs if the browser has crashed
248
- 'browser.sessionstore.resume_from_crash': false,
249
- # Skip check for default browser on startup
250
- 'browser.shell.checkDefaultBrowser': false,
251
-
252
- # Disable newtabpage
253
- 'browser.startup.homepage': 'about:blank',
254
- # Do not redirect user when a milstone upgrade of Firefox is detected
255
- 'browser.startup.homepage_override.mstone': 'ignore',
256
- # Start with a blank page about:blank
257
- 'browser.startup.page': 0,
258
-
259
- # Do not allow background tabs to be zombified on Android: otherwise for
260
- # tests that open additional tabs: the test harness tab itself might get
261
- # unloaded
262
- 'browser.tabs.disableBackgroundZombification': false,
263
- # Do not warn when closing all other open tabs
264
- 'browser.tabs.warnOnCloseOtherTabs': false,
265
- # Do not warn when multiple tabs will be opened
266
- 'browser.tabs.warnOnOpen': false,
267
-
268
- # Do not automatically offer translations, as tests do not expect this.
269
- 'browser.translations.automaticallyPopup': false,
270
-
271
- # Disable the UI tour.
272
- 'browser.uitour.enabled': false,
273
- # Turn off search suggestions in the location bar so as not to trigger
274
- # network connections.
275
- 'browser.urlbar.suggest.searches': false,
276
- # Disable first run splash page on Windows 10
277
- 'browser.usedOnWindows10.introURL': '',
278
- # Do not warn on quitting Firefox
279
- 'browser.warnOnQuit': false,
280
-
281
- # Defensively disable data reporting systems
282
- 'datareporting.healthreport.documentServerURI': "http://#{server}/dummy/healthreport/",
283
- 'datareporting.healthreport.logging.consoleEnabled': false,
284
- 'datareporting.healthreport.service.enabled': false,
285
- 'datareporting.healthreport.service.firstRun': false,
286
- 'datareporting.healthreport.uploadEnabled': false,
287
-
288
- # Do not show datareporting policy notifications which can interfere with tests
289
- 'datareporting.policy.dataSubmissionEnabled': false,
290
- 'datareporting.policy.dataSubmissionPolicyBypassNotification': true,
291
-
292
- # DevTools JSONViewer sometimes fails to load dependencies with its require.js.
293
- # This doesn't affect Puppeteer but spams console (Bug 1424372)
294
- 'devtools.jsonview.enabled': false,
295
-
296
- # Disable popup-blocker
297
- 'dom.disable_open_during_load': false,
298
-
299
- # Enable the support for File object creation in the content process
300
- # Required for |Page.setFileInputFiles| protocol method.
301
- 'dom.file.createInChild': true,
302
-
303
- # Disable the ProcessHangMonitor
304
- 'dom.ipc.reportProcessHangs': false,
305
-
306
- # Disable slow script dialogues
307
- 'dom.max_chrome_script_run_time': 0,
308
- 'dom.max_script_run_time': 0,
309
-
310
- # Only load extensions from the application and user profile
311
- # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
312
- 'extensions.autoDisableScopes': 0,
313
- 'extensions.enabledScopes': 5,
314
-
315
- # Disable metadata caching for installed add-ons by default
316
- 'extensions.getAddons.cache.enabled': false,
317
-
318
- # Disable installing any distribution extensions or add-ons.
319
- 'extensions.installDistroAddons': false,
320
-
321
- # Disabled screenshots extension
322
- 'extensions.screenshots.disabled': true,
323
-
324
- # Turn off extension updates so they do not bother tests
325
- 'extensions.update.enabled': false,
326
-
327
- # Turn off extension updates so they do not bother tests
328
- 'extensions.update.notifyUser': false,
329
-
330
- # Make sure opening about:addons will not hit the network
331
- 'extensions.webservice.discoverURL': "http://#{server}/dummy/discoveryURL",
332
-
333
- # Allow the application to have focus even it runs in the background
334
- 'focusmanager.testmode': true,
335
-
336
- # Disable useragent updates
337
- 'general.useragent.updates.enabled': false,
338
-
339
- # Always use network provider for geolocation tests so we bypass the
340
- # macOS dialog raised by the corelocation provider
341
- 'geo.provider.testing': true,
342
-
343
- # Do not scan Wifi
344
- 'geo.wifi.scan': false,
345
-
346
- # No hang monitor
347
- 'hangmonitor.timeout': 0,
348
-
349
- # Show chrome errors and warnings in the error console
350
- 'javascript.options.showInConsole': true,
351
-
352
- # Disable download and usage of OpenH264: and Widevine plugins
353
- 'media.gmp-manager.updateEnabled': false,
354
-
355
- # Disable the GFX sanity window
356
- 'media.sanity-test.disabled': true,
357
-
358
- # Disable experimental feature that is only available in Nightly
359
- 'network.cookie.sameSite.laxByDefault': false,
360
-
361
- # Do not prompt for temporary redirects
362
- 'network.http.prompt-temp-redirect': false,
363
-
364
- # Disable speculative connections so they are not reported as leaking
365
- # when they are hanging around
366
- 'network.http.speculative-parallel-limit': 0,
367
-
368
- # Do not automatically switch between offline and online
369
- 'network.manage-offline-status': false,
370
-
371
- # Make sure SNTP requests do not hit the network
372
- 'network.sntp.pools': server,
373
-
374
- # Disable Flash.
375
- 'plugin.state.flash': 0,
376
-
377
- 'privacy.trackingprotection.enabled': false,
378
-
379
- # Can be removed once Firefox 89 is no longer supported
380
- # https://bugzilla.mozilla.org/show_bug.cgi?id=1710839
381
- 'remote.enabled': true,
382
-
383
- # Don't do network connections for mitm priming
384
- 'security.certerrors.mitm.priming.enabled': false,
385
-
386
- # Local documents have access to all other local documents,
387
- # including directory listings
388
- 'security.fileuri.strict_origin_policy': false,
389
-
390
- # Do not wait for the notification button security delay
391
- 'security.notification_enable_delay': 0,
392
-
393
- # Ensure blocklist updates do not hit the network
394
- 'services.settings.server': "http://#{server}/dummy/blocklist/",
395
-
396
- # Do not automatically fill sign-in forms with known usernames and
397
- # passwords
398
- 'signon.autofillForms': false,
399
-
400
- # Disable password capture, so that tests that include forms are not
401
- # influenced by the presence of the persistent doorhanger notification
402
- 'signon.rememberSignons': false,
403
-
404
- # Disable first-run welcome page
405
- 'startup.homepage_welcome_url': 'about:blank',
406
-
407
- # Disable first-run welcome page
408
- 'startup.homepage_welcome_url.additional': '',
409
-
410
- # Disable browser animations (tabs, fullscreen, sliding alerts)
411
- 'toolkit.cosmeticAnimations.enabled': false,
412
-
413
- # Prevent starting into safe mode after application crashes
414
- 'toolkit.startup.max_resumed_crashes': -1,
415
- }.merge({ # https://github.com/puppeteer/puppeteer/blob/puppeteer-v23.2.2/packages/puppeteer-core/src/node/FirefoxLauncher.ts#L45-L53
416
- # Do not close the window when the last tab gets closed
417
- 'browser.tabs.closeWindowWithLastTab': false,
418
- # Prevent various error message on the console
419
- # jest-puppeteer asserts that no error message is emitted by the console
420
- 'network.cookie.cookieBehavior': 0,
421
- # Temporarily force disable BFCache in parent (https://bit.ly/bug-1732263)
422
- 'fission.bfcacheInParent': false,
423
- # Only enable the CDP protocol
424
- 'remote.active-protocols': 2,
425
- }).merge({ # https://github.com/puppeteer/puppeteer/blob/puppeteer-v23.2.2/packages/puppeteer-core/src/node/FirefoxLauncher.ts#L55-L60
426
- # Force all web content to use a single content process. TODO: remove
427
- # this once Firefox supports mouse event dispatch from the main frame
428
- # context. Once this happens, webContentIsolationStrategy should only
429
- # be set for CDP. See
430
- # https://bugzilla.mozilla.org/show_bug.cgi?id=1773393
431
- 'fission.webContentIsolationStrategy': 0,
432
- })
433
-
434
- default_preferences.merge(extra_prefs)
435
- end
436
-
437
- private def write_preferences(prefs, profile_path)
438
- File.open(File.join(profile_path, 'user.js'), 'w') do |f|
439
- prefs.each do |key, value|
440
- f.write("user_pref(#{JSON.generate(key)}, #{JSON.generate(value)});\n")
441
- end
442
- end
443
- IO.write(File.join(profile_path, 'prefs.js'), "")
444
- end
445
-
446
- private def create_profile(extra_prefs)
447
- Dir.mktmpdir('puppeteer_dev_firefox_profile-', ENV['PUPPETEER_TMP_DIR']).tap do |profile_path|
448
- prefs = default_preferences(extra_prefs)
449
- write_preferences(prefs, profile_path)
450
- end
451
- end
452
- end
453
- end