зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1693004 - [geckodriver] Add support for the "webSocketUrl" capability. r=webdriver-reviewers,jgraham
The "webSocketUrl" capability offers an opt-in mechanism for WebDriver HTTP implementations to make use of WebDriver BiDi, the bi-directional protocol based on a WebSocket connection. If the used version of Firefox has support for WebDriver BiDi enabled, and the capability is set to "true", it will be returned as part of the "New Session" capabilities and contains the host and port of the WebSocket server. Differential Revision: https://phabricator.services.mozilla.com/D116689
This commit is contained in:
Родитель
1e01a194c0
Коммит
b72f22094f
|
@ -229,6 +229,7 @@ fn set_prefs(
|
||||||
|
|
||||||
// Deprecated with geckodriver 0.30.0, but left for backward compatibility.
|
// Deprecated with geckodriver 0.30.0, but left for backward compatibility.
|
||||||
prefs.insert("marionette.log.level", logging::max_level().into());
|
prefs.insert("marionette.log.level", logging::max_level().into());
|
||||||
|
prefs.insert("remote.log.level", logging::max_level().into());
|
||||||
|
|
||||||
prefs.write().map_err(|e| {
|
prefs.write().map_err(|e| {
|
||||||
WebDriverError::new(
|
WebDriverError::new(
|
||||||
|
|
|
@ -154,6 +154,10 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn accept_proxy(&mut self, _: &Capabilities, _: &Capabilities) -> WebDriverResult<bool> {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
fn set_window_rect(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
|
fn set_window_rect(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
@ -173,8 +177,10 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept_proxy(&mut self, _: &Capabilities, _: &Capabilities) -> WebDriverResult<bool> {
|
fn web_socket_url(&mut self, caps: &Capabilities) -> WebDriverResult<bool> {
|
||||||
Ok(true)
|
self.browser_version(caps)?
|
||||||
|
.map(|v| self.compare_browser_version(&v, ">=90"))
|
||||||
|
.unwrap_or(Ok(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_custom(&mut self, name: &str, value: &Value) -> WebDriverResult<()> {
|
fn validate_custom(&mut self, name: &str, value: &Value) -> WebDriverResult<()> {
|
||||||
|
@ -410,12 +416,7 @@ impl FirefoxOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(args) = rv.args.as_ref() {
|
if let Some(args) = rv.args.as_ref() {
|
||||||
let os_args = parse_args(
|
let os_args = parse_args(args.iter().map(OsString::from).collect::<Vec<_>>().iter());
|
||||||
args.iter()
|
|
||||||
.map(OsString::from)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.iter(),
|
|
||||||
);
|
|
||||||
if let Some(path) = get_arg_value(os_args.iter(), Arg::Profile) {
|
if let Some(path) = get_arg_value(os_args.iter(), Arg::Profile) {
|
||||||
if rv.profile.is_some() {
|
if rv.profile.is_some() {
|
||||||
return Err(WebDriverError::new(
|
return Err(WebDriverError::new(
|
||||||
|
@ -462,6 +463,27 @@ impl FirefoxOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(json) = matched.get("webSocketUrl") {
|
||||||
|
let use_web_socket = json.as_bool().ok_or_else(|| {
|
||||||
|
WebDriverError::new(
|
||||||
|
ErrorStatus::InvalidArgument,
|
||||||
|
"webSocketUrl is not a boolean",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if use_web_socket {
|
||||||
|
let mut remote_args = Vec::new();
|
||||||
|
remote_args.push("--remote-debugging-port".to_owned());
|
||||||
|
remote_args.push("0".to_owned());
|
||||||
|
|
||||||
|
if let Some(ref mut args) = rv.args {
|
||||||
|
args.append(&mut remote_args);
|
||||||
|
} else {
|
||||||
|
rv.args = Some(remote_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(rv)
|
Ok(rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,6 +866,52 @@ mod tests {
|
||||||
assert_eq!(opts.prefs, vec![]);
|
assert_eq!(opts.prefs, vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fx_options_from_capabilities_with_websocket_url_not_set() {
|
||||||
|
let mut caps = Capabilities::new();
|
||||||
|
|
||||||
|
let opts = FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps)
|
||||||
|
.expect("Valid Firefox options");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
opts.args.is_none(),
|
||||||
|
"CLI arguments for Firefox unexpectedly found"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fx_options_from_capabilities_with_websocket_url_false() {
|
||||||
|
let mut caps = Capabilities::new();
|
||||||
|
caps.insert("webSocketUrl".into(), json!(false));
|
||||||
|
|
||||||
|
let opts = FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps)
|
||||||
|
.expect("Valid Firefox options");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
opts.args.is_none(),
|
||||||
|
"CLI arguments for Firefox unexpectedly found"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fx_options_from_capabilities_with_websocket_url_true() {
|
||||||
|
let mut caps = Capabilities::new();
|
||||||
|
caps.insert("webSocketUrl".into(), json!(true));
|
||||||
|
|
||||||
|
let opts = FirefoxOptions::from_capabilities(None, AndroidStorageInput::Auto, &mut caps)
|
||||||
|
.expect("Valid Firefox options");
|
||||||
|
|
||||||
|
if let Some(args) = opts.args {
|
||||||
|
let mut iter = args.iter();
|
||||||
|
assert!(iter
|
||||||
|
.find(|&arg| arg == &"--remote-debugging-port".to_owned())
|
||||||
|
.is_some());
|
||||||
|
assert_eq!(iter.next(), Some(&"0".to_owned()));
|
||||||
|
} else {
|
||||||
|
assert!(false, "CLI arguments for Firefox not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fx_options_from_capabilities_with_debugger_address_not_set() {
|
fn fx_options_from_capabilities_with_debugger_address_not_set() {
|
||||||
let mut caps = Capabilities::new();
|
let mut caps = Capabilities::new();
|
||||||
|
@ -867,7 +935,7 @@ mod tests {
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
opts.args.is_none(),
|
opts.args.is_none(),
|
||||||
"CLI arguments for remote protocol unexpectedly found"
|
"CLI arguments for Firefox unexpectedly found"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,7 +954,7 @@ mod tests {
|
||||||
.is_some());
|
.is_some());
|
||||||
assert_eq!(iter.next(), Some(&"0".to_owned()));
|
assert_eq!(iter.next(), Some(&"0".to_owned()));
|
||||||
} else {
|
} else {
|
||||||
assert!(false, "CLI arguments for remote protocol not found");
|
assert!(false, "CLI arguments for Firefox not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(opts
|
assert!(opts
|
||||||
|
|
|
@ -50,6 +50,9 @@ pub trait BrowserCapabilities {
|
||||||
/// Indicates that interactability checks will be applied to `<input type=file>`.
|
/// Indicates that interactability checks will be applied to `<input type=file>`.
|
||||||
fn strict_file_interactability(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
fn strict_file_interactability(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
||||||
|
|
||||||
|
/// Whether a WebSocket URL for the created session has to be returned
|
||||||
|
fn web_socket_url(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
||||||
|
|
||||||
fn accept_proxy(
|
fn accept_proxy(
|
||||||
&mut self,
|
&mut self,
|
||||||
proxy_settings: &Map<String, Value>,
|
proxy_settings: &Map<String, Value>,
|
||||||
|
@ -132,7 +135,8 @@ impl SpecNewSessionParameters {
|
||||||
match &**key {
|
match &**key {
|
||||||
x @ "acceptInsecureCerts"
|
x @ "acceptInsecureCerts"
|
||||||
| x @ "setWindowRect"
|
| x @ "setWindowRect"
|
||||||
| x @ "strictFileInteractability" => {
|
| x @ "strictFileInteractability"
|
||||||
|
| x @ "webSocketUrl" => {
|
||||||
if !value.is_boolean() {
|
if !value.is_boolean() {
|
||||||
return Err(WebDriverError::new(
|
return Err(WebDriverError::new(
|
||||||
ErrorStatus::InvalidArgument,
|
ErrorStatus::InvalidArgument,
|
||||||
|
@ -169,6 +173,12 @@ impl SpecNewSessionParameters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// With a value of `false` the capability needs to be removed.
|
||||||
|
if let Some(Value::Bool(false)) = capabilities.get(&"webSocketUrl".to_string()) {
|
||||||
|
capabilities.remove(&"webSocketUrl".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(capabilities)
|
Ok(capabilities)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,6 +526,15 @@ impl CapabilitiesMatching for SpecNewSessionParameters {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"webSocketUrl" => {
|
||||||
|
if value.as_bool().unwrap_or(false)
|
||||||
|
&& !browser_capabilities
|
||||||
|
.web_socket_url(merged)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
name => {
|
name => {
|
||||||
if name.contains(':') {
|
if name.contains(':') {
|
||||||
if !browser_capabilities
|
if !browser_capabilities
|
||||||
|
|
Загрузка…
Ссылка в новой задаче