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
@@ -0,0 +1,24 @@
1
+ class Puppeteer::Geolocation
2
+ # @param latitude [Fixnum]
3
+ # @param longitude [Fixnum]
4
+ # @param accuracy [Fixnum]
5
+ def initialize(latitude:, longitude:, accuracy: 0)
6
+ unless (-180..180).include?(longitude)
7
+ raise ArgumentError.new("Invalid longitude \"#{longitude}\": precondition -180 <= LONGITUDE <= 180 failed.")
8
+ end
9
+ unless (-90..90).include?(latitude)
10
+ raise ArgumentError.new("Invalid latitude \"#{latitude}\": precondition -90 <= LATITUDE <= 90 failed.")
11
+ end
12
+ if accuracy < 0
13
+ raise ArgumentError.new("Invalid accuracy \"#{longitude}\": precondition 0 <= ACCURACY failed.")
14
+ end
15
+
16
+ @latitude = latitude
17
+ @longitude = longitude
18
+ @accuracy = accuracy
19
+ end
20
+
21
+ def to_h
22
+ { latitude: @latitude, longitude: @longitude, accuracy: @accuracy }
23
+ end
24
+ end
@@ -89,7 +89,7 @@ class Puppeteer::Keyboard
89
89
  'Digit6': KeyDefinition.new({ 'keyCode': 54, 'code': 'Digit6', 'shiftKey': '^', 'key': '6' }),
90
90
  'Digit7': KeyDefinition.new({ 'keyCode': 55, 'code': 'Digit7', 'shiftKey': '&', 'key': '7' }),
91
91
  'Digit8': KeyDefinition.new({ 'keyCode': 56, 'code': 'Digit8', 'shiftKey': '*', 'key': '8' }),
92
- 'Digit9': KeyDefinition.new({ 'keyCode': 57, 'code': 'Digit9', 'shiftKey': '\(', 'key': '9' }),
92
+ 'Digit9': KeyDefinition.new({ 'keyCode': 57, 'code': 'Digit9', 'shiftKey': '(', 'key': '9' }),
93
93
  'KeyA': KeyDefinition.new({ 'keyCode': 65, 'code': 'KeyA', 'shiftKey': 'A', 'key': 'a' }),
94
94
  'KeyB': KeyDefinition.new({ 'keyCode': 66, 'code': 'KeyB', 'shiftKey': 'B', 'key': 'b' }),
95
95
  'KeyC': KeyDefinition.new({ 'keyCode': 67, 'code': 'KeyC', 'shiftKey': 'C', 'key': 'c' }),
@@ -235,7 +235,7 @@ class Puppeteer::Keyboard
235
235
  '%': KeyDefinition.new({ 'keyCode': 53, 'key': '%', 'code': 'Digit5' }),
236
236
  '^': KeyDefinition.new({ 'keyCode': 54, 'key': '^', 'code': 'Digit6' }),
237
237
  '&': KeyDefinition.new({ 'keyCode': 55, 'key': '&', 'code': 'Digit7' }),
238
- '(': KeyDefinition.new({ 'keyCode': 57, 'key': '\(', 'code': 'Digit9' }),
238
+ '(': KeyDefinition.new({ 'keyCode': 57, 'key': '(', 'code': 'Digit9' }),
239
239
  'A': KeyDefinition.new({ 'keyCode': 65, 'key': 'A', 'code': 'KeyA' }),
240
240
  'B': KeyDefinition.new({ 'keyCode': 66, 'key': 'B', 'code': 'KeyB' }),
241
241
  'C': KeyDefinition.new({ 'keyCode': 67, 'key': 'C', 'code': 'KeyC' }),
@@ -2,6 +2,7 @@ require_relative './launcher/base'
2
2
  require_relative './launcher/browser_options'
3
3
  require_relative './launcher/chrome'
4
4
  require_relative './launcher/chrome_arg_options'
5
+ require_relative './launcher/firefox'
5
6
  require_relative './launcher/launch_options'
6
7
 
7
8
  # https://github.com/puppeteer/puppeteer/blob/main/src/node/Launcher.ts
@@ -9,11 +10,19 @@ module Puppeteer::Launcher
9
10
  # @param project_root [String]
10
11
  # @param prefereed_revision [String]
11
12
  # @param is_puppeteer_core [String]
12
- # @param product [String] 'chrome' or 'firefox' (not implemented yet)
13
+ # @param product [String] 'chrome' or 'firefox'
13
14
  # @return [Puppeteer::Launcher::Chrome]
14
15
  module_function def new(project_root:, preferred_revision:, is_puppeteer_core:, product:)
16
+ unless is_puppeteer_core
17
+ product ||= ENV['PUPPETEER_PRODUCT']
18
+ end
19
+
15
20
  if product == 'firefox'
16
- raise NotImplementedError.new('FirefoxLauncher is not implemented yet.')
21
+ return Firefox.new(
22
+ project_root: project_root,
23
+ preferred_revision: preferred_revision,
24
+ is_puppeteer_core: is_puppeteer_core,
25
+ )
17
26
  end
18
27
 
19
28
  Chrome.new(
@@ -20,15 +20,25 @@ module Puppeteer::Launcher
20
20
  return executable_path
21
21
  end
22
22
  raise ExecutablePathNotFound.new(
23
- "Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: #{executablePath}",
23
+ "Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: #{executable_path}",
24
24
  )
25
25
  end
26
26
 
27
27
  # temporal logic.
28
- if RUBY_PLATFORM.include?('darwin') # MacOS
29
- '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
28
+ if Puppeteer.env.darwin?
29
+ case self
30
+ when Chrome
31
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
32
+ when Firefox
33
+ '/Applications/Firefox Nightly.app/Contents/MacOS/firefox'
34
+ end
30
35
  else
31
- '/usr/bin/google-chrome'
36
+ case self
37
+ when Chrome
38
+ '/usr/bin/google-chrome'
39
+ when Firefox
40
+ '/usr/bin/firefox'
41
+ end
32
42
  end
33
43
 
34
44
  # const browserFetcher = new BrowserFetcher(launcher._projectRoot);
@@ -28,7 +28,8 @@ module Puppeteer::Launcher
28
28
  # @property {number=} slowMo
29
29
  def initialize(options)
30
30
  @ignore_https_errors = options[:ignore_https_errors] || false
31
- @default_viewport = options[:default_viewport] || Puppeteer::Viewport.new(width: 800, height: 600)
31
+ # `default_viewport: nil` must be respected here.
32
+ @default_viewport = options.key?(:default_viewport) ? options[:default_viewport] : Puppeteer::Viewport.new(width: 800, height: 600)
32
33
  @slow_mo = options[:slow_mo] || 0
33
34
  end
34
35
 
@@ -12,9 +12,9 @@ module Puppeteer::Launcher
12
12
 
13
13
  chrome_arguments =
14
14
  if !@launch_options.ignore_default_args
15
- default_args.to_a
15
+ default_args(options).to_a
16
16
  elsif @launch_options.ignore_default_args.is_a?(Enumerable)
17
- default_args.reject do |arg|
17
+ default_args(options).reject do |arg|
18
18
  @launch_options.ignore_default_args.include?(arg)
19
19
  end.to_a
20
20
  else
@@ -34,7 +34,7 @@ module Puppeteer::Launcher
34
34
 
35
35
  temporary_user_data_dir = nil
36
36
  if chrome_arguments.none? { |arg| arg.start_with?('--user-data-dir') }
37
- temporary_user_data_dir = Dir.mktmpdir('puppeteer_dev_profile-')
37
+ temporary_user_data_dir = Dir.mktmpdir('puppeteer_dev_chrome_profile-')
38
38
  chrome_arguments << "--user-data-dir=#{temporary_user_data_dir}"
39
39
  end
40
40
 
@@ -141,11 +141,7 @@ module Puppeteer::Launcher
141
141
 
142
142
  # @return [DefaultArgs]
143
143
  def default_args(options = nil)
144
- if options.nil?
145
- @default_args ||= DefaultArgs.new(@chrome_arg_options)
146
- else
147
- DefaultArgs.new(ChromeArgOptions.new(options))
148
- end
144
+ DefaultArgs.new(ChromeArgOptions.new(options || {}))
149
145
  end
150
146
 
151
147
  # @return [Puppeteer::Browser]
@@ -206,7 +202,7 @@ module Puppeteer::Launcher
206
202
  resolve_executable_path
207
203
  end
208
204
 
209
- private def product
205
+ def product
210
206
  'chrome'
211
207
  end
212
208
  end
@@ -0,0 +1,385 @@
1
+ require 'tmpdir'
2
+
3
+ # https://github.com/puppeteer/puppeteer/blob/main/src/node/Launcher.ts
4
+ module Puppeteer::Launcher
5
+ class Firefox < Base
6
+ # @param {!(Launcher.LaunchOptions & Launcher.ChromeArgOptions & Launcher.BrowserOptions)=} options
7
+ # @return {!Promise<!Browser>}
8
+ def launch(options = {})
9
+ @chrome_arg_options = ChromeArgOptions.new(options)
10
+ @launch_options = LaunchOptions.new(options)
11
+ @browser_options = BrowserOptions.new(options)
12
+
13
+ firefox_arguments =
14
+ if !@launch_options.ignore_default_args
15
+ default_args(options).to_a
16
+ elsif @launch_options.ignore_default_args.is_a?(Enumerable)
17
+ default_args(options).reject do |arg|
18
+ @launch_options.ignore_default_args.include?(arg)
19
+ end.to_a
20
+ else
21
+ @chrome_arg_options.args.dup
22
+ end
23
+
24
+ if firefox_arguments.none? { |arg| arg.start_with?('--remote-debugging-') }
25
+ firefox_arguments << '--remote-debugging-port=0'
26
+ end
27
+
28
+ temporary_user_data_dir = nil
29
+ if firefox_arguments.none? { |arg| arg.start_with?('--profile') || arg.start_with?('-profile') }
30
+ temporary_user_data_dir = create_profile
31
+ firefox_arguments << "--profile"
32
+ firefox_arguments << temporary_user_data_dir
33
+ end
34
+
35
+ firefox_executable = @launch_options.executable_path || resolve_executable_path
36
+ runner = Puppeteer::BrowserRunner.new(firefox_executable, firefox_arguments, temporary_user_data_dir)
37
+ runner.start(
38
+ handle_SIGHUP: @launch_options.handle_SIGHUP?,
39
+ handle_SIGTERM: @launch_options.handle_SIGTERM?,
40
+ handle_SIGINT: @launch_options.handle_SIGINT?,
41
+ dumpio: @launch_options.dumpio?,
42
+ env: @launch_options.env,
43
+ pipe: @launch_options.pipe?,
44
+ )
45
+
46
+ begin
47
+ connection = runner.setup_connection(
48
+ use_pipe: @launch_options.pipe?,
49
+ timeout: @launch_options.timeout,
50
+ slow_mo: @browser_options.slow_mo,
51
+ preferred_revision: @preferred_revision,
52
+ )
53
+
54
+ browser = Puppeteer::Browser.create(
55
+ connection: connection,
56
+ context_ids: [],
57
+ ignore_https_errors: @browser_options.ignore_https_errors?,
58
+ default_viewport: @browser_options.default_viewport,
59
+ process: runner.proc,
60
+ close_callback: -> { runner.close },
61
+ )
62
+
63
+ browser.wait_for_target(predicate: ->(target) { target.type == 'page' })
64
+
65
+ browser
66
+ rescue
67
+ runner.kill
68
+ raise
69
+ end
70
+ end
71
+
72
+ # @return [Puppeteer::Browser]
73
+ def connect(options = {})
74
+ @browser_options = BrowserOptions.new(options)
75
+ browser_ws_endpoint = options[:browser_ws_endpoint]
76
+ browser_url = options[:browser_url]
77
+ transport = options[:transport]
78
+
79
+ connection =
80
+ if browser_ws_endpoint && browser_url.nil? && transport.nil?
81
+ connect_with_browser_ws_endpoint(browser_ws_endpoint)
82
+ elsif browser_ws_endpoint.nil? && browser_url && transport.nil?
83
+ connect_with_browser_url(browser_url)
84
+ elsif browser_ws_endpoint.nil? && browser_url.nil? && transport
85
+ connect_with_transport(transport)
86
+ else
87
+ raise ArgumentError.new("Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect")
88
+ end
89
+
90
+ result = connection.send_message('Target.getBrowserContexts')
91
+ browser_context_ids = result['browserContextIds']
92
+
93
+ Puppeteer::Browser.create(
94
+ connection: connection,
95
+ context_ids: browser_context_ids,
96
+ ignore_https_errors: @browser_options.ignore_https_errors?,
97
+ default_viewport: @browser_options.default_viewport,
98
+ process: nil,
99
+ close_callback: -> { connection.send_message('Browser.close') },
100
+ )
101
+ end
102
+
103
+ # @return [Puppeteer::Connection]
104
+ private def connect_with_browser_ws_endpoint(browser_ws_endpoint)
105
+ transport = Puppeteer::WebSocketTransport.create(browser_ws_endpoint)
106
+ Puppeteer::Connection.new(browser_ws_endpoint, transport, @browser_options.slow_mo)
107
+ end
108
+
109
+ # @return [Puppeteer::Connection]
110
+ private def connect_with_browser_url(browser_url)
111
+ require 'net/http'
112
+ uri = URI(browser_url)
113
+ uri.path = '/json/version'
114
+ response_body = Net::HTTP.get(uri)
115
+ json = JSON.parse(response_body)
116
+ connection_url = json['webSocketDebuggerUrl']
117
+ connect_with_browser_ws_endpoint(connection_url)
118
+ end
119
+
120
+ # @return [Puppeteer::Connection]
121
+ private def connect_with_transport(transport)
122
+ Puppeteer::Connection.new('', transport, @browser_options.slow_mo)
123
+ end
124
+
125
+ # @return {string}
126
+ def executable_path
127
+ resolve_executable_path
128
+ end
129
+
130
+ def product
131
+ 'firefox'
132
+ end
133
+
134
+ class DefaultArgs
135
+ include Enumerable
136
+
137
+ # @param options [Launcher::ChromeArgOptions]
138
+ def initialize(chrome_arg_options)
139
+ firefox_arguments = ['--no-remote', '--foreground']
140
+
141
+ # if (os.platform().startsWith('win')) {
142
+ # firefoxArguments.push('--wait-for-browser');
143
+ # }
144
+
145
+ if chrome_arg_options.user_data_dir
146
+ firefox_arguments << "--profile"
147
+ firefox_arguments << chrome_arg_options.user_data_dir
148
+ end
149
+
150
+ if chrome_arg_options.headless?
151
+ firefox_arguments << '--headless'
152
+ end
153
+
154
+ if chrome_arg_options.devtools?
155
+ firefox_arguments << '--devtools'
156
+ end
157
+
158
+ if chrome_arg_options.args.all? { |arg| arg.start_with?('-') }
159
+ firefox_arguments << 'about:blank'
160
+ end
161
+
162
+ firefox_arguments.concat(chrome_arg_options.args)
163
+
164
+ @firefox_arguments = firefox_arguments
165
+ end
166
+
167
+ def each(&block)
168
+ @firefox_arguments.each do |opt|
169
+ block.call(opt)
170
+ end
171
+ end
172
+ end
173
+
174
+ # @return [DefaultArgs]
175
+ def default_args(options = nil)
176
+ DefaultArgs.new(ChromeArgOptions.new(options || {}))
177
+ end
178
+
179
+ private def create_profile(extra_prefs = {})
180
+ Dir.mktmpdir('puppeteer_dev_firefox_profile-').tap do |profile_path|
181
+ server = 'dummy.test'
182
+ default_preferences = {
183
+ # Make sure Shield doesn't hit the network.
184
+ 'app.normandy.api_url': '',
185
+ # Disable Firefox old build background check
186
+ 'app.update.checkInstallTime': false,
187
+ # Disable automatically upgrading Firefox
188
+ 'app.update.disabledForTesting': true,
189
+
190
+ # Increase the APZ content response timeout to 1 minute
191
+ 'apz.content_response_timeout': 60000,
192
+
193
+ # Prevent various error message on the console
194
+ # jest-puppeteer asserts that no error message is emitted by the console
195
+ 'browser.contentblocking.features.standard': '-tp,tpPrivate,cookieBehavior0,-cm,-fp',
196
+
197
+ # Enable the dump function: which sends messages to the system
198
+ # console
199
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1543115
200
+ 'browser.dom.window.dump.enabled': true,
201
+ # Disable topstories
202
+ 'browser.newtabpage.activity-stream.feeds.system.topstories': false,
203
+ # Always display a blank page
204
+ 'browser.newtabpage.enabled': false,
205
+ # Background thumbnails in particular cause grief: and disabling
206
+ # thumbnails in general cannot hurt
207
+ 'browser.pagethumbnails.capturing_disabled': true,
208
+
209
+ # Disable safebrowsing components.
210
+ 'browser.safebrowsing.blockedURIs.enabled': false,
211
+ 'browser.safebrowsing.downloads.enabled': false,
212
+ 'browser.safebrowsing.malware.enabled': false,
213
+ 'browser.safebrowsing.passwords.enabled': false,
214
+ 'browser.safebrowsing.phishing.enabled': false,
215
+
216
+ # Disable updates to search engines.
217
+ 'browser.search.update': false,
218
+ # Do not restore the last open set of tabs if the browser has crashed
219
+ 'browser.sessionstore.resume_from_crash': false,
220
+ # Skip check for default browser on startup
221
+ 'browser.shell.checkDefaultBrowser': false,
222
+
223
+ # Disable newtabpage
224
+ 'browser.startup.homepage': 'about:blank',
225
+ # Do not redirect user when a milstone upgrade of Firefox is detected
226
+ 'browser.startup.homepage_override.mstone': 'ignore',
227
+ # Start with a blank page about:blank
228
+ 'browser.startup.page': 0,
229
+
230
+ # Do not allow background tabs to be zombified on Android: otherwise for
231
+ # tests that open additional tabs: the test harness tab itself might get
232
+ # unloaded
233
+ 'browser.tabs.disableBackgroundZombification': false,
234
+ # Do not warn when closing all other open tabs
235
+ 'browser.tabs.warnOnCloseOtherTabs': false,
236
+ # Do not warn when multiple tabs will be opened
237
+ 'browser.tabs.warnOnOpen': false,
238
+
239
+ # Disable the UI tour.
240
+ 'browser.uitour.enabled': false,
241
+ # Turn off search suggestions in the location bar so as not to trigger
242
+ # network connections.
243
+ 'browser.urlbar.suggest.searches': false,
244
+ # Disable first run splash page on Windows 10
245
+ 'browser.usedOnWindows10.introURL': '',
246
+ # Do not warn on quitting Firefox
247
+ 'browser.warnOnQuit': false,
248
+
249
+ # Defensively disable data reporting systems
250
+ 'datareporting.healthreport.documentServerURI': "http://#{server}/dummy/healthreport/",
251
+ 'datareporting.healthreport.logging.consoleEnabled': false,
252
+ 'datareporting.healthreport.service.enabled': false,
253
+ 'datareporting.healthreport.service.firstRun': false,
254
+ 'datareporting.healthreport.uploadEnabled': false,
255
+
256
+ # Do not show datareporting policy notifications which can interfere with tests
257
+ 'datareporting.policy.dataSubmissionEnabled': false,
258
+ 'datareporting.policy.dataSubmissionPolicyBypassNotification': true,
259
+
260
+ # DevTools JSONViewer sometimes fails to load dependencies with its require.js.
261
+ # This doesn't affect Puppeteer but spams console (Bug 1424372)
262
+ 'devtools.jsonview.enabled': false,
263
+
264
+ # Disable popup-blocker
265
+ 'dom.disable_open_during_load': false,
266
+
267
+ # Enable the support for File object creation in the content process
268
+ # Required for |Page.setFileInputFiles| protocol method.
269
+ 'dom.file.createInChild': true,
270
+
271
+ # Disable the ProcessHangMonitor
272
+ 'dom.ipc.reportProcessHangs': false,
273
+
274
+ # Disable slow script dialogues
275
+ 'dom.max_chrome_script_run_time': 0,
276
+ 'dom.max_script_run_time': 0,
277
+
278
+ # Only load extensions from the application and user profile
279
+ # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
280
+ 'extensions.autoDisableScopes': 0,
281
+ 'extensions.enabledScopes': 5,
282
+
283
+ # Disable metadata caching for installed add-ons by default
284
+ 'extensions.getAddons.cache.enabled': false,
285
+
286
+ # Disable installing any distribution extensions or add-ons.
287
+ 'extensions.installDistroAddons': false,
288
+
289
+ # Disabled screenshots extension
290
+ 'extensions.screenshots.disabled': true,
291
+
292
+ # Turn off extension updates so they do not bother tests
293
+ 'extensions.update.enabled': false,
294
+
295
+ # Turn off extension updates so they do not bother tests
296
+ 'extensions.update.notifyUser': false,
297
+
298
+ # Make sure opening about:addons will not hit the network
299
+ 'extensions.webservice.discoverURL': "http://#{server}/dummy/discoveryURL",
300
+
301
+ # Allow the application to have focus even it runs in the background
302
+ 'focusmanager.testmode': true,
303
+ # Disable useragent updates
304
+ 'general.useragent.updates.enabled': false,
305
+ # Always use network provider for geolocation tests so we bypass the
306
+ # macOS dialog raised by the corelocation provider
307
+ 'geo.provider.testing': true,
308
+ # Do not scan Wifi
309
+ 'geo.wifi.scan': false,
310
+ # No hang monitor
311
+ 'hangmonitor.timeout': 0,
312
+ # Show chrome errors and warnings in the error console
313
+ 'javascript.options.showInConsole': true,
314
+
315
+ # Disable download and usage of OpenH264: and Widevine plugins
316
+ 'media.gmp-manager.updateEnabled': false,
317
+ # Prevent various error message on the console
318
+ # jest-puppeteer asserts that no error message is emitted by the console
319
+ 'network.cookie.cookieBehavior': 0,
320
+
321
+ # Do not prompt for temporary redirects
322
+ 'network.http.prompt-temp-redirect': false,
323
+
324
+ # Disable speculative connections so they are not reported as leaking
325
+ # when they are hanging around
326
+ 'network.http.speculative-parallel-limit': 0,
327
+
328
+ # Do not automatically switch between offline and online
329
+ 'network.manage-offline-status': false,
330
+
331
+ # Make sure SNTP requests do not hit the network
332
+ 'network.sntp.pools': server,
333
+
334
+ # Disable Flash.
335
+ 'plugin.state.flash': 0,
336
+
337
+ 'privacy.trackingprotection.enabled': false,
338
+
339
+ # Enable Remote Agent
340
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1544393
341
+ 'remote.enabled': true,
342
+
343
+ # Don't do network connections for mitm priming
344
+ 'security.certerrors.mitm.priming.enabled': false,
345
+ # Local documents have access to all other local documents,
346
+ # including directory listings
347
+ 'security.fileuri.strict_origin_policy': false,
348
+ # Do not wait for the notification button security delay
349
+ 'security.notification_enable_delay': 0,
350
+
351
+ # Ensure blocklist updates do not hit the network
352
+ 'services.settings.server': "http://#{server}/dummy/blocklist/",
353
+
354
+ # Do not automatically fill sign-in forms with known usernames and
355
+ # passwords
356
+ 'signon.autofillForms': false,
357
+ # Disable password capture, so that tests that include forms are not
358
+ # influenced by the presence of the persistent doorhanger notification
359
+ 'signon.rememberSignons': false,
360
+
361
+ # Disable first-run welcome page
362
+ 'startup.homepage_welcome_url': 'about:blank',
363
+
364
+ # Disable first-run welcome page
365
+ 'startup.homepage_welcome_url.additional': '',
366
+
367
+ # Disable browser animations (tabs, fullscreen, sliding alerts)
368
+ 'toolkit.cosmeticAnimations.enabled': false,
369
+
370
+ # Prevent starting into safe mode after application crashes
371
+ 'toolkit.startup.max_resumed_crashes': -1,
372
+ }
373
+
374
+ preferences = default_preferences.merge(extra_prefs)
375
+
376
+ File.open(File.join(profile_path, 'user.js'), 'w') do |f|
377
+ preferences.each do |key, value|
378
+ f.write("user_pref(#{JSON.generate(key)}, #{JSON.generate(value)});\n")
379
+ end
380
+ end
381
+ IO.write(File.join(profile_path, 'prefs.js'), "")
382
+ end
383
+ end
384
+ end
385
+ end