Open MatzFan opened 1 month ago
@MatzFan, thank you for creating this issue. We will troubleshoot it as soon as we can.
Triage this issue by using labels.
If information is missing, add a helpful comment and then I-issue-template
label.
If the issue is a question, add the I-question
label.
If the issue is valid but there is no time to troubleshoot it, consider adding the help wanted
label.
If the issue requires changes or fixes from an external project (e.g., ChromeDriver, GeckoDriver, MSEdgeDriver, W3C),
add the applicable G-*
label, and it will provide the correct link and auto-close the
issue.
After troubleshooting the issue, please add the R-awaiting answer
label.
Thank you!
So as a proof of concept I've created a Ruby module to do this. It can get and set prefs exactly as set out above. I've omitted the tests here for brevity, please let me know if you are interested in supporting this - or if I am reinventing a wheel!
module Selenium
module WebDriver
module Firefox
# representation of a Firefox pref API: https://firefox-source-docs.mozilla.org/devtools/preferences.html
class Preference
PREF_TYPES = { 'PREF_BOOL' => 128, 'PREF_INT' => 64, 'PREF_INVALID' => 0, 'PREF_STRING' => 32 }.freeze
GET_METHODS = { 0 => 'getStringPref', 32 => 'getStringPref', 64 => 'getIntPref', 128 => 'getBoolPref' }.freeze
SET_METHODS = { 32 => 'setStringPref', 64 => 'setIntPref', 128 => 'setBoolPref' }.freeze
def initialize(driver)
@driver = driver
end
def [](str)
execute_script_and_preserve_context str
end
def []=(str, val)
execute_script_and_preserve_context str, val
end
private
def execute_script_and_preserve_context(str, val = nil)
@driver.in_chrome_context { @driver.execute_script(script_string(str, val)) }
end
def script_string(str, val)
val ? setter_script(str, val) : getter_script(str)
end
def getter_script(str)
type = pref_type(str)
"return Services.prefs.#{GET_METHODS[type]}('#{str}'#{default(type)})"
end
def default(type)
type.zero? ? ", ''" : '' # empty string default arg if pref not found, otherwise no default arg
end
def setter_script(str, val)
"Services.prefs.#{set_method(str, val)}('#{str}', #{quote_str(val)})"
end
def set_method(str, val)
type = pref_type(str)
return SET_METHODS[type] unless type.zero?
return 'setBoolPref' if val.instance_of?(TrueClass) || val.instance_of?(FalseClass)
return 'setIntPref' if val.is_a? Integer
'setStringPref' # everthing else gets set as a string
end
def pref_type(string)
@driver.execute_script("return Services.prefs.getPrefType('#{string}')")
end
def quote_str(value)
value.is_a?(String) ? "'#{value}'" : value
end
end
# adds Driver#pref method and [] and []= methods on that object
module FirefoxPrefs
def pref
in_chrome_context { Preference.new(self) }
end
def in_chrome_context
old_context = context
self.context = 'chrome'
yield
ensure
self.context = old_context
end
end
class Driver
prepend FirefoxPrefs
end
end
end
end
FWIW here is an example of a Python project using Selenium which uses the Firefox Prefs JS API to set driver prefs.
We are looking for projects to host on https://github.com/seleniumhq-community/, if you wish to work on this, it would be a great plugin that can be added as a dependency by any user. Would you be interested in doing that?
@diemol if you are not interested in incorporating such functionality directly into Selenium (it adds a dependency on the Firefox Prefs JS API) I was planning to simply release my code as a Ruby gem. Are Selenium Community repos simply mirrors of contributors' projects? If so I see no reason why I wouldn't set up a mirror there - and also for my Selenium Tor Browser project too. Can you point me to the docs on Selenium Community?
Selenium is meant to be a base library where users can build things on top. This use case is the perfect example of that.
The community org is meant to host projects driven and owned by the community, with the advantage of using the Selenium name to promote them. We don't have any formal docs because we are getting started. If you are interested, please join our Slack workspace, and we can chat about this.
Feature and motivation
I would like to be able to get the value of a preference set in
about:config
dynamically. These are set when instantiating a driver viaOptions[:prefs]
values). I'd also like to be able to dynamically set a preference.The JS API for Firefox prefs seems straightforward. I do note that Firefox CDP is being deprecated IFO BiDi, could someone confirm whether this JS API is part of that scope or not?
Usage example
From your own Ruby tests I see here that you get a preference value like so, by passing a JS string to the
Driver#execute_script
method.Something like this would be much better:
And the equivalent to set a pref value: