summaryrefslogtreecommitdiffstats
path: root/testing/geckodriver/doc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /testing/geckodriver/doc
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--testing/geckodriver/doc/ARM.md50
-rw-r--r--testing/geckodriver/doc/Bugs.md45
-rw-r--r--testing/geckodriver/doc/Building.md46
-rw-r--r--testing/geckodriver/doc/Capabilities.md98
-rw-r--r--testing/geckodriver/doc/CrashReports.md67
-rw-r--r--testing/geckodriver/doc/Flags.md216
-rw-r--r--testing/geckodriver/doc/Notarization.md44
-rw-r--r--testing/geckodriver/doc/Patches.md31
-rw-r--r--testing/geckodriver/doc/Profiles.md103
-rw-r--r--testing/geckodriver/doc/Releasing.md292
-rw-r--r--testing/geckodriver/doc/Support.md183
-rw-r--r--testing/geckodriver/doc/Testing.md69
-rw-r--r--testing/geckodriver/doc/TraceLogs.md206
-rw-r--r--testing/geckodriver/doc/Usage.md143
-rw-r--r--testing/geckodriver/doc/index.rst55
15 files changed, 1648 insertions, 0 deletions
diff --git a/testing/geckodriver/doc/ARM.md b/testing/geckodriver/doc/ARM.md
new file mode 100644
index 0000000000..8ae9afae58
--- /dev/null
+++ b/testing/geckodriver/doc/ARM.md
@@ -0,0 +1,50 @@
+# Self-serving an ARM build
+
+Mozilla announced the intent to deprecate ARMv7 HF builds of
+geckodriver in September 2018. This does not mean you can no longer
+use geckodriver on ARM systems, and this document explains how you
+can self-service a build for ARMv7 HF.
+
+Assuming you have already checked out [central], the steps to
+cross-compile ARMv7 from a Linux host system is as follows:
+
+ 1. If you don’t have Rust installed:
+
+ ```shell
+ % curl https://sh.rustup.rs -sSf | sh
+ ```
+
+ 2. Install cross-compiler toolchain:
+
+ ```shell
+ % apt install gcc-arm-linux-gnueabihf libc6-armhf-cross libc6-dev-armhf-cross
+ ```
+
+ 3. Create a new shell, or to reuse the existing shell:
+
+ ```shell
+ % source $HOME/.cargo/env
+ ```
+
+ 4. Install rustc target toolchain:
+
+ ```shell
+ % rustup target install armv7-unknown-linux-gnueabihf
+ ```
+
+ 5. Put this in [testing/geckodriver/.cargo/config]:
+
+ ```rust
+ [target.armv7-unknown-linux-gnueabihf]
+ linker = "arm-linux-gnueabihf-gcc"
+ ```
+
+ 6. Build geckodriver from testing/geckodriver:
+
+ ```shell
+ % cd testing/geckodriver
+ % cargo build --release --target armv7-unknown-linux-gnueabihf
+ ```
+
+[central]: https://hg.mozilla.org/mozilla-central/
+[testing/geckodriver/.cargo/config]: https://searchfox.org/mozilla-central/source/testing/geckodriver/.cargo/config
diff --git a/testing/geckodriver/doc/Bugs.md b/testing/geckodriver/doc/Bugs.md
new file mode 100644
index 0000000000..b561bd41b5
--- /dev/null
+++ b/testing/geckodriver/doc/Bugs.md
@@ -0,0 +1,45 @@
+# Reporting bugs
+
+When opening a new issue or commenting on existing issues, please
+make sure discussions are related to concrete technical issues
+with geckodriver or Marionette. Questions or discussions are more
+appropriate for the [mailing list].
+
+For issue reports to be actionable, it must be clear exactly
+what the observed and expected behaviours are, and how to set up
+the state required to observe the erroneous behaviour. The most
+useful thing to provide is a minimal HTML document which permits
+the problem to be reproduced along with a [trace-level log] from
+geckodriver showing the exact wire protocol calls made.
+
+Because of the wide variety and different charateristics of clients
+used with geckodriver, their stacktraces, logs, and code examples are
+typically not very useful as they distract from the actual underlying
+cause. **For this reason, we cannot overstate the importance of
+always providing the [trace-level log] from geckodriver.** Bugs
+relating to a specific client should be filed with that project.
+
+We welcome you to file issues in the [GitHub issue tracker] once you are
+confident it has not already been reported. The [ISSUE_TEMPLATE.md]
+contains a helpful checklist for things we will want to know about
+the affected system, reproduction steps, and logs.
+
+geckodriver development follows a rolling release model as
+we don’t release patches for older versions. It is therefore
+useful to use the tip-of-tree geckodriver binary, or failing this,
+the latest release when verifying the problem. geckodriver is only
+compatible with the current release channel versions of Firefox, and
+it consequently does not help to report bugs that affect outdated
+and unsupported Firefoxen. Please always try to verify the issue
+in the latest Firefox Nightly before you file your bug.
+
+Once we are satisfied the issue raised is of sufficiently actionable
+character, we will continue with triaging it and file a bug where it
+is appropriate. Bugs specific to geckodriver will be filed in the
+[`Testing :: geckodriver`] component in Bugzilla.
+
+[mailing list]: index.rst/#communication
+[trace-level log]: TraceLogs.md
+[GitHub issue tracker]: https://github.com/mozilla/geckodriver/issues
+[ISSUE_TEMPLATE.md]: https://raw.githubusercontent.com/mozilla/geckodriver/master/ISSUE_TEMPLATE.md
+[`Testing :: geckodriver`]: https://bugzilla.mozilla.org/buglist.cgi?component=geckodriver
diff --git a/testing/geckodriver/doc/Building.md b/testing/geckodriver/doc/Building.md
new file mode 100644
index 0000000000..49a5a51200
--- /dev/null
+++ b/testing/geckodriver/doc/Building.md
@@ -0,0 +1,46 @@
+# Building geckodriver
+
+geckodriver is written in [Rust], a systems programming language
+from Mozilla. Crucially, it relies on the [webdriver crate] to
+provide the HTTPD and do most of the heavy lifting of marshalling
+the WebDriver protocol. geckodriver translates WebDriver [commands],
+[responses], and [errors] to the [Marionette protocol], and acts
+as a proxy between [WebDriver] and [Marionette].
+
+To build geckodriver:
+
+```shell
+% ./mach build testing/geckodriver
+```
+
+If you use artifact builds you may build geckodriver using cargo,
+since mach in this case does not have a compile environment:
+
+```shell
+% cd testing/geckodriver
+% cargo build
+…
+Compiling geckodriver v0.21.0 (file:///code/gecko/testing/geckodriver)
+…
+Finished dev [optimized + debuginfo] target(s) in 7.83s
+```
+
+Because all Rust code in central shares the same cargo workspace,
+the binary will be put in the `$(topsrcdir)/target` directory.
+
+You can run your freshly built geckodriver this way:
+
+```shell
+% ./mach geckodriver -- --other --flags
+```
+
+See [Testing](Testing.md) for how to run tests.
+
+[Rust]: https://www.rust-lang.org/
+[webdriver crate]: https://crates.io/crates/webdriver
+[commands]: https://docs.rs/webdriver/newest/webdriver/command/
+[responses]: https://docs.rs/webdriver/newest/webdriver/response/
+[errors]: https://docs.rs/webdriver/newest/webdriver/error/enum.ErrorStatus.html
+[Marionette protocol]: /testing/marionette/Protocol.md
+[WebDriver]: https://w3c.github.io/webdriver/
+[Marionette]: /testing/marionette/index.rst
diff --git a/testing/geckodriver/doc/Capabilities.md b/testing/geckodriver/doc/Capabilities.md
new file mode 100644
index 0000000000..c9eb7a5f97
--- /dev/null
+++ b/testing/geckodriver/doc/Capabilities.md
@@ -0,0 +1,98 @@
+# Firefox capabilities
+
+geckodriver has a few capabilities that are specific to Firefox.
+Most of these [are documented on MDN](https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions).
+
+We additionally have some capabilities that largely are implementation
+concerns that normal users should not care about:
+
+## `moz:debuggerAddress`
+
+A boolean value to indicate if Firefox has to be started with the
+[Remote Protocol] enabled, which is a low-level debugging interface that
+implements a subset of the [Chrome DevTools Protocol] (CDP).
+
+When enabled the returned `moz:debuggerAddress` capability of the `New Session`
+command is the `host:port` combination of a server that supports the following
+HTTP endpoints:
+
+### GET /json/version
+
+The browser version metadata:
+
+```json
+{
+ "Browser": "Firefox/84.0a1",
+ "Protocol-Version": "1.0",
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:84.0) Gecko/20100101 Firefox/84.0",
+ "V8-Version": "1.0",
+ "WebKit-Version": "1.0",
+ "webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/fe507083-2960-a442-bbd7-7dfe1f111c05"
+}
+```
+
+### GET /json/list
+
+A list of all available websocket targets:
+
+```json
+[ {
+ "description": "",
+ "devtoolsFrontendUrl": null,
+ "faviconUrl": "",
+ "id": "ecbf9028-676a-1b40-8596-a5edc0e2875b",
+ "type": "page",
+ "url": "https://www.mozilla.org/en-US/",
+ "browsingContextId": 29,
+ "webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/ecbf9028-676a-1b40-8596-a5edc0e2875b"
+} ]
+```
+
+The contained `webSocketDebuggerUrl` entries can be used to connect to the
+websocket and interact with the browser by using the CDP protocol.
+
+[Remote Protocol]: /remote/index.rst
+[Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/
+
+## `moz:useNonSpecCompliantPointerOrigin`
+
+A boolean value to indicate how the pointer origin for an action
+command will be calculated.
+
+With Firefox 59 the calculation will be based on the requirements
+by the [WebDriver] specification. This means that the pointer origin
+is no longer computed based on the top and left position of the
+referenced element, but on the in-view center point.
+
+To temporarily disable the WebDriver conformant behavior use `false`
+as value for this capability.
+
+Please note that this capability exists only temporarily, and that
+it will be removed once all Selenium bindings can handle the new
+behavior.
+
+## `moz:webdriverClick`
+
+A boolean value to indicate which kind of interactability checks
+to run when performing a click or sending keys to an elements. For
+Firefoxen prior to version 58.0 some legacy code as imported from
+an older version of FirefoxDriver was in use.
+
+With Firefox 58 the interactability checks as required by the
+[WebDriver] specification are enabled by default. This means
+geckodriver will additionally check if an element is obscured by
+another when clicking, and if an element is focusable for sending
+keys.
+
+Because of this change in behaviour, we are aware that some extra
+errors could be returned. In most cases the test in question might
+have to be updated so it's conform with the new checks. But if the
+problem is located in geckodriver, then please raise an issue in
+the [issue tracker].
+
+To temporarily disable the WebDriver conformant checks use `false`
+as value for this capability.
+
+Please note that this capability exists only temporarily, and that
+it will be removed once the interactability checks have been
+stabilized.
diff --git a/testing/geckodriver/doc/CrashReports.md b/testing/geckodriver/doc/CrashReports.md
new file mode 100644
index 0000000000..576bdda7a9
--- /dev/null
+++ b/testing/geckodriver/doc/CrashReports.md
@@ -0,0 +1,67 @@
+# Analyzing crash data of Firefox
+
+It's not uncommon that under some special platform configurations and while
+running automated tests via Selenium and geckodriver Firefox could crash. In
+those cases it is very helpful to retrieve the generated crash data aka
+minidump files, and report these to us.
+
+## Retrieve the crash data
+
+Because geckodriver creates a temporary user profile for Firefox, it also
+automatically removes all its folders once the tests have been finished. That
+also means that if Firefox crashed the created minidump files are lost. To
+prevent that a custom profile has to be used instead. The following code
+shows an example by using the Python Selenium bindings on Mac OS:
+
+```python
+import tempfile
+
+from selenium import webdriver
+from selenium.webdriver.firefox.options import Options
+
+# Custom profile folder to keep the minidump files
+profile = tempfile.mkdtemp(".selenium")
+print("*** Using profile: {}".format(profile))
+
+# Use the above folder as custom profile
+opts = Options()
+opts.add_argument("-profile")
+opts.add_argument(profile)
+opts.binary = "/Applications/Firefox.app/Contents/MacOS/firefox"
+
+driver = webdriver.Firefox(
+ options=opts,
+ # hard-code the Marionette port so geckodriver can connect
+ service_args=["--marionette-port", "2828"]
+)
+
+# Your test code which crashes Firefox
+```
+
+Executing the test with Selenium now, which triggers the crash of Firefox
+will leave all the files from the user profile around in the above path.
+
+To retrieve the minidump files navigate to that folder and look for a sub
+folder with the name `minidumps`. It should contain at least one series of
+files. One file with the `.dmp` extension and another one with `.extra`.
+Both of those files are needed. If more crash files are present grab them all.
+
+Attach the files as best archived as zip file to the created [geckodriver issue]
+on Github.
+
+[geckodriver issue]: https://github.com/mozilla/geckodriver/issues/new
+
+## Getting details of the crash
+
+More advanced users can upload the generated minidump files themselves and
+receive details information about the crash. Therefore find the [crash reporter]
+folder and copy all the generated minidump files into the `pending` sub directory.
+Make sure that both the `.dmp` and `.extra` files are present.
+
+Once done you can also [view the crash reports].
+
+If you submitted a crash please do not forget to also add the link of the
+crash report to the geckodriver issue.
+
+[crash reporter]: https://support.mozilla.org/kb/mozillacrashreporter#w_viewing-reports-outside-of-firefox
+[view the crash reports]: https://support.mozilla.orgkb/mozillacrashreporter#w_viewing-crash-reports
diff --git a/testing/geckodriver/doc/Flags.md b/testing/geckodriver/doc/Flags.md
new file mode 100644
index 0000000000..3db6e27c06
--- /dev/null
+++ b/testing/geckodriver/doc/Flags.md
@@ -0,0 +1,216 @@
+<!-- markdownlint-disable MD033 -->
+# Flags
+
+## <code>-\\-allow-hosts <var>ALLOW_HOSTS</var>...</code>
+
+Values of the `Host` header to allow for incoming requests.
+
+By default the value of <var>HOST</var> is allowed. If `--allow-hosts`
+is provided, exactly the given values will be permitted. For example
+`--allow-host geckodriver.test webdriver.local` will allow requests
+with `Host` set to `geckodriver.test` or `webdriver.local`.
+
+Requests with `Host` set to an IP address are always allowed.
+
+## <code>-\\-allow-origins <var>ALLOW_ORIGINS</var>...</code>
+
+Values of the `Origin` header to allow for incoming requests.
+
+`Origin` is set by web browsers for all `POST` requests, and most
+other cross-origin requests. By default any request with an `Origin`
+header is rejected to protect against malicious websites trying to
+access geckodriver running on the local machine.
+
+If `--allow-origins` is provided, web services running on the given
+origin will be able to make requests to geckodriver. For example
+`--allow-origins https://webdriver.test:8080` will allow a web-based
+service on the origin with scheme `https`, hostname `webdriver.test`,
+and port `8080` to access the geckodriver instance.
+
+## <code>-\\-android-storage <var>ANDROID_STORAGE</var></code>
+
+**Deprecation warning**: This argument is deprecated and planned to be removed
+with the 0.31.0 release of geckodriver. As such it shouldn't be used with version
+0.30.0 or later anymore. By default the automatic detection will now use the
+external storage location, which is always readable and writeable.
+
+Selects the test data location on the Android device, eg. the Firefox profile.
+By default `auto` is used.
+
+<style type="text/css">
+ table { width: 100%; margin-bottom: 2em; }
+ table, th, td { border: solid gray 1px; }
+ td, th { padding: 10px; text-align: left; vertical-align: middle; }
+ td:nth-child(1), th:nth-child(1) { width: 10em; text-align: center; }
+</style>
+
+<table>
+ <thead>
+ <tr>
+ <th>Value
+ <th>Description
+ </tr>
+ </thead>
+
+ <tr>
+ <td>auto
+ <td>Best suitable location based on whether the device is rooted.<br/>
+ If the device is rooted `internal` is used, otherwise `app`.
+ <tr>
+ <td>app
+ <td><p>Location: `/data/data/%androidPackage%/test_root`</p>
+ Based on the `androidPackage` capability that is passed as part of
+ `moz:firefoxOptions` when creating a new session. Commands that
+ change data in the app's directory are executed using run-as. This requires
+ that the installed app is debuggable.
+ <tr>
+ <td>internal
+ <td><p>Location: `/data/local/tmp/test_root`</p>
+ The device must be rooted since when the app runs, files that are created
+ in the profile, which is owned by the app user, cannot be changed by the
+ shell user. Commands will be executed via `su`.
+ <tr>
+ <td>sdcard
+ <td><p>Location: `$EXTERNAL_STORAGE/Android/data/%androidPackage%/files/test_root`</p>
+ This location is supported by all versions of Android whether if the device
+ is rooted or not.
+</table>
+
+## <code>-b <var>BINARY</var></code> / <code>-\\-binary <var>BINARY</var></code>
+
+Path to the Firefox binary to use. By default geckodriver tries to
+find and use the system installation of Firefox, but that behaviour
+can be changed by using this option. Note that the `binary`
+capability of the `moz:firefoxOptions` object that is passed when
+[creating a new session] will override this option.
+
+On Linux systems it will use the first _firefox_ binary found
+by searching the `PATH` environmental variable, which is roughly
+equivalent to calling [whereis(1)] and extracting the second column:
+
+```shell
+% whereis firefox
+firefox: /usr/bin/firefox /usr/local/firefox
+```
+
+On macOS, the binary is found by looking for the first _firefox-bin_
+binary in the same fashion as on Linux systems. This means it is
+possible to also use `PATH` to control where geckodriver should
+find Firefox on macOS. It will then look for _/Applications/Firefox.app_.
+
+On Windows systems, geckodriver looks for the system Firefox by
+scanning the Windows registry.
+
+[creating a new session]: https://w3c.github.io/webdriver/#new-session
+[whereis(1)]: http://www.manpagez.com/man/1/whereis/
+
+## <code>-\\-connect-existing</code>
+
+Connect geckodriver to an existing Firefox instance. This means
+geckodriver will abstain from the default of starting a new Firefox
+session.
+
+The existing Firefox instance must have [Marionette] enabled.
+To enable the remote protocol in Firefox, you can pass the
+`--marionette` flag. Unless the `marionette.port` preference
+has been user-set, Marionette will listen on port 2828. So when
+using `--connect-existing` it is likely you will also have to use
+`--marionette-port` to set the correct port.
+
+## <code>-\\-host <var>HOST</var></code>
+
+Host to use for the WebDriver server. Defaults to 127.0.0.1.
+
+## <code>-\\-jsdebugger</code>
+
+Attach [browser toolbox] debugger when Firefox starts. This is
+useful for debugging [Marionette] internals.
+
+To be prompted at the start of the test run or between tests,
+you can set the `marionette.debugging.clicktostart` preference to
+`true`.
+
+For reference, below is the list of preferences that enables the
+chrome debugger. These are all set implicitly when the
+argument is passed to geckodriver.
+
+* `devtools.browsertoolbox.panel` -> `jsdebugger`
+
+ Selects the Debugger panel by default.
+
+* `devtools.chrome.enabled` → true
+
+ Enables debugging of chrome code.
+
+* `devtools.debugger.prompt-connection` → false
+
+ Controls the remote connection prompt. Note that this will
+ automatically expose your Firefox instance to localhost.
+
+* `devtools.debugger.remote-enabled` → true
+
+ Allows a remote debugger to connect, which is necessary for
+ debugging chrome code.
+
+[browser toolbox]: https://developer.mozilla.org/en-US/docs/Tools/Browser_Toolbox
+
+## <code>-\\-log <var>LEVEL</var></code>
+
+Set the Gecko and geckodriver log level. Possible values are `fatal`,
+`error`, `warn`, `info`, `config`, `debug`, and `trace`.
+
+## <code>-\\-log-no-truncate</code>
+
+Disables truncation of long log lines.
+
+## <code>-\\-marionette-host <var>HOST</var></code>
+
+Selects the host for geckodriver’s connection to the [Marionette]
+remote protocol. Defaults to 127.0.0.1.
+
+## <code>-\\-marionette-port <var>PORT</var></code>
+
+Selects the port for geckodriver’s connection to the [Marionette]
+remote protocol.
+
+In the default mode where geckodriver starts and manages the Firefox
+process, it will pick a free port assigned by the system and set the
+`marionette.port` preference in the profile.
+
+When `--connect-existing` is used and the Firefox process is not
+under geckodriver’s control, it will simply connect to <var>PORT</var>.
+
+`--connect-existing`: #connect-existing
+
+## <code>-p <var>PORT</var></code> / <code>-\\-port <var>PORT</var></code>
+
+Port to use for the WebDriver server. Defaults to 4444.
+
+A helpful trick is that it is possible to bind to 0 to get the
+system to atomically assign a free port.
+
+## <code>-\\-profile-root <var>PROFILE_ROOT</var></code>
+
+Path to the directory to use when creating temporary profiles. By
+default this is the system temporary directory. Both geckodriver and
+Firefox must have read-write access to this path.
+
+This setting can be useful when Firefox is sandboxed from the host
+filesystem such that it doesn't share the same system temporary
+directory as geckodriver (e.g. when running Firefox inside a container
+or packaged as a snap).
+
+## <code>-v[v]</code>
+
+Increases the logging verbosity by to debug level when passing
+a single `-v`, or to trace level if `-vv` is passed. This is
+analogous to passing `--log debug` and `--log trace`, respectively.
+
+## <code>-\\-websocket-port<var>PORT</var></code>
+
+Port to use to connect to WebDriver BiDi. Defaults to 9222.
+
+A helpful trick is that it is possible to bind to 0 to get the
+system to atomically assign a free port.
+
+[Marionette]: /testing/marionette/index.rst
diff --git a/testing/geckodriver/doc/Notarization.md b/testing/geckodriver/doc/Notarization.md
new file mode 100644
index 0000000000..ba1ba08d64
--- /dev/null
+++ b/testing/geckodriver/doc/Notarization.md
@@ -0,0 +1,44 @@
+# MacOS notarization
+
+With the introduction of macOS 10.15 “Catalina” Apple introduced
+[new notarization requirements] that all software must be signed
+and notarized centrally.
+
+Whilst the geckodriver binary is technically both signed and notarized, the
+actual validation can only be performed by MacOS if the machine that starts
+the geckodriver binary for the very first time is online. Offline validation
+would require shipping geckodriver as a DMG/PKG. You can track the relevant
+progress in [bug 1783943].
+
+Note: geckodriver releases between 0.26.0 and 0.31.0 don't have the
+notarization applied and always require the manual steps below to
+bypass the notarization requirement of the binary during the very first start.
+
+[new notarization requirements]: https://developer.apple.com/news/?id=04102019a
+[bug 1783943]: https://bugzilla.mozilla.org/show_bug.cgi?id=1783943
+
+## Offline mode
+
+There are some mitigating circumstances:
+
+* Verification problems only occur when other notarized programs,
+ such as a web browser, downloads the software from the internet.
+
+* Arbitrary software downloaded through other means, such as
+ curl(1) is _not_ affected by this change.
+
+In other words, if your method for fetching geckodriver on macOS
+is through the GitHub web UI using a web browser, the program will
+not be able to run unless you manually disable the quarantine check
+(explained below). If downloading geckodriver via other means
+than a macOS notarized program, you should not be affected.
+
+To bypass the notarization requirement on macOS if you have downloaded
+the geckodriver .tar.gz via a web browser, you can run the following
+command in a terminal:
+
+ % xattr -r -d com.apple.quarantine geckodriver
+
+A problem with notarization will manifest itself through a security
+dialogue appearing, explaining that the source of the program is
+not trusted.
diff --git a/testing/geckodriver/doc/Patches.md b/testing/geckodriver/doc/Patches.md
new file mode 100644
index 0000000000..e559da075d
--- /dev/null
+++ b/testing/geckodriver/doc/Patches.md
@@ -0,0 +1,31 @@
+# Submitting patches
+
+You can submit patches by using [Phabricator]. Walk through its documentation
+in how to set it up, and uploading patches for review. Don't worry about which
+person to select for reviewing your code. It will be done automatically.
+
+Please also make sure to follow the [commit creation guidelines].
+
+Once you have contributed a couple of patches, we are happy to sponsor you in
+[becoming a Mozilla committer]. When you have been granted commit access
+level 1, you will have permission to use the [Firefox CI] to trigger your own
+“try runs” to test your changes. You can use the following [try preset] to run
+the most relevant tests:
+
+```shell
+% ./mach try --preset geckodriver
+```
+
+This preset will schedule geckodriver-related tests on various platforms. You can
+reduce the number of tasks by filtering on platforms (e.g. linux) or build type
+(e.g. opt):
+
+```shell
+% ./mach try --preset geckodriver -xq "'linux 'opt"
+```
+
+[Phabricator]: https://moz-conduit.readthedocs.io/en/latest/phabricator-user.html
+[commit creation guidelines]: https://mozilla-version-control-tools.readthedocs.io/en/latest/devguide/contributing.html?highlight=phabricator#submitting-patches-for-review
+[becoming a Mozilla committer]: https://www.mozilla.org/en-US/about/governance/policies/commit/
+[Firefox CI]: https://treeherder.mozilla.org/
+[try preset]: https://firefox-source-docs.mozilla.org/tools/try/presets.html
diff --git a/testing/geckodriver/doc/Profiles.md b/testing/geckodriver/doc/Profiles.md
new file mode 100644
index 0000000000..abad9af730
--- /dev/null
+++ b/testing/geckodriver/doc/Profiles.md
@@ -0,0 +1,103 @@
+# Profiles
+
+geckodriver uses [profiles] to instrument Firefox’ behaviour. The
+user will usually rely on geckodriver to generate a temporary,
+throwaway profile. These profiles are deleted when the WebDriver
+session expires.
+
+In cases where the user needs to use custom, prepared profiles,
+geckodriver will make modifications to the profile that ensures
+correct behaviour. See [_Automation preferences_] below on the
+precedence of user-defined preferences in this case.
+
+Custom profiles can be provided two different ways:
+
+ 1. by appending `--profile /some/location` to the [`args` capability],
+ which will instruct geckodriver to use the profile _in-place_;
+
+ 2. or by setting the [`profile` capability] to a Base64-encoded
+ ZIP of the profile directory.
+
+Note that geckodriver has a [known bug concerning `--profile`] that
+prevents the randomised Marionette port from being passed to
+geckodriver. To circumvent this issue, make sure you specify the
+port manually using `--marionette-port <port>`.
+
+The second way is compatible with shipping Firefox profiles across
+a network, when for example the geckodriver instance is running on
+a remote system. This is the case when using Selenium’s `RemoteWebDriver`
+concept, where the WebDriver client and the server are running on
+two distinct systems.
+
+[profiles]: https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data
+[_Automation preferences_]: #automation-preferences
+[`args` capability]: https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions#args_array_of_strings
+[`profile` capability]: https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions#profile_string
+[known bug concerning `--profile`]: https://github.com/mozilla/geckodriver/issues/1058
+
+## Default locations for temporary profiles
+
+When a custom user profile is not provided with the `-profile`
+command-line argument geckodriver generates a temporary, throwaway
+profile. This is written to the default system temporary folder
+and subsequently removed when the WebDriver session expires.
+
+The default location for temporary profiles depends on the system.
+On Unix systems it uses /tmp, and on Windows it uses the Windows
+directory.
+
+The default location can be overridden. On Unix you set the `TMPDIR`
+environment variable. On Windows, the following environment variables
+are respected, in order:
+
+ 1. `TMP`
+ 2. `TEMP`
+ 3. `USERPROFILE`
+
+It is not necessary to change the temporary directory system-wide.
+All you have to do is make sure it gets set for the environment of
+the geckodriver process:
+
+ TMPDIR=/some/location ./geckodriver
+
+## Automation preferences
+
+As indicated in the introduction, geckodriver configures Firefox
+so it is well-behaved in automation environments. It uses a
+combination of preferences written to the profile prior to launching
+Firefox (1), and a set of recommended preferences set on startup (2).
+
+These can be perused here:
+
+ 1. [testing/geckodriver/src/prefs.rs](https://searchfox.org/mozilla-central/source/testing/geckodriver/src/prefs.rs)
+ 2. [remote/components/marionette.js](https://searchfox.org/mozilla-central/source/remote/components/marionette.js)
+
+As mentioned, these are _recommended_ preferences, and any user-defined
+preferences in the [user.js file] or as part of the [`prefs` capability]
+take precedence. This means for example that the user can tweak
+`browser.startup.page` to override the recommended preference for
+starting the browser with a blank page.
+
+The recommended preferences set at runtime (see 2 above) may also
+be disabled entirely by setting `remote.prefs.recommended` starting with Firefox
+91. For older versions of Firefox, the preference to use was
+`marionette.prefs.recommended`.
+This may however cause geckodriver to not behave correctly according
+to the WebDriver standard, so it should be used with caution.
+
+Users should take note that the `marionette.port` preference is
+special, and will always be overridden when using geckodriver unless
+the `--marionette-port <port>` flag is used specifically to instruct
+the Marionette server in Firefox which port to use.
+
+[user.js file]: http://kb.mozillazine.org/User.js_file
+[`prefs` capability]: https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions#prefs_preferences_object
+
+## Temporary profiles not being removed
+
+It is a known bug that geckodriver in some instances fails to remove
+the temporary profile, particularly when the session is not explicitly
+deleted or the process gets interrupted. See [geckodriver issue
+299] for more information.
+
+[geckodriver issue 299]: https://github.com/mozilla/geckodriver/issues/299
diff --git a/testing/geckodriver/doc/Releasing.md b/testing/geckodriver/doc/Releasing.md
new file mode 100644
index 0000000000..79574f8a0e
--- /dev/null
+++ b/testing/geckodriver/doc/Releasing.md
@@ -0,0 +1,292 @@
+# Releasing geckodriver
+
+Releasing geckodriver is not as easy as it once used to be when the
+project’s canonical home was on GitHub. Today geckodriver is hosted
+in [mozilla-central], and whilst we do want to make future releases
+from [Mozilla’s CI infrastructure], we are currently in between two
+worlds: development happens in m-c, but releases continue to be made
+from GitHub.
+
+In any case, the steps to release geckodriver are as follows:
+
+[mozilla-central]: https://hg.mozilla.org/mozilla-central/
+[Mozilla’s CI infrastructure]: https://treeherder.mozilla.org/
+
+## Update in-tree dependency crates
+
+geckodriver depends on a number of Rust crates that also live in
+central by using relative paths. Here an excerpt from its `Cargo.toml`:
+
+```ini
+[dependencies]
+…
+marionette = { path = "./marionette" }
+…
+mozdevice = { path = "../mozbase/rust/mozdevice" }
+mozprofile = { path = "../mozbase/rust/mozprofile" }
+mozrunner = { path = "../mozbase/rust/mozrunner" }
+mozversion = { path = "../mozbase/rust/mozversion" }
+…
+webdriver = { path = "../webdriver" }
+```
+
+Because we need to export the geckodriver source code to the old
+GitHub repository when we release, we first need to publish these
+crates in the specified order if they have had any changes in the
+interim since the last release. If they have received no changes,
+you can skip them:
+
+- `testing/mozbase/rust/mozdevice`
+- `testing/mozbase/rust/mozprofile`
+- `testing/mozbase/rust/mozrunner`
+- `testing/mozbase/rust/mozversion`
+- `testing/webdriver`
+- `testing/geckodriver/marionette`
+
+For each crate:
+
+1. Change into the crates folder.
+2. Bump the version number in `Cargo.toml` based on [semantic versioning rules],
+ and also update the version dependency for other in-tree crates using the
+ currently modified crate. Note that running `cargo update` will fail if you
+ missed updating a crate's dependency.
+
+3. Use the [cargo-semver-checks] command to validate the version change:
+
+ ```shell
+ % cargo semver-checks check-release
+ ```
+
+4. Update the crate:
+
+ ```shell
+ % cargo update -p <crate name>
+ ```
+
+5. We also publish audit information for the crates based on Mozilla's
+ [audit criteria]. Because we use [wildcard audit entries] make sure that the
+ latest day of publication is still within the `end` date. The related entry
+ of the crate can be found at the top of [audits.toml]. If the date is over,
+ then update its value to at most 1 year in the future.
+
+6. Commit the changes for the modified [Cargo.toml] files, [Cargo.lock] and
+ [audits.toml].
+
+ ```shell
+ % git add Cargo.toml Cargo.lock audits.toml testing
+ % git commit -m "Bug XYZ - [rust-<name>] Release version <version>"
+ ```
+
+[semantic versioning rules]: https://semver.org/
+[cargo-semver-checks]: https://crates.io/crates/cargo-semver-checks
+[audit criteria]: https://mozilla.github.io/cargo-vet/audit-criteria.html
+[wildcard audit entries]: https://mozilla.github.io/cargo-vet/wildcard-audit-entries.html
+[Cargo.toml]: https://searchfox.org/mozilla-central/source/testing/geckodriver/Cargo.toml
+[Cargo.lock]: https://searchfox.org/mozilla-central/source/Cargo.lock
+[audits.toml]: https://searchfox.org/mozilla-central/source/supply-chain/audits.toml
+
+## Update the change log
+
+Notable changes to geckodriver are mentioned in [CHANGES.md]. Many
+users rely on this, so it’s important that you make it **relevant
+to end-users**. For example, we only mention changes that are visible
+to users. The change log is not a complete anthology of commits,
+as these often will not convey the essence of a change to end-users.
+If a feature was added but removed before release, there is no reason
+to list it as a change.
+
+It is good practice to also include relevant information from the
+[webdriver], [marionette], [rust-mozrunner], and [rust-mozdevice] crates,
+since these are the most important dependencies of geckodriver and a lot
+of its functionality is implemented there.
+
+To get a list of all the changes for one of the above crates one of the following
+commands can be used:
+
+```shell
+% hg log -M -r <revision>::central --template "{node|short}\t{desc|firstline}\n" <path>
+% git log --reverse $(git cinnabar hg2git <revision>)..HEAD --pretty="%s" <path>
+```
+
+where `<revision>` is the changeset of the last geckodriver release and `<path>`
+the location of the crate in the repository.
+
+Add the list of changes to the related release bug on Bugzilla, and also check the
+dependency list of the bug for other fixes that are worth mentioning.
+
+We follow the writing style of the existing change log, with
+one section per version (with a release date), with subsections
+‘Added’, ‘Changed’, 'Fixed' and ‘Removed’. If the targeted
+Firefox or Selenium versions have changed, it is good to make a
+mention of this. Lines are optimally formatted at roughly 72 columns
+to make the file readable in a text editor as well as rendered HTML.
+fmt(1) does a splendid job at text formatting.
+
+[CHANGES.md]: https://searchfox.org/mozilla-central/source/testing/geckodriver/CHANGES.md
+[webdriver]: https://searchfox.org/mozilla-central/source/testing/webdriver
+[marionette]: https://searchfox.org/mozilla-central/source/testing/geckodriver/marionette
+[rust-mozrunner]: https://searchfox.org/mozilla-central/source/testing/mozbase/rust/mozrunner
+[rust-mozdevice]: https://searchfox.org/mozilla-central/source/testing/mozbase/rust/mozdevice
+
+## Bump the version number and update the support page
+
+Bump the version number in [Cargo.toml] to the next version.
+geckodriver follows [semantic versioning] so it’s a good idea to
+familiarise yourself with that before deciding on the version number.
+
+After you’ve changed the version number, run
+
+```shell
+% ./mach build testing/geckodriver
+```
+
+again to update [Cargo.lock].
+
+Now update the [support page] by adding a new row to the versions table,
+including the required versions of Selenium, and Firefox.
+
+Finally commit all those changes.
+
+[semantic versioning]: http://semver.org/
+[support page]: https://searchfox.org/mozilla-central/source/testing/geckodriver/doc/Support.md
+
+## Add the changeset id
+
+To easily allow a release build of geckodriver after cloning the
+repository, the changeset id for the release has to be added to the
+change log. Therefore add a final place-holder commit to the patch
+series, to already get review for.
+
+Once all previous revisions of the patch series have been landed, and got merged
+to `mozilla-central`, the changeset id from the merge commit has to picked for
+finalizing the change log. This specific id is needed because Taskcluster creates
+the final signed builds based on that merge.
+
+## Release new in-tree dependency crates
+
+Make sure to wait until the complete patch series from above has been
+merged to mozilla-central. Then continue with the following steps.
+
+Before releasing geckodriver all dependency crates as
+[updated earlier](#update-in-tree-dependency-crates) have to be
+released first.
+
+Therefore change into each of the directories for crates with an update
+and run the following command to publish the crate:
+
+```shell
+% cargo publish
+```
+
+Note that if a crate has an in-tree dependency make sure to first
+change the dependency information.
+
+Do not release the geckodriver crate yet!
+
+Once all crates have been published observe the `/target/package/` folder under
+the root of the mozilla-central repository and remove all the folders related
+to the above published packages (it will save ~1GB disk space).
+
+## Export to GitHub
+
+The canonical GitHub repository is <https://github.com/mozilla/geckodriver.git>
+so make sure you have a local clone of that. It has three branches:
+_master_ which only contains the [README.md]; _old_ which was the
+state of the project when it was exported to mozilla-central; and
+_release_, from where releases are made.
+
+Before we copy the code over to the GitHub repository we need to
+check out the [release commit that bumped the version number](#add-the-changeset-id)
+on mozilla-central:
+
+```shell
+% hg update $RELEASE_REVISION
+```
+
+Or:
+
+```shell
+% git checkout $(git cinnabar hg2git $RELEASE_REVISION)
+```
+
+We will now export the contents of [testing/geckodriver] to a new branch that
+is based on the _release_ branch, which will be used to create a pull request:
+
+```shell
+% cd $SRC/geckodriver
+% git checkout release
+% git pull
+% git checkout -b do_release_X.Y.Z
+% git rm -rf .
+% git clean -fxd
+% cp -rt $SRC/gecko/testing/geckodriver .
+```
+
+Now verify that geckodriver builds correctly by running:
+
+```shell
+% cargo build
+```
+
+[README.md]: https://searchfox.org/mozilla-central/source/testing/geckodriver/README.md
+[testing/geckodriver]: https://searchfox.org/mozilla-central/source/testing/geckodriver
+
+## Commit local changes
+
+Now commit all the changes you have made locally to the _release_ branch.
+It is recommended to setup a [GPG key] for signing the commit, so
+that the release commit is marked as `verified`.
+
+```shell
+% git add . -- ':!mach_commands.py :!moz.build :!target/*'
+% git commit -S -am "Import of vX.Y.Z" (signed)
+```
+
+or if you cannot use signing use:
+
+```shell
+% git add . -- ':!mach_commands.py :!moz.build :!target/*'
+% git commit -am "Import of vX.Y.Z" (unsigned)
+```
+
+Then push the changes, and create a pull request:
+
+```shell
+% git push origin do_release_X.Y.Z
+```
+
+As indicated above, the changes you make to this branch will not
+be upstreamed back into mozilla-central. It is merely used as a
+place for external consumers to build their own version of geckodriver.
+
+[GPG key]: https://help.github.com/articles/signing-commits/
+
+## Make the release
+
+geckodriver needs to be manually released on github.com. Therefore start to
+[draft a new release], and make the following changes:
+
+1. Specify the "Tag version", and select "Release" as target.
+
+2. Leave the release title empty
+
+3. Paste the raw Markdown source from [CHANGES.md] into the description field.
+ This will highlight for end-users what changes were made in that particular
+ package when they visit the GitHub downloads section. Make sure to check that
+ all references can be resolved, and if not make sure to add those too.
+
+4. Find the signed geckodriver archives in the [taskcluster index] by
+ replacing %changeset% with the full release changeset id. Rename the
+ individual files so the basename looks like 'geckodriver-v%version%-%platform%'.
+ Upload them all, including the checksum files for the Linux platforms.
+
+5. Before announcing the release on GitHub publish the geckodriver crate as well
+ on crates.io by running `cargo publish` from the release branch.
+
+6. Send the release announcement to the [dev-webdriver] mailing list.
+
+[draft a new release]: https://github.com/mozilla/geckodriver/releases/new
+[taskcluster index]: https://firefox-ci-tc.services.mozilla.com/tasks/index/gecko.v2.mozilla-central.revision.%changeset%.geckodriver
+[dev-webdriver]: https://groups.google.com/a/mozilla.org/g/dev-webdriver
+
+Congratulations! You’ve released geckodriver!
diff --git a/testing/geckodriver/doc/Support.md b/testing/geckodriver/doc/Support.md
new file mode 100644
index 0000000000..0c06ee1bc0
--- /dev/null
+++ b/testing/geckodriver/doc/Support.md
@@ -0,0 +1,183 @@
+<!-- markdownlint-disable MD033 -->
+# Supported platforms
+
+The following table shows a mapping between [geckodriver releases],
+and required versions of Selenium and Firefox:
+
+<style type="text/css">
+ table { width: 100%; margin-bottom: 2em; }
+ table, th, td { border: solid gray 1px; }
+ td, th { padding: 5px 10px; text-align: center; }
+</style>
+
+<table>
+ <thead>
+ <tr>
+ <th rowspan="2">geckodriver
+ <th rowspan="2">Selenium
+ <th colspan="2">Firefox
+ </tr>
+ <tr>
+ <th>min
+ <th>max
+ </tr>
+ </thead>
+ </thead>
+ <tr>
+ <td>0.33.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>102 ESR
+ <td>n/a
+ <tr>
+ <td>0.32.2
+ <td>≥ 3.11 (3.14 Python)
+ <td>102 ESR
+ <td>n/a
+ <tr>
+ <td>0.32.1
+ <td>≥ 3.11 (3.14 Python)
+ <td>102 ESR
+ <td>n/a
+ <tr>
+ <td>0.32.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>102 ESR
+ <td>n/a
+ <tr>
+ <td>0.31.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>91 ESR
+ <td>n/a
+ <tr>
+ <tr>
+ <td>0.30.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>78 ESR
+ <td>90
+ <tr>
+ <td>0.29.1
+ <td>≥ 3.11 (3.14 Python)
+ <td>60
+ <td>90
+ <tr>
+ <td>0.29.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>60
+ <td>90
+ <tr>
+ <td>0.28.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>60
+ <td>90
+ <tr>
+ <td>0.27.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>60
+ <td>90
+ <tr>
+ <td>0.26.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>60
+ <td>90
+ <tr>
+ <td>0.25.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>57
+ <td>90
+ <tr>
+ <td>0.24.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>57
+ <td>79
+ <tr>
+ <td>0.23.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>57
+ <td>79
+ <tr>
+ <td>0.22.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>57
+ <td>79
+ <tr>
+ <td>0.21.0
+ <td>≥ 3.11 (3.14 Python)
+ <td>57
+ <td>79
+ <tr>
+ <td>0.20.1
+ <td>≥ 3.5
+ <td>55
+ <td>62
+ <tr>
+ <td>0.20.0
+ <td>≥ 3.5
+ <td>55
+ <td>62
+ <tr>
+ <td>0.19.1
+ <td>≥ 3.5
+ <td>55
+ <td>62
+ <tr>
+ <td>0.19.0
+ <td>≥ 3.5
+ <td>55
+ <td>62
+ <tr>
+ <td>0.18.0
+ <td>≥ 3.4
+ <td>53
+ <td>62
+ <tr>
+ <td>0.17.0
+ <td>≥ 3.4
+ <td>52
+ <td>62
+</table>
+
+## Clients
+
+[Selenium] users must update to version 3.11 or later to use geckodriver.
+Other clients that follow the [W3C WebDriver specification][WebDriver]
+are also supported.
+
+## Firefoxen
+
+geckodriver is not yet feature complete. This means that it does
+not yet offer full conformance with the [WebDriver] standard
+or complete compatibility with [Selenium]. You can track the
+[implementation status] of the latest [Firefox Nightly] on MDN.
+We also keep track of known [Selenium], [remote protocol], and
+[specification] problems in our [issue tracker].
+
+Support is best in Firefox 57 and greater, although generally the more
+recent the Firefox version, the better the experience as they have
+more bug fixes and features. Some features will only be available
+in the most recent Firefox versions, and we strongly advise using the
+latest [Firefox Nightly] with geckodriver. Since Windows XP support
+in Firefox was dropped with Firefox 53, we do not support this platform.
+
+## Android
+
+Starting with the 0.26.0 release geckodriver is able to connect
+to Android devices, and to control packages which are based on [GeckoView]
+(eg. [Firefox Preview] aka Fenix, or [Firefox Reality]). But it also still
+supports versions of Fennec up to 68 ESR, which is the last officially
+supported release from Mozilla.
+
+To run tests on Android specific capabilities under `moz:firefoxOptions`
+have to be set when requesting a new session. See the Android section under
+[Firefox Capabilities](Capabilities.md#android) for more details.
+
+[geckodriver releases]: https://github.com/mozilla/geckodriver/releases
+[Selenium]: https://github.com/seleniumhq/selenium
+[WebDriver]: https://w3c.github.io/webdriver/
+[implementation status]: https://bugzilla.mozilla.org/showdependencytree.cgi?id=721859&hide_resolved=1
+[remote protocol]: https://github.com/mozilla/geckodriver/issues?q=is%3Aissue+is%3Aopen+label%3Amarionette
+[specification]: https://github.com/mozilla/geckodriver/issues?q=is%3Aissue+is%3Aopen+label%3Aspec
+[issue tracker]: https://github.com/mozilla/geckodriver/issues
+[Firefox Nightly]: https://nightly.mozilla.org/
+[GeckoView]: https://wiki.mozilla.org/Mobile/GeckoView
+[Firefox Preview]: https://play.google.com/store/apps/details?id=org.mozilla.fenix
+[Firefox Reality]: https://play.google.com/store/apps/details?id=org.mozilla.vrbrowser
diff --git a/testing/geckodriver/doc/Testing.md b/testing/geckodriver/doc/Testing.md
new file mode 100644
index 0000000000..2f8f5c9ef6
--- /dev/null
+++ b/testing/geckodriver/doc/Testing.md
@@ -0,0 +1,69 @@
+# Testing geckodriver
+
+We verify and test geckodriver in a couple of different ways.
+Since it is an implementation of the WebDriver web standard, we share
+a set of conformance tests with other browser vendors through the
+[Web Platform Tests] (WPT) initiative. This lets us ensure web
+compatibility between _different_ WebDriver implementations for
+different browsers.
+
+In addition to the WPT tests, geckodriver and webdriver have
+unit tests. These are written in Rust, but you must explicitly
+tell mach to build these by adding the following line to your [mozconfig]:
+
+```make
+ac_add_options --enable-rust-tests
+```
+
+Tests can then be run by using the `test` sub command for [cargo] in the
+specific source folder:
+
+```shell
+% cd testing/geckodriver/src
+% cargo test
+```
+
+To run the more extensive WPT tests you can use mach, but first
+make sure you have built Firefox:
+
+```shell
+% ./mach build
+% ./mach wpt testing/web-platform/tests/webdriver
+```
+
+As these are functional integration tests and pop up Firefox windows
+sporadically, a helpful tip is to suppress the window whilst you
+are running them by using Firefox’ [headless mode]:
+
+```shell
+% ./mach wpt --headless testing/web-platform/tests/webdriver
+```
+
+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
+the additional benefit of also working on macOS and Windows.
+
+As you get in to development of geckodriver and Marionette you will
+increasingly grow to understand our love for [trace-level logs].
+They provide us with the input—the HTTP requests—from the client
+(in WPT’s case from the tests’ use of a custom WebDriver client),
+the translation geckodriver makes to the [Marionette protocol],
+the log output from Marionette, its responses back to geckodriver,
+and finally the output—or the HTTP response—back to the client.
+
+The [trace-level logs] can be surfaced by passing on the `-vv`
+flag to geckodriver through WPT:
+
+```shell
+% ./mach wpt --webdriver-arg=-vv testing/web-platform/tests/webdriver
+```
+
+[Web Platform Tests]: http://web-platform-tests.org/
+[cargo]: http://doc.crates.io/guide.html
+[headless mode]: https://developer.mozilla.org/en-US/Firefox/Headless_mode
+[mozconfig]: https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Configuring_Build_Options
+[trace-level logs]: TraceLogs.md
+[Marionette protocol]: /testing/marionette/Protocol.md
diff --git a/testing/geckodriver/doc/TraceLogs.md b/testing/geckodriver/doc/TraceLogs.md
new file mode 100644
index 0000000000..fb4e298c44
--- /dev/null
+++ b/testing/geckodriver/doc/TraceLogs.md
@@ -0,0 +1,206 @@
+# Enabling trace logs
+
+geckodriver provides different bands of logs for different audiences.
+The most important log entries are shown to everyone by default,
+and these include which port geckodriver provides the WebDriver
+API on, as well as informative warnings, errors, and fatal exceptions.
+
+The different log bands are, in ascending bandwidth:
+
+1. `fatal` is reserved for exceptional circumstances when geckodriver
+ or Firefox cannot recover. This usually entails that either
+ one or both of the processes will exit.
+
+2. `error` messages are mistakes in the program code which it is
+ possible to recover from.
+
+3. `warn` shows warnings of more informative nature that are not
+ necessarily problems in geckodriver. This could for example happen
+ if you use the legacy `desiredCapabilities`/`requiredCapabilities`
+ objects instead of the new `alwaysMatch`/`firstMatch` structures.
+
+4. `info` (default) contains information about which port geckodriver
+ binds to, but also all messages from the lower-bandwidth levels
+ listed above.
+
+5. `config` additionally shows the negotiated capabilities after
+ matching the `alwaysMatch` capabilities with the sequence of
+ `firstMatch` capabilities.
+
+6. `debug` is reserved for information that is useful when programming.
+
+7. `trace`, where in addition to itself, all previous levels
+ are included. The trace level shows all HTTP requests received
+ by geckodriver, packets sent to and from the remote protocol in
+ Firefox, and responses sent back to your client.
+
+In other words this means that the configured level will coalesce
+entries from all lower bands including itself. If you set the log
+level to `error`, you will get log entries for both `fatal` and `error`.
+Similarly for `trace`, you will get all the logs that are offered.
+
+To help debug a problem with geckodriver or Firefox, the trace-level
+output is vital to understand what is going on. This is why we ask
+that trace logs are included when filing bugs gainst geckodriver.
+It is only under very special circumstances that a trace log is
+not needed, so you will normally find that our first action when
+triaging your issue will be to ask you to include one. Do yourself
+and us a favour and provide a trace-level log right away.
+
+To silence geckodriver altogether you may for example either redirect
+all output to append to some log files:
+
+```shell
+% geckodriver >>geckodriver.log 2>>geckodriver.err.log
+```
+
+Or a black hole somewhere:
+
+```shell
+% geckodriver >/dev/null 2>&1
+```
+
+The log level set for geckodriver is propagated to the Marionette
+logger in Firefox. Marionette is the remote protocol that geckodriver
+uses to implement WebDriver. This means enabling trace logs for
+geckodriver will also implicitly enable them for Marionette.
+
+The log level is set in different ways. Either by using the
+`--log <LEVEL>` option, where `LEVEL` is one of the log levels
+from the list above, or by using the `-v` (for debug) or `-vv`
+(for trace) shorthands. For example, the following command will
+enable trace logs for both geckodriver and Marionette:
+
+```shell
+% geckodriver -vv
+```
+
+The second way of setting the log level is through capabilities.
+geckodriver accepts a Mozilla-specific configuration object
+in [`moz:firefoxOptions`]. This JSON Object, which is further
+described in the [README] can hold Firefox-specific configuration,
+such as which Firefox binary to use, additional preferences to set,
+and of course which log level to use.
+
+[`moz:firefoxOptions`]: https://searchfox.org/mozilla-central/source/testing/geckodriver/README.md#firefox-capabilities
+[README]: https://searchfox.org/mozilla-central/source/testing/geckodriver/README.md
+
+Each client has its own way of specifying capabilities, and some clients
+include “helpers” for providing browser-specific configuration.
+It is often advisable to use these helpers instead of encoding the
+JSON Object yourself because it can be difficult to get the exact
+details right, but if you choose to, it should look like this:
+
+```json
+{"moz:firefoxOptions": {"log": {"level": "trace"}}}
+```
+
+Note that most known WebDriver clients, such as those provided by
+the Selenium project, do not expose a way to actually _see_ the logs
+unless you redirect the log output to a particular file (using the
+method shown above) or let the client “inherit” geckodriver’s
+output, for example by redirecting the stdout and stderr streams to
+its own. The notable exceptions are the Python and Ruby bindings,
+which surface geckodriver logs in a remarkable easy and efficient way.
+
+See the client-specific documentation below for the most idiomatic
+way to enable trace logs in your language. We want to expand this
+documentation to cover all the best known clients people use with
+geckodriver. If you find your language missing, please consider
+[submitting a patch].
+
+[submitting a patch]: Patches.md
+
+## C-Sharp
+
+The Selenium [C# client] comes with a [`FirefoxOptions`] helper for
+constructing the [`moz:firefoxOptions`] capabilities object:
+
+```csharp
+FirefoxOptions options = new FirefoxOptions();
+options.LogLevel = FirefoxDriverLogLevel.Trace;
+IWebDriver driver = new FirefoxDriver(options);
+```
+
+The log output is directed to stdout.
+
+[C# client]: https://seleniumhq.github.io/selenium/docs/api/dotnet/
+[`FirefoxOptions`]: https://seleniumhq.github.io/selenium/docs/api/dotnet/html/T_OpenQA_Selenium_Firefox_FirefoxOptions.htm
+
+## Java
+
+The Selenium [Java client] also comes with
+a [`org.openqa.selenium.firefox.FirefoxOptions`] helper for
+constructing the [`moz:firefoxOptions`] capabilities object:
+
+```java
+FirefoxOptions options = new FirefoxOptions();
+options.setLogLevel(FirefoxDriverLogLevel.TRACE);
+WebDriver driver = new FirefoxDriver(options);
+```
+
+The log output is directed to stdout.
+
+[Java client]: https://seleniumhq.github.io/selenium/docs/api/java/
+[`org.openqa.selenium.firefox.FirefoxOptions`]: https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/firefox/FirefoxOptions.html
+
+## Javascript (webdriver.io)
+
+With the Selenium [JavaScript client] the capabilities object can directly be
+constructed:
+
+```javascript
+import WebDriver from 'webdriver'
+
+const driver = await WebDriver.newSession({
+ capabilities: {
+ browserName: 'firefox',
+ 'moz:firefoxOptions': {
+ log: { level: 'trace' },
+ }
+ }
+})
+```
+
+The log output is directed to stdout, or if geckodriver runs as a wdio plugin
+then the generated logs are part of the wdio log system.
+
+[JavaScript client]: https://webdriver.io/
+
+## Python
+
+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:
+
+```python
+from selenium.webdriver import Firefox
+from selenium.webdriver.firefox.options import Options
+
+opts = Options()
+opts.log.level = "trace"
+driver = Firefox(options=opts)
+```
+
+The log output is stored in a file called _geckodriver.log_ in your
+script’s current working directory.
+
+[Python client]: https://selenium-python.readthedocs.io/
+[`selenium.webdriver.firefox.options.Options`]: https://github.com/SeleniumHQ/selenium/blob/master/py/selenium/webdriver/firefox/options.py
+
+## Ruby
+
+The Selenium [Ruby client] comes with an [`Options`] helper to
+generate the correct [`moz:firefoxOptions`] capabilities object:
+
+```ruby
+Selenium::WebDriver.logger.level = :debug
+opts = Selenium::WebDriver::Firefox::Options.new(log_level: :trace)
+driver = Selenium::WebDriver.for :firefox, options: opts
+```
+
+The log output is directed to stdout.
+
+[Ruby client]: https://seleniumhq.github.io/selenium/docs/api/rb/
+[`Options`]: https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/Firefox/Options.html
diff --git a/testing/geckodriver/doc/Usage.md b/testing/geckodriver/doc/Usage.md
new file mode 100644
index 0000000000..ee4ab86f8d
--- /dev/null
+++ b/testing/geckodriver/doc/Usage.md
@@ -0,0 +1,143 @@
+# Usage
+
+geckodriver is an implementation of WebDriver, and WebDriver can
+be used for widely different purposes. How you invoke geckodriver
+largely depends on your use case.
+
+## Running Firefox in a container-based package
+
+When Firefox is packaged inside a container (e.g. [Snap], [Flatpak]), it may
+see a different filesystem to the host. This can affect access to the generated
+profile directory, which may result in a hang when starting Firefox.
+
+This is known to affect launching the default Firefox shipped with Ubuntu 22.04+.
+
+There are several workarounds available for this problem:
+
+- Do not use container-packaged Firefox builds with geckodriver. Instead
+download a Firefox release from <https://download.mozilla.org/?product=firefox-latest&os=linux>
+and a geckodriver release from <https://github.com/mozilla/geckodriver/releases>.
+
+- Use a geckodriver that runs in the same container filesystem as the Firefox
+package. For example on Ubuntu `/snap/bin/geckodriver` will work with the
+default Firefox.
+
+- Set the `--profile-root` command line option to write the profile to a
+directory accessible to both Firefox and geckodriver, for example a non-hidden
+directory under `$HOME`.
+
+[Flatpak]: https://flatpak.org/
+[Snap]: https://ubuntu.com/core/services/guide/snaps-intro
+
+## Selenium
+
+If you are using geckodriver through [Selenium], you must ensure that
+you have version 3.11 or greater. Because geckodriver implements the
+[W3C WebDriver standard][WebDriver] and not the same Selenium wire
+protocol older drivers are using, you may experience incompatibilities
+and migration problems when making the switch from FirefoxDriver to
+geckodriver.
+
+Generally speaking, Selenium 3 enabled geckodriver as the default
+WebDriver implementation for Firefox. With the release of Firefox 47,
+FirefoxDriver had to be discontinued for its lack of support for the
+[new multi-processing architecture in Gecko][e10s].
+
+Selenium client bindings will pick up the _geckodriver_ binary executable
+from your [system’s `PATH` environmental variable][PATH] unless you
+override it by setting the `webdriver.gecko.driver` [Java VM system
+property]:
+
+```java
+System.setProperty("webdriver.gecko.driver", "/home/user/bin");
+```
+
+Or by passing it as a flag to the [java(1)] launcher:
+
+```shell
+% java -Dwebdriver.gecko.driver=/home/user/bin YourApplication
+```
+
+Your mileage with this approach may vary based on which programming
+language bindings you are using. It is in any case generally the case
+that geckodriver will be picked up if it is available on the system path.
+In a bash compatible shell, you can make other programs aware of its
+location by exporting or setting the `PATH` variable:
+
+```shell
+% export PATH=$PATH:/home/user/bin
+% whereis geckodriver
+geckodriver: /home/user/bin/geckodriver
+```
+
+On Window systems you can change the system path by right-clicking **My
+Computer** and choosing **Properties**. In the dialogue that appears,
+navigate **Advanced** → **Environmental Variables** → **Path**.
+
+Or in the Windows console window:
+
+```shell
+% set PATH=%PATH%;C:\bin\geckodriver
+```
+
+## Standalone
+
+Since geckodriver is a separate HTTP server that is a complete remote end
+implementation of [WebDriver], it is possible to avoid using the Selenium
+remote server if you have no requirements to distribute processes across
+a matrix of systems.
+
+Given a W3C WebDriver conforming client library (or _local end_) you
+may interact with the geckodriver HTTP server as if you were speaking
+to any Selenium server.
+
+Using [curl(1)]:
+
+```shell
+% geckodriver &
+[1] 16010
+% 1491834109194 geckodriver INFO Listening on 127.0.0.1:4444
+% curl -H 'Content-Type: application/json' -d '{"capabilities": {"alwaysMatch": {"acceptInsecureCerts": true}}}' http://localhost:4444/session
+{"value":{"sessionId":"d4605710-5a4e-4d64-a52a-778bb0c31e00","capabilities":{"acceptInsecureCerts":true,[...]}}}
+% curl -H 'Content-Type: application/json' -d '{"url": "https://mozilla.org"}' http://localhost:4444/session/d4605710-5a4e-4d64-a52a-778bb0c31e00/url
+{}
+% curl http://localhost:4444/session/d4605710-5a4e-4d64-a52a-778bb0c31e00/url
+{"value":"https://www.mozilla.org/en-US/"
+% curl -X DELETE http://localhost:4444/session/d4605710-5a4e-4d64-a52a-778bb0c31e00
+{}
+% fg
+geckodriver
+^C
+```
+
+Using the Python [wdclient] library:
+
+```python
+import webdriver
+
+with webdriver.Session("127.0.0.1", 4444) as session:
+ session.url = "https://mozilla.org"
+ print "The current URL is %s" % session.url
+```
+
+And to run:
+
+```shell
+% geckodriver &
+[1] 16054
+% python example.py
+1491835308354 geckodriver INFO Listening on 127.0.0.1:4444
+The current URL is https://www.mozilla.org/en-US/
+% fg
+geckodriver
+^C
+```
+
+[Selenium]: http://seleniumhq.org/
+[e10s]: https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox
+[PATH]: https://en.wikipedia.org/wiki/PATH_(variable)
+[Java VM system property]: http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
+[java(1)]: http://www.manpagez.com/man/1/java/
+[WebDriver]: https://w3c.github.io/webdriver/
+[curl(1)]: http://www.manpagez.com/man/1/curl/
+[wdclient]: https://github.com/web-platform-tests/wpt/tree/master/tools/webdriver
diff --git a/testing/geckodriver/doc/index.rst b/testing/geckodriver/doc/index.rst
new file mode 100644
index 0000000000..863c05810c
--- /dev/null
+++ b/testing/geckodriver/doc/index.rst
@@ -0,0 +1,55 @@
+===========
+geckodriver
+===========
+
+Proxy for using W3C WebDriver-compatible clients to interact with
+Gecko-based browsers.
+
+This program provides the HTTP API described by the `WebDriver protocol`_.
+to communicate with Gecko browsers, such as Firefox. It translates calls
+into the :ref:`Firefox remote protocol <Protocol>` by acting as a proxy between the local-
+and remote ends.
+
+You can consult the `change log`_ for a record of all notable changes
+to the program. Releases_ are made available on GitHub.
+
+.. _WebDriver protocol: https://w3c.github.io/webdriver/#protocol
+.. _change log: https://github.com/mozilla/geckodriver/releases
+.. _Releases: https://github.com/mozilla/geckodriver/releases
+
+
+.. toctree::
+ :maxdepth: 1
+
+ Support.md
+ WebDriver capabilities <https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities>
+ Capabilities.md
+ Usage.md
+ Flags.md
+ Profiles.md
+ Bugs.md
+ TraceLogs.md
+ CrashReports.md
+ Notarization.md
+
+
+For developers
+==============
+.. toctree::
+ :maxdepth: 1
+
+ Building.md
+ Testing.md
+ Patches.md
+ Releasing.md
+ ARM.md
+
+
+Communication
+=============
+
+The mailing list for geckodriver discussion is
+https://groups.google.com/a/mozilla.org/g/dev-webdriver.
+
+If you prefer real-time chat, ask your questions
+on `#webdriver:mozilla.org <https://chat.mozilla.org/#/room/#webdriver:mozilla.org>`__.