Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mozilla/geckodriver.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Skupin <mail@hskupin.info>2019-01-29 01:24:52 +0300
committerHenrik Skupin <mail@hskupin.info>2019-01-29 01:26:07 +0300
commit17945ac838449dda1defc8cda0c6dadb042519b2 (patch)
treec95252edc1cfa7665d5d1a70cff10ed2673fde24
parentdb536edd5187fad9282d8c7670e844f4cb5dba3b (diff)
import of v0.24.0v0.24.0
-rw-r--r--.travis.yml11
-rw-r--r--CHANGES.md64
-rw-r--r--Cargo.toml14
-rw-r--r--README.md17
-rw-r--r--doc/Support.md13
-rw-r--r--doc/Testing.md9
-rw-r--r--doc/TraceLogs.md4
-rw-r--r--doc/index.rst4
-rw-r--r--mach_commands.py43
-rw-r--r--moz.build18
-rw-r--r--src/capabilities.rs94
-rw-r--r--src/command.rs51
-rw-r--r--src/main.rs18
-rw-r--r--src/marionette.rs239
-rw-r--r--src/prefs.rs29
15 files changed, 383 insertions, 245 deletions
diff --git a/.travis.yml b/.travis.yml
index 49883e1..707f241 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,17 +15,6 @@ matrix:
include:
- os: linux
env:
- - TARGET=armv7-unknown-linux-gnueabihf
- - NAME=arm7hf
- - EXT=tar.gz
- addons:
- apt:
- packages: &armhf
- - gcc-arm-linux-gnueabihf
- - libc6-armhf-cross
- - libc6-dev-armhf-cross
- - os: linux
- env:
- TARGET=x86_64-unknown-linux-musl
- NAME=linux64
- EXT=tar.gz
diff --git a/CHANGES.md b/CHANGES.md
index 2b28eed..0dd7731 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -4,6 +4,69 @@ Change log
All notable changes to this program is documented in this file.
+0.24.0 [917474f3473e] (2018-01-28)
+------------------------------------
+
+### Added
+
+- Introduces `strictFileInteractability` capability
+
+ The new capabilitiy indicates if strict interactability checks
+ should be applied to `<input type=file>` elements. As strict
+ interactability checks are off by default, there is a change
+ in behaviour when using [Element Send Keys] with hidden file
+ upload controls.
+
+- Added new endpoint `GET /session/{session id}/moz/screenshot/full`
+ for taking full document screenshots, thanks to Greg Fraley.
+
+- Added new `--marionette-host <HOSTNAME>` flag for binding to a
+ particular interface/IP layer on the system.
+
+- Added new endpoint `POST /session/{session_id}/window/new`
+ for the [New Window] command to create a new top-level browsing
+ context, which can be either a window or a tab.
+
+- When using the preference `devtools.console.stdout.content` set to
+ `true` logging of console API calls like `info()`, `warn()`, and
+ `error()` can be routed to stdout.
+
+- geckodriver now sets the `app.update.disabledForTesting` preference
+ to prevent Firefox >= 65 from automatically updating whilst under
+ automation.
+
+### Removed
+
+- Turned off builds for arm7hf, which will no longer be released but
+ can still be built from the source.
+
+### Changed
+
+- Allow file uploads to hidden `<input type=file>` elements
+
+ Through a series of changes to the WebDriver specification,
+ geckodriver is now aligned with chromedriver’s behaviour that
+ allows interaction with hidden `<input type=file>` elements.
+
+ This allows WebDriver to be used with various popular web
+ frameworks that—through indirection—hides the file upload control
+ and invokes it through other means.
+
+- Allow use of an indefinite script timeout for the [Set Timeouts]
+ command, thanks to reimu.
+
+### Fixed
+
+- Corrected `Content-Type` of response header to `utf-8` to fix
+ an HTTP/1.1 compatibility bug.
+
+- Relaxed the deserialization of timeouts parameters to allow unknown
+ fields for the [Set Timeouts] command.
+
+- Fixed a regression in the [Take Element Screenshot] to not screenshot
+ the viewport, but the requested element.
+
+
0.23.0 (2018-10-03)
-------------------
@@ -1078,6 +1141,7 @@ and greater.
[insecure certificate]: https://w3c.github.io/webdriver/webdriver-spec.html#dfn-insecure-certificate
[Minimize Window]: https://w3c.github.io/webdriver/webdriver-spec.html#minimize-window
[New Session]: https://w3c.github.io/webdriver/webdriver-spec.html#new-session
+[New Window]: https://developer.mozilla.org/en-US/docs/Web/WebDriver/Commands/New_Window
[Send Alert Text]: https://w3c.github.io/webdriver/webdriver-spec.html#send-alert-text
[Set Timeouts]: https://w3c.github.io/webdriver/webdriver-spec.html#set-timeouts
[Set Window Rect]: https://w3c.github.io/webdriver/webdriver-spec.html#set-window-rect
diff --git a/Cargo.toml b/Cargo.toml
index 9fe2066..b5232c0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "geckodriver"
-version = "0.23.0"
+version = "0.24.0"
description = "Proxy for using WebDriver clients to interact with Gecko-based browsers."
keywords = ["webdriver", "w3c", "httpd", "mozilla", "firefox"]
repository = "https://hg.mozilla.org/mozilla-central/file/tip/testing/geckodriver"
@@ -9,21 +9,21 @@ license = "MPL-2.0"
publish = false
[dependencies]
-base64 = "0.9"
+base64 = "0.10"
chrono = "0.4.6"
clap = { version = "^2.19", default-features = false, features = ["suggestions", "wrap_help"] }
hyper = "0.12"
lazy_static = "1.0"
log = { version = "0.4", features = ["std"] }
-mozprofile = "0.4.0"
-mozrunner = "0.8.0"
-mozversion = "0.1.3"
+mozprofile = "0.5.0"
+mozrunner = "0.9.0"
+mozversion = "0.2.0"
regex = "1.0"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
-uuid = { version = "0.5", features = ["v4"] }
-webdriver = "0.38.0"
+uuid = { version = "0.6", features = ["v4"] }
+webdriver = "0.39.0"
zip = "0.4"
[[bin]]
diff --git a/README.md b/README.md
index 4c23aa1..e7bdc13 100644
--- a/README.md
+++ b/README.md
@@ -40,16 +40,29 @@ Documentation
* [C# API](https://seleniumhq.github.io/selenium/docs/api/dotnet/)
* [JavaScript API](https://seleniumhq.github.io/selenium/docs/api/javascript/)
* [Java API](https://seleniumhq.github.io/selenium/docs/api/java/)
+ * [Perl API](https://metacpan.org/pod/Selenium::Remote::Driver)
* [Python API](https://seleniumhq.github.io/selenium/docs/api/py/)
* [Ruby API](https://seleniumhq.github.io/selenium/docs/api/rb/)
* [geckodriver usage](https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/Usage.html)
+ * [Supported platforms](https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/Support.html)
* [Firefox capabilities](https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/Capabilities.html)
* [Capabilities example](https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/Capabilities.html#capabilities-example)
* [Enabling trace logs](https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/TraceLogs.html)
* [Analyzing crash data from Firefox](https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/CrashReports.html)
-* [Contributing](https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/index.html#for-developers)
+* [Contributing](https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/#for-developers)
+
+
+Source code
+-----------
+
+geckodriver’s canonical source code can be found in [mozilla-central].
+We only use this GitHub repository for issue tracking and making releases.
+See our [contribution documentation] for more information.
+
+[mozilla-central]: https://hg.mozilla.org/mozilla-central/file/tip/testing/geckodriver
+[contribution documentation]: https://firefox-source-docs.mozilla.org/testing/geckodriver/geckodriver/#for-developers
Contact
@@ -59,7 +72,7 @@ The mailing list for geckodriver discussion is
tools-marionette@lists.mozilla.org ([subscribe], [archive]).
There is also an IRC channel to talk about using and developing
-geckodriver in #ateam on irc.mozilla.org.
+geckodriver in #interop on irc.mozilla.org.
[subscribe]: https://lists.mozilla.org/listinfo/tools-marionette
[archive]: https://lists.mozilla.org/pipermail/tools-marionette/
diff --git a/doc/Support.md b/doc/Support.md
index 5eba885..5adfb52 100644
--- a/doc/Support.md
+++ b/doc/Support.md
@@ -4,6 +4,12 @@ Supported platforms
The following table shows a mapping between [geckodriver releases],
supported versions of Firefox, and required Selenium version:
+<style type="text/css">
+ table { width: 100%; margin-bottom: 2em; }
+ table, th, td { border: solid gray 1px; }
+ td { padding: 5px 10px; text-align: center; }
+</style>
+
<table>
<thead>
<tr>
@@ -18,6 +24,11 @@ supported versions of Firefox, and required Selenium version:
</thead>
<tr>
+ <td>0.23.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>57
+ <td>n/a
+ <tr>
<td>0.22.0
<td>≥ 3.11 (3.14 Python)
<td>57
@@ -57,7 +68,7 @@ supported versions of Firefox, and required Selenium version:
<td>≥ 3.4
<td>52
<td>62
-
+</table>
Clients
-------
diff --git a/doc/Testing.md b/doc/Testing.md
index 063c95b..5ed2f9f 100644
--- a/doc/Testing.md
+++ b/doc/Testing.md
@@ -28,12 +28,13 @@ As these are functional integration tests and pop up Firefox windows
sporadically, a helpful tip is to surpress the window whilst you
are running them by using Firefox’ [headless mode]:
- % MOZ_HEADLESS=1 ./mach wpt testing/web-platform/tests/webdriver
+ % ./mach wpt --headless testing/web-platform/tests/webdriver
-In addition to the `MOZ_HEADLESS` output variable there is also
-`MOZ_HEADLESS_WIDTH` and `MOZ_HEADLESS_HEIGHT` to control the
+The `--headless` flag is equivalent to setting the `MOZ_HEADLESS`
+output variable. In addition to `MOZ_HEADLESS` there is also
+`MOZ_HEADLESS_WIDTH` and `MOZ_HEADLESS_HEIGHT` for controlling the
dimensions of the no-op virtual display. This is similar to using
-xvfb(1) which you may know from the X windowing system, but has
+Xvfb(1) which you may know from the X windowing system, but has
the additional benefit of also working on macOS and Windows.
As you get in to development of geckodriver and Marionette you will
diff --git a/doc/TraceLogs.md b/doc/TraceLogs.md
index 787a6cb..791f838 100644
--- a/doc/TraceLogs.md
+++ b/doc/TraceLogs.md
@@ -140,7 +140,7 @@ As with C#, the log output is helpfully propagated to stdout.
Python
------
-The Selenium [Python client] comes with an
+The Selenium [Python client] comes with a
[`selenium.webdriver.firefox.options.Options`] helper that can
be used programmatically to construct the [`moz:firefoxOptions`]
capabilities object:
@@ -150,7 +150,7 @@ capabilities object:
opts = Options()
opts.log.level = "trace"
- driver = Firefox(firefox_options=opts)
+ driver = Firefox(options=opts)
The log output is stored in a file called _geckodriver.log_ in your
script’s current working directory.
diff --git a/doc/index.rst b/doc/index.rst
index 9f841fd..cb159de 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -47,10 +47,10 @@ For developers
Communication
=============
-The mailing list for Marionette discussion is
+The mailing list for geckodriver discussion is
tools-marionette@lists.mozilla.org (`subscribe`_, `archive`_).
-If you prefer real-time chat, there is often someone in the #ateam IRC
+If you prefer real-time chat, there is often someone in the #interop IRC
channel on irc.mozilla.org. Don’t ask if you may ask a question;
just go ahead and ask, and please wait for an answer as we might
not be in your timezone.
diff --git a/mach_commands.py b/mach_commands.py
index a52412e..2dcb7af 100644
--- a/mach_commands.py
+++ b/mach_commands.py
@@ -4,47 +4,47 @@
from __future__ import absolute_import, print_function, unicode_literals
-import argparse
import os
+import logging
from mach.decorators import (
Command,
CommandArgument,
CommandArgumentGroup,
CommandProvider,
- SubCommand,
)
-from mozbuild.base import (
- MachCommandBase,
- MachCommandConditions as conditions,
-)
+from mozbuild.base import MachCommandBase
@CommandProvider
-class GeckoDriover(MachCommandBase):
+class GeckoDriver(MachCommandBase):
@Command("geckodriver",
- category="post-build",
- description="Run the WebDriver implementation for Gecko.")
+ category="post-build",
+ description="Run the WebDriver implementation for Gecko.")
@CommandArgument("--binary", type=str,
- help="Firefox binary (defaults to the local build).")
+ help="Firefox binary (defaults to the local build).")
@CommandArgument("params", nargs="...",
- help="Flags to be passed through to geckodriver.")
+ help="Flags to be passed through to geckodriver.")
@CommandArgumentGroup("debugging")
@CommandArgument("--debug", action="store_true", group="debugging",
- help="Enable the debugger. Not specifying a --debugger option will result in the default debugger being used.")
+ help="Enable the debugger. Not specifying a --debugger "
+ "option will result in the default debugger "
+ "being used.")
@CommandArgument("--debugger", default=None, type=str, group="debugging",
- help="Name of debugger to use.")
- @CommandArgument("--debugger-args", default=None, metavar="params", type=str,
- group="debugging",
- help="Flags to pass to the debugger itself; split as the Bourne shell would.")
+ help="Name of debugger to use.")
+ @CommandArgument("--debugger-args", default=None, metavar="params",
+ type=str, group="debugging",
+ help="Flags to pass to the debugger itself; "
+ "split as the Bourne shell would.")
def run(self, binary, params, debug, debugger, debugger_args):
try:
binpath = self.get_binary_path("geckodriver")
except Exception as e:
print("It looks like geckodriver isn't built. "
- "Add ac_add_options --enable-geckodriver to your mozconfig ",
+ "Add ac_add_options --enable-geckodriver to your "
+ "mozconfig ",
"and run |mach build| to build it.")
print(e)
return 1
@@ -90,17 +90,18 @@ class GeckoDriover(MachCommandBase):
args = [self.debuggerInfo.path] + self.debuggerInfo.args + args
return self.run_process(args=args, ensure_exit_code=False,
- pass_thru=True)
+ pass_thru=True)
@CommandProvider
class GeckoDriverTest(MachCommandBase):
@Command("geckodriver-test",
- category="post-build",
- description="Run geckodriver unit tests.")
+ category="post-build",
+ description="Run geckodriver unit tests.")
@CommandArgument("-v", "--verbose", action="store_true",
- help="Verbose output for what commands the build is running.")
+ help="Verbose output for what"
+ " commands the build is running.")
def test(self, verbose=False, **kwargs):
from mozbuild.controller.building import BuildDriver
diff --git a/moz.build b/moz.build
index 6222abf..1dd7026 100644
--- a/moz.build
+++ b/moz.build
@@ -6,17 +6,15 @@ RUST_PROGRAMS += ["geckodriver"]
# Some Rust build scripts compile C/C++ sources, don't error on warnings for them.
AllowCompilerWarnings()
-# https://bugzil.la/1425365
-if CONFIG["OS_ARCH"] != "WINNT":
- RUST_TESTS = [
- "geckodriver",
- "webdriver",
+RUST_TESTS = [
+ "geckodriver",
+ "webdriver",
- # TODO: Move to mozbase/rust/moz.build once those crates can be
- # tested separately.
- "mozprofile",
- "mozrunner",
- "mozversion",
+ # TODO: Move to mozbase/rust/moz.build once those crates can be
+ # tested separately.
+ "mozprofile",
+ "mozrunner",
+ "mozversion",
]
with Files("**"):
diff --git a/src/capabilities.rs b/src/capabilities.rs
index b25c202..ed85705 100644
--- a/src/capabilities.rs
+++ b/src/capabilities.rs
@@ -1,6 +1,6 @@
use base64;
-use command::LogOptions;
-use logging::Level;
+use crate::command::LogOptions;
+use crate::logging::Level;
use mozprofile::preferences::Pref;
use mozprofile::profile::Profile;
use mozrunner::runner::platform::firefox_default_path;
@@ -136,7 +136,10 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
fn accept_insecure_certs(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
let version_str = self.version();
if let Some(x) = version_str {
- Ok(try!(Version::from_str(&*x).or_else(|x| Err(convert_version_error(x)))).major >= 52)
+ Ok(Version::from_str(&*x)
+ .or_else(|x| Err(convert_version_error(x)))?
+ .major
+ >= 52)
} else {
Ok(false)
}
@@ -151,11 +154,16 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
version: &str,
comparison: &str,
) -> WebDriverResult<bool> {
- try!(Version::from_str(version).or_else(|x| Err(convert_version_error(x))))
+ Version::from_str(version)
+ .or_else(|x| Err(convert_version_error(x)))?
.matches(comparison)
.or_else(|x| Err(convert_version_error(x)))
}
+ fn strict_file_interactability(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
+ Ok(true)
+ }
+
fn accept_proxy(&mut self, _: &Capabilities, _: &Capabilities) -> WebDriverResult<bool> {
Ok(true)
}
@@ -316,16 +324,16 @@ impl FirefoxOptions {
rv.binary = binary_path;
if let Some(json) = matched.remove("moz:firefoxOptions") {
- let options = try!(json.as_object().ok_or(WebDriverError::new(
+ let options = json.as_object().ok_or(WebDriverError::new(
ErrorStatus::InvalidArgument,
"'moz:firefoxOptions' \
capability is not an object"
- )));
+ ))?;
- rv.profile = try!(FirefoxOptions::load_profile(&options));
- rv.args = try!(FirefoxOptions::load_args(&options));
- rv.log = try!(FirefoxOptions::load_log(&options));
- rv.prefs = try!(FirefoxOptions::load_prefs(&options));
+ rv.profile = FirefoxOptions::load_profile(&options)?;
+ rv.args = FirefoxOptions::load_args(&options)?;
+ rv.log = FirefoxOptions::load_log(&options)?;
+ rv.prefs = FirefoxOptions::load_prefs(&options)?;
}
Ok(rv)
@@ -333,22 +341,22 @@ impl FirefoxOptions {
fn load_profile(options: &Capabilities) -> WebDriverResult<Option<Profile>> {
if let Some(profile_json) = options.get("profile") {
- let profile_base64 = try!(profile_json.as_str().ok_or(WebDriverError::new(
+ let profile_base64 = profile_json.as_str().ok_or(WebDriverError::new(
ErrorStatus::UnknownError,
"Profile is not a string"
- )));
- let profile_zip = &*try!(base64::decode(profile_base64));
+ ))?;
+ let profile_zip = &*base64::decode(profile_base64)?;
// Create an emtpy profile directory
- let profile = try!(Profile::new(None));
- try!(unzip_buffer(
+ let profile = Profile::new(None)?;
+ unzip_buffer(
profile_zip,
profile
.temp_dir
.as_ref()
.expect("Profile doesn't have a path")
.path()
- ));
+ )?;
Ok(Some(profile))
} else {
@@ -358,22 +366,20 @@ impl FirefoxOptions {
fn load_args(options: &Capabilities) -> WebDriverResult<Option<Vec<String>>> {
if let Some(args_json) = options.get("args") {
- let args_array = try!(args_json.as_array().ok_or(WebDriverError::new(
+ let args_array = args_json.as_array().ok_or(WebDriverError::new(
ErrorStatus::UnknownError,
"Arguments were not an \
array"
- )));
- let args = try!(
- args_array
- .iter()
- .map(|x| x.as_str().map(|x| x.to_owned()))
- .collect::<Option<Vec<String>>>()
- .ok_or(WebDriverError::new(
- ErrorStatus::UnknownError,
- "Arguments entries were not all \
- strings"
- ))
- );
+ ))?;
+ let args = args_array
+ .iter()
+ .map(|x| x.as_str().map(|x| x.to_owned()))
+ .collect::<Option<Vec<String>>>()
+ .ok_or(WebDriverError::new(
+ ErrorStatus::UnknownError,
+ "Arguments entries were not all \
+ strings"
+ ))?;
Ok(Some(args))
} else {
Ok(None)
@@ -409,13 +415,13 @@ impl FirefoxOptions {
pub fn load_prefs(options: &Capabilities) -> WebDriverResult<Vec<(String, Pref)>> {
if let Some(prefs_data) = options.get("prefs") {
- let prefs = try!(prefs_data.as_object().ok_or(WebDriverError::new(
+ let prefs = prefs_data.as_object().ok_or(WebDriverError::new(
ErrorStatus::UnknownError,
"Prefs were not an object"
- )));
+ ))?;
let mut rv = Vec::with_capacity(prefs.len());
for (key, value) in prefs.iter() {
- rv.push((key.clone(), try!(pref_from_json(value))));
+ rv.push((key.clone(), pref_from_json(value)?));
}
Ok(rv)
} else {
@@ -438,16 +444,16 @@ fn pref_from_json(value: &Value) -> WebDriverResult<Pref> {
fn unzip_buffer(buf: &[u8], dest_dir: &Path) -> WebDriverResult<()> {
let reader = Cursor::new(buf);
- let mut zip = try!(
- zip::ZipArchive::new(reader)
- .map_err(|_| WebDriverError::new(ErrorStatus::UnknownError, "Failed to unzip profile"))
- );
+ let mut zip = zip::ZipArchive::new(reader)
+ .map_err(|_| WebDriverError::new(ErrorStatus::UnknownError, "Failed to unzip profile"))?;
for i in 0..zip.len() {
- let mut file = try!(zip.by_index(i).map_err(|_| WebDriverError::new(
- ErrorStatus::UnknownError,
- "Processing profile zip file failed"
- )));
+ let mut file = zip.by_index(i).map_err(|_| {
+ WebDriverError::new(
+ ErrorStatus::UnknownError,
+ "Processing profile zip file failed",
+ )
+ })?;
let unzip_path = {
let name = file.name();
let is_dir = name.ends_with("/");
@@ -463,7 +469,7 @@ fn unzip_buffer(buf: &[u8], dest_dir: &Path) -> WebDriverResult<()> {
if let Some(dir) = create_dir {
if !dir.exists() {
debug!("Creating profile directory tree {}", dir.to_string_lossy());
- try!(fs::create_dir_all(dir));
+ fs::create_dir_all(dir)?;
}
}
}
@@ -477,10 +483,10 @@ fn unzip_buffer(buf: &[u8], dest_dir: &Path) -> WebDriverResult<()> {
if let Some(unzip_path) = unzip_path {
debug!("Extracting profile to {}", unzip_path.to_string_lossy());
- let dest = try!(fs::File::create(unzip_path));
+ let dest = fs::File::create(unzip_path)?;
if file.size() > 0 {
let mut writer = BufWriter::new(dest);
- try!(io::copy(&mut file, &mut writer));
+ io::copy(&mut file, &mut writer)?;
}
}
}
@@ -494,7 +500,7 @@ mod tests {
use self::mozprofile::preferences::Pref;
use super::*;
- use marionette::MarionetteHandler;
+ use crate::marionette::MarionetteHandler;
use std::default::Default;
use std::fs::File;
use std::io::Read;
diff --git a/src/command.rs b/src/command.rs
index 754b91e..9847d02 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -1,6 +1,6 @@
use base64;
+use crate::logging;
use hyper::Method;
-use logging;
use regex::Captures;
use serde::de::{self, Deserialize, Deserializer};
use serde_json::{self, Value};
@@ -48,6 +48,11 @@ pub fn extension_routes() -> Vec<(Method, &'static str, GeckoExtensionRoute)> {
"/session/{sessionId}/moz/addon/uninstall",
GeckoExtensionRoute::UninstallAddon,
),
+ (
+ Method::GET,
+ "/session/{sessionId}/moz/screenshot/full",
+ GeckoExtensionRoute::TakeFullScreenshot,
+ ),
];
}
@@ -59,6 +64,7 @@ pub enum GeckoExtensionRoute {
XblAnonymousByAttribute,
InstallAddon,
UninstallAddon,
+ TakeFullScreenshot,
}
impl WebDriverExtensionRoute for GeckoExtensionRoute {
@@ -69,12 +75,14 @@ impl WebDriverExtensionRoute for GeckoExtensionRoute {
params: &Captures,
body_data: &Value,
) -> WebDriverResult<WebDriverCommand<GeckoExtensionCommand>> {
- let command = match self {
- &GeckoExtensionRoute::GetContext => GeckoExtensionCommand::GetContext,
- &GeckoExtensionRoute::SetContext => {
+ use self::GeckoExtensionRoute::*;
+
+ let command = match *self {
+ GetContext => GeckoExtensionCommand::GetContext,
+ SetContext => {
GeckoExtensionCommand::SetContext(serde_json::from_value(body_data.clone())?)
}
- &GeckoExtensionRoute::XblAnonymousChildren => {
+ XblAnonymousChildren => {
let element_id = try_opt!(
params.name("elementId"),
ErrorStatus::InvalidArgument,
@@ -83,7 +91,7 @@ impl WebDriverExtensionRoute for GeckoExtensionRoute {
let element = WebElement::new(element_id.as_str().to_string());
GeckoExtensionCommand::XblAnonymousChildren(element)
}
- &GeckoExtensionRoute::XblAnonymousByAttribute => {
+ XblAnonymousByAttribute => {
let element_id = try_opt!(
params.name("elementId"),
ErrorStatus::InvalidArgument,
@@ -94,13 +102,15 @@ impl WebDriverExtensionRoute for GeckoExtensionRoute {
serde_json::from_value(body_data.clone())?,
)
}
- &GeckoExtensionRoute::InstallAddon => {
+ InstallAddon => {
GeckoExtensionCommand::InstallAddon(serde_json::from_value(body_data.clone())?)
}
- &GeckoExtensionRoute::UninstallAddon => {
+ UninstallAddon => {
GeckoExtensionCommand::UninstallAddon(serde_json::from_value(body_data.clone())?)
}
+ TakeFullScreenshot => GeckoExtensionCommand::TakeFullScreenshot,
};
+
Ok(WebDriverCommand::Extension(command))
}
}
@@ -113,25 +123,20 @@ pub enum GeckoExtensionCommand {
XblAnonymousByAttribute(WebElement, XblLocatorParameters),
InstallAddon(AddonInstallParameters),
UninstallAddon(AddonUninstallParameters),
+ TakeFullScreenshot,
}
impl WebDriverExtensionCommand for GeckoExtensionCommand {
fn parameters_json(&self) -> Option<Value> {
+ use self::GeckoExtensionCommand::*;
match self {
- &GeckoExtensionCommand::GetContext => None,
- &GeckoExtensionCommand::InstallAddon(ref x) => {
- Some(serde_json::to_value(x.clone()).unwrap())
- }
- &GeckoExtensionCommand::SetContext(ref x) => {
- Some(serde_json::to_value(x.clone()).unwrap())
- }
- &GeckoExtensionCommand::UninstallAddon(ref x) => {
- Some(serde_json::to_value(x.clone()).unwrap())
- }
- &GeckoExtensionCommand::XblAnonymousByAttribute(_, ref x) => {
- Some(serde_json::to_value(x.clone()).unwrap())
- }
- &GeckoExtensionCommand::XblAnonymousChildren(_) => None,
+ GetContext => None,
+ InstallAddon(x) => Some(serde_json::to_value(x).unwrap()),
+ SetContext(x) => Some(serde_json::to_value(x).unwrap()),
+ UninstallAddon(x) => Some(serde_json::to_value(x).unwrap()),
+ XblAnonymousByAttribute(_, x) => Some(serde_json::to_value(x).unwrap()),
+ XblAnonymousChildren(_) => None,
+ TakeFullScreenshot => None,
}
}
}
@@ -231,9 +236,9 @@ pub struct LogOptions {
#[cfg(test)]
mod tests {
use super::*;
+ use crate::test::check_deserialize;
use std::fs::File;
use std::io::Read;
- use test::check_deserialize;
#[test]
fn test_json_addon_install_parameters_null() {
diff --git a/src/main.rs b/src/main.rs
index 685919f..efa774f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -46,9 +46,9 @@ mod prefs;
#[cfg(test)]
pub mod test;
-use build::BuildInfo;
-use command::extension_routes;
-use marionette::{MarionetteHandler, MarionetteSettings};
+use crate::build::BuildInfo;
+use crate::command::extension_routes;
+use crate::marionette::{MarionetteHandler, MarionetteSettings};
type ProgramResult = std::result::Result<(), (ExitCode, String)>;
@@ -96,10 +96,17 @@ fn app<'a, 'b>() -> App<'a, 'b> {
.takes_value(true),
)
.arg(
+ Arg::with_name("marionette_host")
+ .long("marionette-host")
+ .value_name("HOST")
+ .help("Host to use to connect to Gecko (default: 127.0.0.1)")
+ .takes_value(true)
+ )
+ .arg(
Arg::with_name("marionette_port")
.long("marionette-port")
.value_name("PORT")
- .help("Port to use to connect to Gecko (default: random free port)")
+ .help("Port to use to connect to Gecko (default: system-allocated port)")
.takes_value(true),
)
.arg(
@@ -162,6 +169,8 @@ fn run() -> ProgramResult {
let binary = matches.value_of("binary").map(PathBuf::from);
+ let marionette_host = matches.value_of("marionette_host")
+ .unwrap_or("127.0.0.1").to_string();
let marionette_port = match matches.value_of("marionette_port") {
Some(x) => match u16::from_str(x) {
Ok(x) => Some(x),
@@ -186,6 +195,7 @@ fn run() -> ProgramResult {
}
let settings = MarionetteSettings {
+ host: marionette_host,
port: marionette_port,
binary,
connect_existing: matches.is_present("connect_existing"),
diff --git a/src/marionette.rs b/src/marionette.rs
index 7998bfa..4ed383e 100644
--- a/src/marionette.rs
+++ b/src/marionette.rs
@@ -1,6 +1,8 @@
-use command::{AddonInstallParameters, AddonUninstallParameters, GeckoContextParameters,
- GeckoExtensionCommand, GeckoExtensionRoute, XblLocatorParameters,
- CHROME_ELEMENT_KEY, LEGACY_ELEMENT_KEY};
+use crate::command::{
+ AddonInstallParameters, AddonUninstallParameters, GeckoContextParameters,
+ GeckoExtensionCommand, GeckoExtensionRoute, XblLocatorParameters, CHROME_ELEMENT_KEY,
+ LEGACY_ELEMENT_KEY,
+};
use mozprofile::preferences::Pref;
use mozprofile::profile::Profile;
use mozrunner::runner::{FirefoxProcess, FirefoxRunner, Runner, RunnerProcess};
@@ -18,10 +20,10 @@ use std::sync::Mutex;
use std::thread;
use std::time;
use webdriver::capabilities::CapabilitiesMatching;
-use webdriver::command::WebDriverCommand::{AcceptAlert, AddCookie, CloseWindow, DeleteCookie,
- DeleteCookies, DeleteSession, DismissAlert,
- ElementClear, ElementClick, ElementSendKeys,
- ExecuteAsyncScript, ExecuteScript,
+use webdriver::command::WebDriverCommand::{AcceptAlert, AddCookie, NewWindow, CloseWindow,
+ DeleteCookie, DeleteCookies, DeleteSession,
+ DismissAlert, ElementClear, ElementClick,
+ ElementSendKeys, ExecuteAsyncScript, ExecuteScript,
Extension, FindElement, FindElementElement,
FindElementElements, FindElements, FullscreenWindow,
Get, GetActiveElement, GetAlertText, GetCSSValue,
@@ -39,23 +41,19 @@ use webdriver::command::WebDriverCommand::{AcceptAlert, AddCookie, CloseWindow,
use webdriver::command::{ActionsParameters, AddCookieParameters, GetNamedCookieParameters,
GetParameters, JavascriptCommandParameters, LocatorParameters,
NewSessionParameters, SwitchToFrameParameters, SwitchToWindowParameters,
- TakeScreenshotParameters, TimeoutsParameters, WindowRectParameters};
+ TimeoutsParameters, WindowRectParameters, NewWindowParameters};
use webdriver::command::{WebDriverCommand, WebDriverMessage};
use webdriver::common::{Cookie, FrameId, WebElement, ELEMENT_KEY, FRAME_KEY, WINDOW_KEY};
use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
-use webdriver::response::{CloseWindowResponse, CookieResponse, CookiesResponse,
+use webdriver::response::{NewWindowResponse, CloseWindowResponse, CookieResponse, CookiesResponse,
ElementRectResponse, NewSessionResponse, TimeoutsResponse,
ValueResponse, WebDriverResponse, WindowRectResponse};
use webdriver::server::{Session, WebDriverHandler};
-use build::BuildInfo;
-use capabilities::{FirefoxCapabilities, FirefoxOptions};
-use logging;
-use prefs;
-
-// localhost may be routed to the IPv6 stack on certain systems,
-// and nsIServerSocket in Marionette only supports IPv4
-const DEFAULT_HOST: &'static str = "127.0.0.1";
+use crate::build::BuildInfo;
+use crate::capabilities::{FirefoxCapabilities, FirefoxOptions};
+use crate::logging;
+use crate::prefs;
#[derive(Debug, PartialEq, Deserialize)]
pub struct MarionetteHandshake {
@@ -67,6 +65,7 @@ pub struct MarionetteHandshake {
#[derive(Default)]
pub struct MarionetteSettings {
+ pub host: String,
pub port: Option<u16>,
pub binary: Option<PathBuf>,
pub connect_existing: bool,
@@ -117,12 +116,13 @@ impl MarionetteHandler {
logging::set_max_level(l);
}
- let port = self.settings.port.unwrap_or(get_free_port()?);
+ let host = self.settings.host.to_owned();
+ let port = self.settings.port.unwrap_or(get_free_port(&host)?);
if !self.settings.connect_existing {
self.start_browser(port, options)?;
}
- let mut connection = MarionetteConnection::new(port, session_id.clone());
+ let mut connection = MarionetteConnection::new(host, port, session_id.clone());
connection.connect(&mut self.browser).or_else(|e| {
if let Some(ref mut runner) = self.browser {
runner.kill()?;
@@ -423,6 +423,8 @@ impl MarionetteSession {
msg: &WebDriverMessage<GeckoExtensionRoute>,
resp: MarionetteResponse,
) -> WebDriverResult<WebDriverResponse> {
+ use self::GeckoExtensionCommand::*;
+
if resp.id != self.command_id {
return Err(WebDriverError::new(
ErrorStatus::UnknownError,
@@ -437,7 +439,7 @@ impl MarionetteSession {
return Err(error.into());
}
- try!(self.update(msg, &resp));
+ self.update(msg, &resp)?;
Ok(match msg.command {
// Everything that doesn't have a response value
@@ -479,15 +481,18 @@ impl MarionetteSession {
| TakeScreenshot
| TakeElementScreenshot(_) => WebDriverResponse::Generic(resp.to_value_response(true)?),
GetTimeouts => {
- let script = try_opt!(
- try_opt!(
+ let script = match try_opt!(
resp.result.get("script"),
ErrorStatus::UnknownError,
"Missing field: script"
- ).as_u64(),
- ErrorStatus::UnknownError,
- "Failed to interpret script timeout duration as u64"
- );
+ ) {
+ Value::Null => None,
+ n => try_opt!(
+ Some(n.as_u64()),
+ ErrorStatus::UnknownError,
+ "Failed to interpret script timeout duration as u64"
+ ),
+ };
// Check for the spec-compliant "pageLoad", but also for "page load",
// which was sent by Firefox 52 and earlier.
let page_load = try_opt!(
@@ -517,23 +522,43 @@ impl MarionetteSession {
}
Status => panic!("Got status command that should already have been handled"),
GetWindowHandles => WebDriverResponse::Generic(resp.to_value_response(false)?),
+ NewWindow(_) => {
+ let handle: String = try_opt!(
+ try_opt!(
+ resp.result.get("handle"),
+ ErrorStatus::UnknownError,
+ "Failed to find handle field"
+ ).as_str(),
+ ErrorStatus::UnknownError,
+ "Failed to interpret handle as string"
+ ).into();
+ let typ: String = try_opt!(
+ try_opt!(
+ resp.result.get("type"),
+ ErrorStatus::UnknownError,
+ "Failed to find type field"
+ ).as_str(),
+ ErrorStatus::UnknownError,
+ "Failed to interpret type as string"
+ ).into();
+
+ WebDriverResponse::NewWindow(NewWindowResponse { handle, typ })
+ }
CloseWindow => {
let data = try_opt!(
resp.result.as_array(),
ErrorStatus::UnknownError,
"Failed to interpret value as array"
);
- let handles = try!(
- data.iter()
- .map(|x| {
- Ok(try_opt!(
- x.as_str(),
- ErrorStatus::UnknownError,
- "Failed to interpret window handle as string"
- ).to_owned())
- })
- .collect()
- );
+ let handles = data
+ .iter()
+ .map(|x| {
+ Ok(try_opt!(
+ x.as_str(),
+ ErrorStatus::UnknownError,
+ "Failed to interpret window handle as string"
+ ).to_owned())
+ }).collect::<Result<Vec<_>, _>>()?;
WebDriverResponse::CloseWindow(CloseWindowResponse(handles))
}
GetElementRect(_) => {
@@ -650,11 +675,11 @@ impl MarionetteSession {
WebDriverResponse::Cookie(CookieResponse(cookie))
}
FindElement(_) | FindElementElement(_, _) => {
- let element = try!(self.to_web_element(try_opt!(
+ let element = self.to_web_element(try_opt!(
resp.result.get("value"),
ErrorStatus::UnknownError,
"Failed to find value field"
- )));
+ ))?;
WebDriverResponse::Generic(ValueResponse(serde_json::to_value(element)?))
}
FindElements(_) | FindElementElements(_, _) => {
@@ -663,12 +688,11 @@ impl MarionetteSession {
ErrorStatus::UnknownError,
"Failed to interpret value as array"
);
- let elements = try!(
- element_vec
- .iter()
- .map(|x| self.to_web_element(x))
- .collect::<Result<Vec<_>, _>>()
- );
+ let elements = element_vec
+ .iter()
+ .map(|x| self.to_web_element(x))
+ .collect::<Result<Vec<_>, _>>()?;
+
// TODO(Henrik): How to remove unwrap?
WebDriverResponse::Generic(ValueResponse(Value::Array(
elements
@@ -678,11 +702,11 @@ impl MarionetteSession {
)))
}
GetActiveElement => {
- let element = try!(self.to_web_element(try_opt!(
+ let element = self.to_web_element(try_opt!(
resp.result.get("value"),
ErrorStatus::UnknownError,
"Failed to find value field"
- )));
+ ))?;
WebDriverResponse::Generic(ValueResponse(serde_json::to_value(element)?))
}
NewSession(_) => {
@@ -715,36 +739,32 @@ impl MarionetteSession {
}
DeleteSession => WebDriverResponse::DeleteSession,
Extension(ref extension) => match extension {
- &GeckoExtensionCommand::GetContext => {
- WebDriverResponse::Generic(resp.to_value_response(true)?)
- }
- &GeckoExtensionCommand::SetContext(_) => WebDriverResponse::Void,
- &GeckoExtensionCommand::XblAnonymousChildren(_) => {
+ GetContext => WebDriverResponse::Generic(resp.to_value_response(true)?),
+ SetContext(_) => WebDriverResponse::Void,
+ XblAnonymousChildren(_) => {
let els_vec = try_opt!(
resp.result.as_array(),
ErrorStatus::UnknownError,
"Failed to interpret body as array"
);
- let els = try!(
- els_vec
- .iter()
- .map(|x| self.to_web_element(x))
- .collect::<Result<Vec<_>, _>>()
- );
+ let els = els_vec
+ .iter()
+ .map(|x| self.to_web_element(x))
+ .collect::<Result<Vec<_>, _>>()?;
+
WebDriverResponse::Generic(ValueResponse(serde_json::to_value(els)?))
}
- &GeckoExtensionCommand::XblAnonymousByAttribute(_, _) => {
- let el = try!(self.to_web_element(try_opt!(
+ XblAnonymousByAttribute(_, _) => {
+ let el = self.to_web_element(try_opt!(
resp.result.get("value"),
ErrorStatus::UnknownError,
"Failed to find value field"
- )));
+ ))?;
WebDriverResponse::Generic(ValueResponse(serde_json::to_value(el)?))
}
- &GeckoExtensionCommand::InstallAddon(_) => {
- WebDriverResponse::Generic(resp.to_value_response(true)?)
- }
- &GeckoExtensionCommand::UninstallAddon(_) => WebDriverResponse::Void,
+ InstallAddon(_) => WebDriverResponse::Generic(resp.to_value_response(true)?),
+ UninstallAddon(_) => WebDriverResponse::Void,
+ TakeFullScreenshot => WebDriverResponse::Generic(resp.to_value_response(true)?),
},
})
}
@@ -781,6 +801,8 @@ impl MarionetteCommand {
capabilities: Option<Map<String, Value>>,
msg: &WebDriverMessage<GeckoExtensionRoute>,
) -> WebDriverResult<MarionetteCommand> {
+ use self::GeckoExtensionCommand::*;
+
let (opt_name, opt_parameters) = match msg.command {
Status => panic!("Got status command that should already have been handled"),
AcceptAlert => {
@@ -788,6 +810,7 @@ impl MarionetteCommand {
(Some("WebDriver:AcceptDialog"), None)
}
AddCookie(ref x) => (Some("WebDriver:AddCookie"), Some(x.to_marionette())),
+ NewWindow(ref x) => (Some("WebDriver:NewWindow"), Some(x.to_marionette())),
CloseWindow => (Some("WebDriver:CloseWindow"), None),
DeleteCookie(ref x) => {
let mut data = Map::new();
@@ -828,13 +851,13 @@ impl MarionetteCommand {
ExecuteScript(ref x) => (Some("WebDriver:ExecuteScript"), Some(x.to_marionette())),
FindElement(ref x) => (Some("WebDriver:FindElement"), Some(x.to_marionette())),
FindElementElement(ref e, ref x) => {
- let mut data = try!(x.to_marionette());
+ let mut data = x.to_marionette()?;
data.insert("element".to_string(), Value::String(e.id.clone()));
(Some("WebDriver:FindElement"), Some(Ok(data)))
}
FindElements(ref x) => (Some("WebDriver:FindElements"), Some(x.to_marionette())),
FindElementElements(ref e, ref x) => {
- let mut data = try!(x.to_marionette());
+ let mut data = x.to_marionette()?;
data.insert("element".to_string(), Value::String(e.id.clone()));
(Some("WebDriver:FindElements"), Some(Ok(data)))
}
@@ -918,8 +941,7 @@ impl MarionetteCommand {
SwitchToWindow(ref x) => (Some("WebDriver:SwitchToWindow"), Some(x.to_marionette())),
TakeElementScreenshot(ref e) => {
let mut data = Map::new();
- data.insert("element".to_string(), serde_json::to_value(e)?);
- // data.insert("id".to_string(), e.id.to_json());
+ data.insert("id".to_string(), Value::String(e.id.clone()));
data.insert("highlights".to_string(), Value::Array(vec![]));
data.insert("full".to_string(), Value::Bool(false));
(Some("WebDriver:TakeScreenshot"), Some(Ok(data)))
@@ -932,28 +954,35 @@ impl MarionetteCommand {
(Some("WebDriver:TakeScreenshot"), Some(Ok(data)))
}
Extension(ref extension) => match extension {
- &GeckoExtensionCommand::GetContext => (Some("Marionette:GetContext"), None),
- &GeckoExtensionCommand::InstallAddon(ref x) => {
+ GetContext => (Some("Marionette:GetContext"), None),
+ InstallAddon(x) => {
(Some("Addon:Install"), Some(x.to_marionette()))
}
- &GeckoExtensionCommand::SetContext(ref x) => {
+ SetContext(x) => {
(Some("Marionette:SetContext"), Some(x.to_marionette()))
}
- &GeckoExtensionCommand::UninstallAddon(ref x) => {
+ UninstallAddon(x) => {
(Some("Addon:Uninstall"), Some(x.to_marionette()))
}
- &GeckoExtensionCommand::XblAnonymousByAttribute(ref e, ref x) => {
- let mut data = try!(x.to_marionette());
+ XblAnonymousByAttribute(e, x) => {
+ let mut data = x.to_marionette()?;
data.insert("element".to_string(), Value::String(e.id.clone()));
(Some("WebDriver:FindElement"), Some(Ok(data)))
}
- &GeckoExtensionCommand::XblAnonymousChildren(ref e) => {
+ XblAnonymousChildren(e) => {
let mut data = Map::new();
data.insert("using".to_owned(), serde_json::to_value("anon")?);
data.insert("value".to_owned(), Value::Null);
data.insert("element".to_string(), serde_json::to_value(e.id.clone())?);
(Some("WebDriver:FindElements"), Some(Ok(data)))
}
+ TakeFullScreenshot => {
+ let mut data = Map::new();
+ data.insert("id".to_string(), Value::Null);
+ data.insert("highlights".to_string(), Value::Array(vec![]));
+ data.insert("full".to_string(), Value::Bool(true));
+ (Some("WebDriver:TakeScreenshot"), Some(Ok(data)))
+ }
},
};
@@ -962,7 +991,7 @@ impl MarionetteCommand {
ErrorStatus::UnsupportedOperation,
"Operation not supported"
);
- let parameters = try!(opt_parameters.unwrap_or(Ok(Map::new())));
+ let parameters = opt_parameters.unwrap_or(Ok(Map::new()))?;
Ok(MarionetteCommand::new(id, name.into(), parameters))
}
@@ -1040,24 +1069,27 @@ impl Into<WebDriverError> for MarionetteError {
}
}
-fn get_free_port() -> IoResult<u16> {
- TcpListener::bind((DEFAULT_HOST, 0))
+fn get_free_port(host: &str) -> IoResult<u16> {
+ TcpListener::bind((host, 0))
.and_then(|stream| stream.local_addr())
.map(|x| x.port())
}
pub struct MarionetteConnection {
+ host: String,
port: u16,
stream: Option<TcpStream>,
pub session: MarionetteSession,
}
impl MarionetteConnection {
- pub fn new(port: u16, session_id: Option<String>) -> MarionetteConnection {
+ pub fn new(host: String, port: u16, session_id: Option<String>) -> MarionetteConnection {
+ let session = MarionetteSession::new(session_id);
MarionetteConnection {
- port: port,
+ host,
+ port,
stream: None,
- session: MarionetteSession::new(session_id),
+ session,
}
}
@@ -1069,7 +1101,7 @@ impl MarionetteConnection {
debug!(
"Waiting {}s to connect to browser on {}:{}",
timeout.as_secs(),
- DEFAULT_HOST,
+ self.host,
self.port
);
loop {
@@ -1093,7 +1125,7 @@ impl MarionetteConnection {
}
}
- match TcpStream::connect(&(DEFAULT_HOST, self.port)) {
+ match TcpStream::connect((&self.host[..], self.port)) {
Ok(stream) => {
self.stream = Some(stream);
break;
@@ -1113,7 +1145,7 @@ impl MarionetteConnection {
debug!(
"Connection established on {}:{}. Waiting for Marionette handshake",
- DEFAULT_HOST, self.port,
+ self.host, self.port,
);
let data = self.handshake()?;
@@ -1237,7 +1269,7 @@ impl MarionetteConnection {
let stream = self.stream.as_mut().unwrap();
loop {
let buf = &mut [0 as u8];
- let num_read = try!(stream.read(buf));
+ let num_read = stream.read(buf)?;
let byte = match num_read {
0 => {
return Err(IoError::new(
@@ -1262,7 +1294,7 @@ impl MarionetteConnection {
let mut payload = Vec::with_capacity(bytes);
let mut total_read = 0;
while total_read < bytes {
- let num_read = try!(stream.read(buf));
+ let num_read = stream.read(buf)?;
if num_read == 0 {
return Err(IoError::new(
ErrorKind::Other,
@@ -1369,7 +1401,7 @@ impl ToMarionette for FrameId {
FrameId::Short(x) => data.insert("id".to_string(), serde_json::to_value(x)?),
FrameId::Element(ref x) => data.insert(
"element".to_string(),
- Value::Object(try!(x.to_marionette())),
+ Value::Object(x.to_marionette()?),
),
};
Ok(data)
@@ -1398,10 +1430,11 @@ impl ToMarionette for GetParameters {
impl ToMarionette for JavascriptCommandParameters {
fn to_marionette(&self) -> WebDriverResult<Map<String, Value>> {
- let mut data = serde_json::to_value(self)?.as_object().unwrap().clone();
- data.insert("newSandbox".to_string(), Value::Bool(false));
- data.insert("specialPowers".to_string(), Value::Bool(false));
- Ok(data)
+ Ok(try_opt!(
+ serde_json::to_value(self)?.as_object(),
+ ErrorStatus::UnknownError,
+ "Expected an object"
+ ).clone())
}
}
@@ -1415,6 +1448,16 @@ impl ToMarionette for LocatorParameters {
}
}
+impl ToMarionette for NewWindowParameters {
+ fn to_marionette(&self) -> WebDriverResult<Map<String, Value>> {
+ let mut data = Map::new();
+ if let Some(ref x) = self.type_hint {
+ data.insert("type".to_string(), serde_json::to_value(x)?);
+ }
+ Ok(data)
+ }
+}
+
impl ToMarionette for SwitchToFrameParameters {
fn to_marionette(&self) -> WebDriverResult<Map<String, Value>> {
let mut data = Map::new();
@@ -1441,18 +1484,6 @@ impl ToMarionette for SwitchToWindowParameters {
}
}
-impl ToMarionette for TakeScreenshotParameters {
- fn to_marionette(&self) -> WebDriverResult<Map<String, Value>> {
- let mut data = Map::new();
- let element = match self.element {
- None => Value::Null,
- Some(ref x) => Value::Object(try!(x.to_marionette())),
- };
- data.insert("element".to_string(), element);
- Ok(data)
- }
-}
-
impl ToMarionette for TimeoutsParameters {
fn to_marionette(&self) -> WebDriverResult<Map<String, Value>> {
Ok(try_opt!(
diff --git a/src/prefs.rs b/src/prefs.rs
index 9f058e6..171ccb6 100644
--- a/src/prefs.rs
+++ b/src/prefs.rs
@@ -2,28 +2,37 @@ use mozprofile::preferences::Pref;
// ALL CHANGES TO THIS FILE MUST HAVE REVIEW FROM A GECKODRIVER PEER!
//
-// The Marionette Python client is used out-of-tree with release
-// channel builds of Firefox. Removing a preference from this file
-// will cause regressions, so please be careful and get review from
-// a Testing :: Marionette peer before you make any changes to this file.
-
+// All preferences in this file are not immediately effective, and
+// require a restart of Firefox, or have to be set in the profile before
+// Firefox gets started the first time. If a preference has to be added,
+// which is immediately effective, it needs to be done in Marionette
+// (marionette.js).
+//
+// Note: geckodriver is used out-of-tree with various builds of Firefox.
+// Removing a preference from this file will cause regressions,
+// so please be careful and get review from a Testing :: geckodriver peer
+// before you make any changes to this file.
lazy_static! {
pub static ref DEFAULT: Vec<(&'static str, Pref)> = vec![
// Make sure Shield doesn't hit the network.
("app.normandy.api_url", Pref::new("")),
- // Disable automatic downloading of new releases
- ("app.update.auto", Pref::new(false)),
+ // Disable Firefox old build background check
+ ("app.update.checkInstallTime", Pref::new(false)),
// Disable automatically upgrading Firefox
+ //
+ // Note: Possible update tests could reset or flip the value to allow
+ // updates to be downloaded and applied.
("app.update.disabledForTesting", Pref::new(true)),
- // app.update.enabled is being removed. Once Firefox 62 becomes stable,
- // the line below can be removed as well.
- ("app.update.enabled", Pref::new(false)),
+ // !!! For backward compatibility up to Firefox 64. Only remove
+ // when this Firefox version is no longer supported by geckodriver !!!
+ ("app.update.auto", Pref::new(false)),
// Enable the dump function, which sends messages to the system
// console
("browser.dom.window.dump.enabled", Pref::new(true)),
+ ("devtools.console.stdout.chrome", Pref::new(true)),
// Disable safebrowsing components
("browser.safebrowsing.blockedURIs.enabled", Pref::new(false)),