Bug 1384517 - Fix testing/marionette API docs; r=automatedtester
authorAndreas Tolfsen <ato@sny.no>
Wed, 26 Jul 2017 13:11:53 +0100
changeset 419917 c530d257c6d254246db783792ed8c62f3673fcc0
parent 419916 9c46b91899fa2933e362200e4dbffd6b9e1e5c5a
child 419918 31dcb89c3c4bab13b99e9c4f9c25ffa102fc3629
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersautomatedtester
bugs1384517
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1384517 - Fix testing/marionette API docs; r=automatedtester Various fixes to make the generated API documentation from testing/marionette somewhat easier to read. MozReview-Commit-ID: F9duuQoOYBt
testing/marionette/accessibility.js
testing/marionette/action.js
testing/marionette/addon.js
testing/marionette/assert.js
testing/marionette/atom.js
testing/marionette/browser.js
testing/marionette/capture.js
testing/marionette/cert.js
testing/marionette/cookie.js
testing/marionette/driver.js
testing/marionette/element.js
testing/marionette/error.js
testing/marionette/evaluate.js
testing/marionette/event.js
testing/marionette/frame.js
testing/marionette/interaction.js
testing/marionette/l10n.js
testing/marionette/legacyaction.js
testing/marionette/listener.js
testing/marionette/message.js
testing/marionette/modal.js
testing/marionette/navigate.js
testing/marionette/packets.js
testing/marionette/proxy.js
testing/marionette/reftest.js
testing/marionette/server.js
testing/marionette/session.js
testing/marionette/stream-utils.js
testing/marionette/transport.js
testing/marionette/wait.js
--- a/testing/marionette/accessibility.js
+++ b/testing/marionette/accessibility.js
@@ -27,16 +27,17 @@ XPCOMUtils.defineLazyGetter(this, "servi
   } catch (e) {
     logger.warn("Accessibility module is not present");
     return undefined;
   }
 });
 
 this.EXPORTED_SYMBOLS = ["accessibility"];
 
+/** @namespace */
 this.accessibility = {
   get service() {
     return service;
   },
 };
 
 /**
  * Accessible states used to check element"s state from the accessiblity API
@@ -119,17 +120,17 @@ accessibility.Checks = class {
    * Get an accessible object for an element.
    *
    * @param {DOMElement|XULElement} element
    *     Element to get the accessible object for.
    * @param {boolean=} mustHaveAccessible
    *     Flag indicating that the element must have an accessible object.
    *     Defaults to not require this.
    *
-   * @return {Promise: nsIAccessible}
+   * @return {Promise.<nsIAccessible>}
    *     Promise with an accessibility object for the given element.
    */
   getAccessible(element, mustHaveAccessible = false) {
     if (!this.strict) {
       return Promise.resolve();
     }
 
     return new Promise((resolve, reject) => {
--- a/testing/marionette/action.js
+++ b/testing/marionette/action.js
@@ -25,16 +25,18 @@ this.EXPORTED_SYMBOLS = ["action"];
 
 const {pprint} = error;
 
 // TODO? With ES 2016 and Symbol you can make a safer approximation
 // to an enum e.g. https://gist.github.com/xmlking/e86e4f15ec32b12c4689
 /**
  * Implements WebDriver Actions API: a low-level interface for providing
  * virtualised device input to the web browser.
+ *
+ * @namespace
  */
 this.action = {
   Pause: "pause",
   KeyDown: "keyDown",
   KeyUp: "keyUp",
   PointerDown: "pointerDown",
   PointerUp: "pointerUp",
   PointerMove: "pointerMove",
@@ -341,25 +343,25 @@ const KEY_CODE_LOOKUP = {
 action.PointerOrigin = {
   Viewport: "viewport",
   Pointer: "pointer",
 };
 
 /**
  * Look up a PointerOrigin.
  *
- * @param {?} obj
+ * @param {(undefined|string|WebElement)} obj
  *     Origin for a pointerMove action.
  *
- * @return {?}
+ * @return {action.PointerOrigin}
  *     A pointer origin that is either "viewport" (default), "pointer", or a
  *     web-element reference.
  *
  * @throws {InvalidArgumentError}
- *     If |obj| is not a valid origin.
+ *     If <code>obj</code> is not a valid origin.
  */
 action.PointerOrigin.get = function(obj) {
   let origin = obj;
   if (typeof obj == "undefined") {
     origin = this.Viewport;
   } else if (typeof obj == "string") {
     let name = capitalize(obj);
     assert.in(name, this, pprint`Unknown pointer-move origin: ${obj}`);
@@ -384,17 +386,17 @@ action.PointerType = {
  *
  * @param {string} str
  *     Name of pointer type.
  *
  * @return {string}
  *     A pointer type for processing pointer parameters.
  *
  * @throws {InvalidArgumentError}
- *     If |str| is not a valid pointer type.
+ *     If <code>str</code> is not a valid pointer type.
  */
 action.PointerType.get = function(str) {
   let name = capitalize(str);
   assert.in(name, this, pprint`Unknown pointerType: ${str}`);
   return this[name];
 };
 
 /**
@@ -402,17 +404,17 @@ action.PointerType.get = function(str) {
  * input ID and the device state for that input source, with one entry
  * for each active input source.
  *
  * Initialized in listener.js.
  */
 action.inputStateMap = undefined;
 
 /**
- * List of |action.Action| associated with current session.  Used to
+ * List of {@link action.Action} associated with current session.  Used to
  * manage dispatching events when resetting the state of the input sources.
  * Reset operations are assumed to be idempotent.
  *
  * Initialized in listener.js
  */
 action.inputsToCancel = undefined;
 
 /**
@@ -421,42 +423,46 @@ action.inputsToCancel = undefined;
 class InputState {
   constructor() {
     this.type = this.constructor.name.toLowerCase();
   }
 
   /**
    * Check equality of this InputState object with another.
    *
-   * @para{?} other
+   * @param {InputState} other
    *     Object representing an input state.
+   *
    * @return {boolean}
-   *     True if |this| has the same |type| as |other|.
+   *     True if <code>this</code> has the same <code>type</code>
+   *     as <code>other</code>.
    */
   is(other) {
     if (typeof other == "undefined") {
       return false;
     }
     return this.type === other.type;
   }
 
   toString() {
     return `[object ${this.constructor.name}InputState]`;
   }
 
   /**
-   * @param {?} obj
-   *     Object with property |type| and optionally |parameters| or
-   *     |pointerType|, representing an action sequence or an action item.
+   * @param {Object.<string, ?>} obj
+   *     Object with property <code>type</code> and optionally
+   *     <code>parameters</code> or <code>pointerType</code>,
+   *     representing an action sequence or an action item.
    *
    * @return {action.InputState}
-   *     An |action.InputState| object for the type of the |actionSequence|.
+   *     An {@link InputState} object for the type of the
+   *     {@link actionSequence}.
    *
    * @throws {InvalidArgumentError}
-   *     If |actionSequence.type| is not valid.
+   *     If {@link actionSequence.type} is not valid.
    */
   static fromJson(obj) {
     let type = obj.type;
     assert.in(type, ACTIONS, pprint`Unknown action type: ${type}`);
     let name = type == "none" ? "Null" : capitalize(type);
     if (name == "Pointer") {
       if (!obj.pointerType &&
           (!obj.parameters || !obj.parameters.pointerType)) {
@@ -623,18 +629,20 @@ action.InputState.Pointer = class Pointe
  * Repesents an action for dispatch. Used in |action.Chain| and
  * |action.Sequence|.
  *
  * @param {string} id
  *     Input source ID.
  * @param {string} type
  *     Action type: none, key, pointer.
  * @param {string} subtype
- *     Action subtype: pause, keyUp, keyDown, pointerUp, pointerDown,
- *     pointerMove, pointerCancel.
+ *     Action subtype: {@link action.Pause}, {@link action.KeyUp},
+ *     {@link action.KeyDown}, {@link action.PointerUp},
+ *     {@link action.PointerDown}, {@link action.PointerMove}, or
+ *     {@link action.PointerCancel}.
  *
  * @throws {InvalidArgumentError}
  *      If any parameters are undefined.
  */
 action.Action = class {
   constructor(id, type, subtype) {
     if ([id, type, subtype].includes(undefined)) {
       throw new InvalidArgumentError("Missing id, type or subtype");
@@ -647,28 +655,29 @@ action.Action = class {
     this.subtype = subtype;
   }
 
   toString() {
     return `[action ${this.type}]`;
   }
 
   /**
-   * @param {?} actionSequence
+   * @param {action.Sequence} actionSequence
    *     Object representing sequence of actions from one input source.
-   * @param {?} actionItem
+   * @param {action.Action} actionItem
    *     Object representing a single action from |actionSequence|.
    *
    * @return {action.Action}
    *     An action that can be dispatched; corresponds to |actionItem|.
    *
    * @throws {InvalidArgumentError}
-   *     If any |actionSequence| or |actionItem| attributes are invalid.
+   *     If any <code>actionSequence</code> or <code>actionItem</code>
+   *     attributes are invalid.
    * @throws {UnsupportedOperationError}
-   *     If |actionItem.type| is |pointerCancel|.
+   *     If <code>actionItem.type</code> is {@link action.PointerCancel}.
    */
   static fromJson(actionSequence, actionItem) {
     let type = actionSequence.type;
     let id = actionSequence.id;
     let subtypes = ACTIONS[type];
     if (!subtypes) {
       throw new InvalidArgumentError("Unknown type: " + type);
     }
@@ -785,17 +794,17 @@ action.Chain = class extends Array {
  * |Array.<action.Action>|.
  */
 action.Sequence = class extends Array {
   toString() {
     return `[sequence ${super.toString()}]`;
   }
 
   /**
-   * @param {?} actionSequence
+   * @param {Object.<string, ?>} actionSequence
    *     Object that represents a sequence action items for one input source.
    *
    * @return {action.Sequence}
    *     Sequence of actions that can be dispatched.
    *
    * @throws {InvalidArgumentError}
    *     If |actionSequence.id| is not a string or it's aleady mapped
    *     to an |action.InputState} incompatible with |actionSequence.type|.
@@ -838,17 +847,17 @@ action.PointerParameters = class {
     this.pointerType = action.PointerType.get(pointerType);
   }
 
   toString() {
     return `[pointerParameters ${this.pointerType}]`;
   }
 
   /**
-   * @param {?} parametersData
+   * @param {Object.<string, ?>} parametersData
    *     Object that represents pointer parameters.
    *
    * @return {action.PointerParameters}
    *     Validated pointer paramters.
    */
   static fromJson(parametersData) {
     if (typeof parametersData == "undefined") {
       return new action.PointerParameters();
@@ -949,18 +958,19 @@ action.Mouse = class {
  * tick's actions are not dispatched until the Promise for the current
  * tick is resolved.
  *
  * @param {action.Chain} chain
  *     Actions grouped by tick; each element in |chain| is a sequence of
  *     actions for one tick.
  * @param {element.Store} seenEls
  *     Element store.
- * @param {?} container
- *     Object with |frame| attribute of type |nsIDOMWindow|.
+ * @param {Object.<string, nsIDOMWindow>} container
+ *     Object with <code>frame</code> property of type
+ *     <code>nsIDOMWindow</code>.
  *
  * @return {Promise}
  *     Promise for dispatching all actions in |chain|.
  */
 action.dispatch = function(chain, seenEls, container) {
   let chainEvents = Task.spawn(function*() {
     for (let tickActions of chain) {
       yield action.dispatchTickActions(
@@ -985,18 +995,19 @@ action.dispatch = function(chain, seenEl
  * different durations and therefore may not end in the same order.
  *
  * @param {Array.<action.Action>} tickActions
  *     List of actions for one tick.
  * @param {number} tickDuration
  *     Duration in milliseconds of this tick.
  * @param {element.Store} seenEls
  *     Element store.
- * @param {?} container
- *     Object with |frame| attribute of type |nsIDOMWindow|.
+ * @param {Object.<string, nsIDOMWindow>} container
+ *     Object with <code>frame</code> property of type
+ *     <code>nsIDOMWindow</code>.
  *
  * @return {Promise}
  *     Promise for dispatching all tick-actions and pending DOM events.
  */
 action.dispatchTickActions = function(
     tickActions, tickDuration, seenEls, container) {
   let pendingEvents = tickActions.map(
       toEvents(tickDuration, seenEls, container));
@@ -1062,18 +1073,19 @@ action.computePointerDestination = funct
 
 /**
  * Create a closure to use as a map from action definitions to Promise events.
  *
  * @param {number} tickDuration
  *     Duration in milliseconds of this tick.
  * @param {element.Store} seenEls
  *     Element store.
- * @param {?} container
- *     Object with |frame| attribute of type |nsIDOMWindow|.
+ * @param {Object.<string, nsIDOMWindow>} container
+ *     Object with <code>frame</code> property of type
+ *     <code>nsIDOMWindow</code>.
  *
  * @return {function(action.Action): Promise}
  *     Function that takes an action and returns a Promise for dispatching
  *     the event that corresponds to that action.
  */
 function toEvents(tickDuration, seenEls, container) {
   return a => {
     let inputState = action.inputStateMap.get(a.id);
@@ -1263,18 +1275,19 @@ function dispatchPointerUp(a, inputState
  * with the pointer coordinates being updated around 60 times per second.
  *
  * @param {action.Action} a
  *     Action to dispatch.
  * @param {action.InputState} inputState
  *     Input state for this action's input source.
  * @param {element.Store} seenEls
  *     Element store.
- * @param {?} container
- *     Object with |frame| attribute of type |nsIDOMWindow|.
+ * @param {Object.<string, nsIDOMWindow>} container
+ *     Object with <code>frame</code> property of type
+ *     <code>nsIDOMWindow</code>.
  *
  * @return {Promise}
  *     Promise to dispatch at least one pointermove event, as well as
  *     mousemove events as appropriate.
  */
 function dispatchPointerMove(
     a, inputState, tickDuration, seenEls, container) {
   const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
--- a/testing/marionette/addon.js
+++ b/testing/marionette/addon.js
@@ -8,16 +8,17 @@ const {interfaces: Ci, utils: Cu} = Comp
 
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 
 const {UnknownError} = Cu.import("chrome://marionette/content/error.js", {});
 
 this.EXPORTED_SYMBOLS = ["addon"];
 
+/** @namespace */
 this.addon = {};
 
 // from https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
 addon.Errors = {
   [-1]: "ERROR_NETWORK_FAILURE: A network error occured.",
   [-2]: "ERROR_INCORECT_HASH: The downloaded file did not match the expected hash.",
   [-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
   [-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
@@ -38,17 +39,17 @@ function lookupError(code) {
  * Temporary addons will automatically be uninstalled on shutdown and
  * do not need to be signed, though they must be restartless.
  *
  * @param {string} path
  *     Full path to the extension package archive.
  * @param {boolean=} temporary
  *     True to install the addon temporarily, false (default) otherwise.
  *
- * @return {Promise: string}
+ * @return {Promise.<string>}
  *     Addon ID.
  *
  * @throws {UnknownError}
  *     If there is a problem installing the addon.
  */
 addon.install = function(path, temporary = false) {
   return new Promise((resolve, reject) => {
     let file = new FileUtils.File(path);
--- a/testing/marionette/assert.js
+++ b/testing/marionette/assert.js
@@ -19,17 +19,21 @@ const {
   UnsupportedOperationError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 
 this.EXPORTED_SYMBOLS = ["assert"];
 
 const isFennec = () => AppConstants.platform == "android";
 const isFirefox = () => Services.appinfo.name == "Firefox";
 
-/** Shorthands for common assertions made in Marionette. */
+/**
+ * Shorthands for common assertions made in Marionette.
+ *
+ * @namespace
+ */
 this.assert = {};
 
 /**
  * Asserts that Marionette has a session.
  *
  * @param {GeckoDriver} driver
  *     Marionette driver instance.
  * @param {string=} msg
--- a/testing/marionette/atom.js
+++ b/testing/marionette/atom.js
@@ -9,16 +9,17 @@
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
 this.EXPORTED_SYMBOLS = ["atom"];
 
+/** @namespace */
 this.atom = {};
 
 // https://github.com/SeleniumHQ/selenium/blob/master/javascript/atoms/action.js#L83
 atom.clearElement = function (element, window){return function(){function g(a){throw a;}var h=void 0,i=!0,k=null,l=!1;function n(a){return function(){return this[a]}}function o(a){return function(){return a}}var p,q=this;
 function aa(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
 else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function r(a){return a!==h}function ba(a){var b=aa(a);return"array"==b||"object"==b&&"number"==typeof a.length}function t(a){return"string"==typeof a}function w(a){return"function"==aa(a)}function ca(a){a=aa(a);return"object"==a||"array"==a||"function"==a}var da="closure_uid_"+Math.floor(2147483648*Math.random()).toString(36),ea=0,fa=Date.now||function(){return+new Date};
 function x(a,b){function c(){}c.prototype=b.prototype;a.$=b.prototype;a.prototype=new c};function ga(a,b){for(var c=1;c<arguments.length;c++)var d=(""+arguments[c]).replace(/\$/g,"$$$$"),a=a.replace(/\%s/,d);return a}function ha(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")}function ia(a){if(!ja.test(a))return a;-1!=a.indexOf("&")&&(a=a.replace(ka,"&amp;"));-1!=a.indexOf("<")&&(a=a.replace(la,"&lt;"));-1!=a.indexOf(">")&&(a=a.replace(ma,"&gt;"));-1!=a.indexOf('"')&&(a=a.replace(na,"&quot;"));return a}var ka=/&/g,la=/</g,ma=/>/g,na=/\"/g,ja=/[&<>\"]/;
 function oa(a,b){for(var c=0,d=ha(""+a).split("."),e=ha(""+b).split("."),f=Math.max(d.length,e.length),j=0;0==c&&j<f;j++){var m=d[j]||"",s=e[j]||"",O=RegExp("(\\d*)(\\D*)","g"),E=RegExp("(\\d*)(\\D*)","g");do{var u=O.exec(m)||["","",""],v=E.exec(s)||["","",""];if(0==u[0].length&&0==v[0].length)break;c=((0==u[1].length?0:parseInt(u[1],10))<(0==v[1].length?0:parseInt(v[1],10))?-1:(0==u[1].length?0:parseInt(u[1],10))>(0==v[1].length?0:parseInt(v[1],10))?1:0)||((0==u[2].length)<(0==v[2].length)?-1:(0==
--- a/testing/marionette/browser.js
+++ b/testing/marionette/browser.js
@@ -11,27 +11,28 @@ Cu.import("chrome://marionette/content/e
 const {
   NoSuchWindowError,
   UnsupportedOperationError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 Cu.import("chrome://marionette/content/frame.js");
 
 this.EXPORTED_SYMBOLS = ["browser"];
 
+/** @namespace */
 this.browser = {};
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /**
- * Get the <xul:browser> for the specified tab.
+ * Get the <code>&lt;xul:browser&gt;</code> for the specified tab.
  *
- * @param {<xul:tab>} tab
+ * @param {Tab} tab
  *     The tab whose browser needs to be returned.
  *
- * @return {<xul:browser>}
+ * @return {Browser}
  *     The linked browser for the tab or null if no browser can be found.
  */
 browser.getBrowserForTab = function(tab) {
   // Fennec
   if ("browser" in tab) {
     return tab.browser;
 
   // Firefox
@@ -43,17 +44,17 @@ browser.getBrowserForTab = function(tab)
 };
 
 /**
  * Return the tab browser for the specified chrome window.
  *
  * @param {nsIDOMWindow} win
  *     The window whose tabbrowser needs to be accessed.
  *
- * @return {<xul:tabbrowser>}
+ * @return {Tab}
  *     Tab browser or null if it's not a browser window.
  */
 browser.getTabBrowser = function(win) {
   // Fennec
   if ("BrowserApp" in win) {
     return win.BrowserApp;
 
   // Firefox
--- a/testing/marionette/capture.js
+++ b/testing/marionette/capture.js
@@ -9,17 +9,21 @@ Cu.importGlobalProperties(["crypto"]);
 
 this.EXPORTED_SYMBOLS = ["capture"];
 
 const CONTEXT_2D = "2d";
 const BG_COLOUR = "rgb(255,255,255)";
 const PNG_MIME = "image/png";
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
-/** Provides primitives to capture screenshots. */
+/**
+ * Provides primitives to capture screenshots.
+ *
+ * @namespace
+ */
 this.capture = {};
 
 capture.Format = {
   Base64: 0,
   Hash: 1,
 };
 
 /**
--- a/testing/marionette/cert.js
+++ b/testing/marionette/cert.js
@@ -17,17 +17,21 @@ const sss = Cc["@mozilla.org/ssservice;1
     .getService(Ci.nsISiteSecurityService);
 
 const CONTRACT_ID = "@mozilla.org/security/certoverride;1";
 const CERT_PINNING_ENFORCEMENT_PREF =
     "security.cert_pinning.enforcement_level";
 const HSTS_PRELOAD_LIST_PREF =
     "network.stricttransportsecurity.preloadlist";
 
-/** TLS certificate service override management for Marionette. */
+/**
+ * TLS certificate service override management for Marionette.
+ *
+ * @namespace
+ */
 this.cert = {
   Error: {
     Untrusted: 1,
     Mismatch: 2,
     Time: 4,
   },
 
   currentOverride: null,
--- a/testing/marionette/cookie.js
+++ b/testing/marionette/cookie.js
@@ -13,34 +13,43 @@ const {
   error,
   InvalidCookieDomainError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 
 this.EXPORTED_SYMBOLS = ["cookie"];
 
 const IPV4_PORT_EXPR = /:\d+$/;
 
+/** @namespace */
 this.cookie = {
   manager: Services.cookies,
 };
 
 /**
+ * @name Cookie
+ *
+ * @return {Object.<string, (number|boolean|string)>
+ */
+
+/**
  * Unmarshal a JSON Object to a cookie representation.
  *
  * Effectively this will run validation checks on |json|, which will
  * produce the errors expected by WebDriver if the input is not valid.
  *
- * @param {Map.<string, (number|boolean|string)> json
- *     Cookie to be deserialised.  |name| and |value| are required fields
- *     which must be strings.  The |path| field is optional, but must
- *     be a string if provided.  The |secure|, |httpOnly|, and |session|
- *     fields are similarly optional, but must be booleans.  Likewise,
- *     the |expiry| field is optional but must be unsigned integer.
+ * @param {Object.<string, (number|boolean|string)>} json
+ *     Cookie to be deserialised.  <var>name</var> and <var>value</var>
+ *     are required fields which must be strings.  The <var>path</var>
+ *     field is optional, but must be a string if provided.
+ *     The <var>secure</var>, <var>httpOnly</var>, and
+ *     <var>session</var>fields are similarly optional, but must be
+ *     booleans.  Likewise, the <var>expiry</var> field is optional but
+ *     must be unsigned integer.
  *
- * @return {Map.<string, (number|boolean|string)>
+ * @return {Cookie}
  *     Valid cookie object.
  *
  * @throws {InvalidArgumentError}
  *     If any of the properties are invalid.
  */
 cookie.fromJSON = function(json) {
   let newCookie = {};
 
@@ -66,55 +75,50 @@ cookie.fromJSON = function(json) {
   }
 
   return newCookie;
 };
 
 /**
  * Insert cookie to the cookie store.
  *
- * @param {Map.<string, (string|number|boolean)} newCookie
+ * @param {Cookie} newCookie
  *     Cookie to add.
- * @param {Map.<string, ?>} opts
- *     Optional parameters:
- *
- *       restrictToHost (string)
- *         Perform test that |newCookie|'s domain matches this.
+ * @param {string=} restrictToHost
+ *     Perform test that <var>newCookie</var>'s domain matches this.
  *
  * @throws {TypeError}
- *     If |name|, |value|, or |domain| are not present and of the
- *     correct type.
+ *     If <var>name</var>, <var>value</var>, or <var>domain</var> are
+ *     not present and of the correct type.
  * @throws {InvalidCookieDomainError}
- *     If |restrictToHost| is set and |newCookie|'s domain does not match.
+ *     If <var>restrictToHost</var> is set and <var>newCookie</var>'s
+ *     domain does not match.
  */
-cookie.add = function(newCookie, opts = {}) {
+cookie.add = function(newCookie, {restrictToHost = null} = {}) {
   assert.string(newCookie.name, "Cookie name must be string");
   assert.string(newCookie.value, "Cookie value must be string");
   assert.string(newCookie.domain, "Cookie domain must be string");
 
   if (typeof newCookie.path == "undefined") {
     newCookie.path = "/";
   }
 
   if (typeof newCookie.expiry == "undefined") {
     // twenty years into the future
     let date = new Date();
     let now = new Date(Date.now());
     date.setYear(now.getFullYear() + 20);
     newCookie.expiry = date.getTime() / 1000;
   }
 
-  if (opts.restrictToHost) {
-    assert.in("restrictToHost", opts,
-        "Missing cookie domain for host restriction test");
-
-    if (newCookie.domain !== opts.restrictToHost) {
+  if (restrictToHost) {
+    if (newCookie.domain !== restrictToHost) {
       throw new InvalidCookieDomainError(
           `Cookies may only be set ` +
-          ` for the current domain (${opts.restrictToHost})`);
+          ` for the current domain (${restrictToHost})`);
     }
   }
 
   // remove port from domain, if present.
   // unfortunately this catches IPv6 addresses by mistake
   // TODO: Bug 814416
   newCookie.domain = newCookie.domain.replace(IPV4_PORT_EXPR, "");
 
@@ -128,40 +132,41 @@ cookie.add = function(newCookie, opts = 
       newCookie.session,
       newCookie.expiry,
       {} /* origin attributes */);
 };
 
 /**
  * Remove cookie from the cookie store.
  *
- * @param {Map.<string, (string|number|boolean)} toDelete
+ * @param {Cookie} toDelete
  *     Cookie to remove.
  */
 cookie.remove = function(toDelete) {
   cookie.manager.remove(
       toDelete.domain,
       toDelete.name,
       toDelete.path,
       false,
       {} /* originAttributes */);
 };
 
 /**
- * Iterates over the cookies for the current |host|.  You may optionally
- * filter for specific paths on that |host| by specifying a path in
- * |currentPath|.
+ * Iterates over the cookies for the current <var>host</var>.  You may
+ * optionally filter for specific paths on that <var>host</var> by
+ * specifying a path in <var>currentPath</var>.
  *
  * @param {string} host
  *     Hostname to retrieve cookies for.
- * @param {string=} currentPath
- *     Optionally filter the cookies for |host| for the specific path.
- *     Defautls to "/", meaning all cookies for |host| are included.
+ * @param {string=} [currentPath="/"] currentPath
+ *     Optionally filter the cookies for <var>host</var> for the
+ *     specific path.  Defaults to "<tt>/</tt>", meaning all cookies
+ *     for <var>host</var> are included.
  *
- * @return {[Symbol.Iterator]}
+ * @return {Iterable.<Cookie>}
  *     Iterator.
  */
 cookie.iter = function*(host, currentPath = "/") {
   assert.string(host, "host must be string");
   assert.string(currentPath, "currentPath must be string");
 
   const isForCurrentPath = path => currentPath.indexOf(path) != -1;
 
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -70,59 +70,80 @@ const SUPPORTED_STRATEGIES = new Set([
   element.Strategy.Anon,
   element.Strategy.AnonAttribute,
 ]);
 
 const logger = Log.repository.getLogger("Marionette");
 const globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"]
     .getService(Ci.nsIMessageBroadcaster);
 
+/**
+ * The Marionette WebDriver services provides a standard conforming
+ * implementation of the W3C WebDriver specification.
+ *
+ * @see {@link https://w3c.github.io/webdriver/webdriver-spec.html}
+ * @namespace driver
+ */
+
 // This is used to prevent newSession from returning before the telephony
 // API's are ready; see bug 792647.  This assumes that marionette-server.js
 // will be loaded before the 'system-message-listener-ready' message
 // is fired.  If this stops being true, this approach will have to change.
 var systemMessageListenerReady = false;
 Services.obs.addObserver(function() {
   systemMessageListenerReady = true;
 }, "system-message-listener-ready");
 
+/**
+ * @enum
+ * @memberof driver
+ */
 this.Context = {
   CHROME: "chrome",
   CONTENT: "content",
 };
 
+/** @memberof driver */
 this.Context.fromString = function(s) {
   s = s.toUpperCase();
   if (s in this) {
     return this[s];
   }
   return null;
 };
 
 /**
-* Helper function for converting an nsISimpleEnumerator to
-* a javascript iterator
-* @param{nsISimpleEnumerator} enumerator
-*    enumerator to convert
-*/
+ * Helper function for converting a {@link nsISimpleEnumerator} to a
+ * JavaScript iterator.
+ *
+ * @memberof driver
+ *
+ * @param {nsISimpleEnumerator} enumerator
+ *     Enumerator to turn into  iterator.
+ *
+ * @return {Iterable}
+ *     Iterator.
+ */
 function* enumeratorIterator(enumerator) {
   while (enumerator.hasMoreElements()) {
     yield enumerator.getNext();
   }
 }
 
 /**
  * Implements (parts of) the W3C WebDriver protocol.  GeckoDriver lives
  * in chrome space and mediates calls to the message listener of the current
  * browsing context's content frame message listener via ListenerProxy.
  *
- * Throughout this prototype, functions with the argument {@code cmd}'s
- * documentation refers to the contents of the {@code cmd.parameters}
+ * Throughout this prototype, functions with the argument <var>cmd</var>'s
+ * documentation refers to the contents of the <code>cmd.parameter</code>}
  * object.
  *
+ * @class GeckoDriver
+ *
  * @param {string} appName
  *     Description of the product, for example "Firefox".
  * @param {MarionetteServer} server
  *     The instance of Marionette server.
  */
 this.GeckoDriver = function(appName, server) {
   this.appName = appName;
   this._server = server;
@@ -313,17 +334,17 @@ GeckoDriver.prototype.switchToGlobalMess
 /**
  * Helper method to send async messages to the content listener.
  * Correct usage is to pass in the name of a function in listener.js,
  * a serialisable object, and optionally the current command's ID
  * when not using the modern dispatching technique.
  *
  * @param {string} name
  *     Suffix of the targetted message listener
- *     ({@code Marionette:<suffix>}).
+ *     <tt>Marionette:SUFFIX</tt>.
  * @param {Object=} msg
  *     Optional JSON serialisable object to send to the listener.
  * @param {number=} commandID
  *     Optional command ID to ensure synchronisity.
  */
 GeckoDriver.prototype.sendAsync = function(name, data, commandID) {
   name = "Marionette:" + name;
   let payload = copy(data);
@@ -371,19 +392,19 @@ GeckoDriver.prototype.sendTargettedAsync
         throw new WebDriverError(e);
     }
   }
 };
 
 /**
  * Get the session's current top-level browsing context.
  *
- * It will return the outer {@ChromeWindow} previously selected by window
- * handle through {@code #switchToWindow}, or the first window that was
- * registered.
+ * It will return the outer {@link ChromeWindow} previously selected by
+ * window handle through {@link #switchToWindow}, or the first window that
+ * was registered.
  *
  * @param {Context=} forcedContext
  *     Optional name of the context to use for finding the window.
  *     It will be required if a command always needs a specific context,
  *     whether which context is currently set. Defaults to the current
  *     context.
  *
  * @return {ChromeWindow}
@@ -460,17 +481,17 @@ GeckoDriver.prototype.addBrowser = funct
  * Registers a new browser, win, with Marionette.
  *
  * If we have not seen the browser content window before, the listener
  * frame script will be loaded into it.  If isNewSession is true, we will
  * switch focus to the start frame when it registers.
  *
  * @param {nsIDOMWindow} win
  *     Window whose browser we need to access.
- * @param {boolean=false} isNewSession
+ * @param {boolean=} [false] isNewSession
  *     True if this is the first time we're talking to this browser.
  */
 GeckoDriver.prototype.startBrowser = function(win, isNewSession = false) {
   this.mainFrame = win;
   this.curFrame = null;
   this.addBrowser(win);
   this.curBrowser.isNewSession = isNewSession;
   this.whenBrowserStarted(win, isNewSession);
@@ -771,146 +792,148 @@ GeckoDriver.prototype.getContext = funct
   resp.body.value = this.context.toString();
 };
 
 /**
  * Executes a JavaScript function in the context of the current browsing
  * context, if in content space, or in chrome space otherwise, and returns
  * the return value of the function.
  *
- * It is important to note that if the {@code sandboxName} parameter
+ * It is important to note that if the <var>sandboxName</var> parameter
  * is left undefined, the script will be evaluated in a mutable sandbox,
  * causing any change it makes on the global state of the document to have
  * lasting side-effects.
  *
  * @param {string} script
  *     Script to evaluate as a function body.
  * @param {Array.<(string|boolean|number|object|WebElement)>} args
- *     Arguments exposed to the script in {@code arguments}.  The array
- *     items must be serialisable to the WebDriver protocol.
+ *     Arguments exposed to the script in <code>arguments</code>.
+ *     The array items must be serialisable to the WebDriver protocol.
  * @param {number} scriptTimeout
  *     Duration in milliseconds of when to interrupt and abort the
  *     script evaluation.
  * @param {string=} sandbox
  *     Name of the sandbox to evaluate the script in.  The sandbox is
  *     cached for later re-use on the same Window object if
- *     {@code newSandbox} is false.  If he parameter is undefined,
+ *     <var>newSandbox</var> is false.  If he parameter is undefined,
  *     the script is evaluated in a mutable sandbox.  If the parameter
  *     is "system", it will be evaluted in a sandbox with elevated system
  *     privileges, equivalent to chrome space.
  * @param {boolean=} newSandbox
  *     Forces the script to be evaluated in a fresh sandbox.  Note that if
  *     it is undefined, the script will normally be evaluted in a fresh
  *     sandbox.
  * @param {string=} filename
  *     Filename of the client's program where this script is evaluated.
  * @param {number=} line
  *     Line in the client's program where this script is evaluated.
  * @param {boolean=} debug_script
- *     Attach an {@code onerror} event handler on the Window object.
- *     It does not differentiate content errors from chrome errors.
+ *     Attach an <code>onerror</code> event handler on the {@link Window}
+ *     object.  It does not differentiate content errors from chrome errors.
  * @param {boolean=} directInject
  *     Evaluate the script without wrapping it in a function.
  *
  * @return {(string|boolean|number|object|WebElement)}
  *     Return value from the script, or null which signifies either the
  *     JavaScript notion of null or undefined.
  *
- * @throws ScriptTimeoutError
- *     If the script was interrupted due to reaching the {@code
- *     scriptTimeout} or default timeout.
- * @throws JavaScriptError
- *     If an Error was thrown whilst evaluating the script.
+ * @throws {ScriptTimeoutError}
+ *     If the script was interrupted due to reaching the
+ *     <var>scriptTimeout</var> or default timeout.
+ * @throws {JavaScriptError}
+ *     If an {@link Error} was thrown whilst evaluating the script.
  */
 GeckoDriver.prototype.executeScript = function*(cmd, resp) {
   assert.window(this.getCurrentWindow());
 
   let {script, args, scriptTimeout} = cmd.parameters;
   scriptTimeout = scriptTimeout || this.timeouts.script;
 
   let opts = {
     sandboxName: cmd.parameters.sandbox,
     newSandbox: !!(typeof cmd.parameters.newSandbox == "undefined") ||
         cmd.parameters.newSandbox,
-    filename: cmd.parameters.filename,
+    file: cmd.parameters.filename,
     line: cmd.parameters.line,
     debug: cmd.parameters.debug_script,
   };
 
   resp.body.value = yield this.execute_(script, args, scriptTimeout, opts);
 };
 
 /**
  * Executes a JavaScript function in the context of the current browsing
  * context, if in content space, or in chrome space otherwise, and returns
  * the object passed to the callback.
  *
- * The callback is always the last argument to the {@code arguments}
+ * The callback is always the last argument to the <var>arguments</var>
  * list passed to the function scope of the script.  It can be retrieved
  * as such:
  *
+ * <pre><code>
  *     let callback = arguments[arguments.length - 1];
  *     callback("foo");
  *     // "foo" is returned
+ * </code></pre>
  *
- * It is important to note that if the {@code sandboxName} parameter
+ * It is important to note that if the <var>sandboxName</var> parameter
  * is left undefined, the script will be evaluated in a mutable sandbox,
  * causing any change it makes on the global state of the document to have
  * lasting side-effects.
  *
  * @param {string} script
  *     Script to evaluate as a function body.
  * @param {Array.<(string|boolean|number|object|WebElement)>} args
- *     Arguments exposed to the script in {@code arguments}.  The array
- *     items must be serialisable to the WebDriver protocol.
+ *     Arguments exposed to the script in <code>arguments</code>.
+ *     The array items must be serialisable to the WebDriver protocol.
  * @param {number} scriptTimeout
  *     Duration in milliseconds of when to interrupt and abort the
  *     script evaluation.
  * @param {string=} sandbox
  *     Name of the sandbox to evaluate the script in.  The sandbox is
  *     cached for later re-use on the same Window object if
- *     {@code newSandbox} is false.  If the parameter is undefined,
+ *     <var>newSandbox</var> is false.  If the parameter is undefined,
  *     the script is evaluated in a mutable sandbox.  If the parameter
  *     is "system", it will be evaluted in a sandbox with elevated system
  *     privileges, equivalent to chrome space.
  * @param {boolean=} newSandbox
  *     Forces the script to be evaluated in a fresh sandbox.  Note that if
  *     it is undefined, the script will normally be evaluted in a fresh
  *     sandbox.
  * @param {string=} filename
  *     Filename of the client's program where this script is evaluated.
  * @param {number=} line
  *     Line in the client's program where this script is evaluated.
  * @param {boolean=} debug_script
- *     Attach an {@code onerror} event handler on the Window object.
- *     It does not differentiate content errors from chrome errors.
+ *     Attach an <code>onerror</code> event handler on the {@link Window}
+ *     object.  It does not differentiate content errors from chrome errors.
  * @param {boolean=} directInject
  *     Evaluate the script without wrapping it in a function.
  *
  * @return {(string|boolean|number|object|WebElement)}
  *     Return value from the script, or null which signifies either the
  *     JavaScript notion of null or undefined.
  *
- * @throws ScriptTimeoutError
- *     If the script was interrupted due to reaching the {@code
- *     scriptTimeout} or default timeout.
- * @throws JavaScriptError
+ * @throws {ScriptTimeoutError}
+ *     If the script was interrupted due to reaching the
+ *     <var>scriptTimeout</var> or default timeout.
+ * @throws {JavaScriptError}
  *     If an Error was thrown whilst evaluating the script.
  */
 GeckoDriver.prototype.executeAsyncScript = function* (cmd, resp) {
   assert.window(this.getCurrentWindow());
 
   let {script, args, scriptTimeout} = cmd.parameters;
   scriptTimeout = scriptTimeout || this.timeouts.script;
 
   let opts = {
     sandboxName: cmd.parameters.sandbox,
     newSandbox: !!(typeof cmd.parameters.newSandbox == "undefined") ||
         cmd.parameters.newSandbox,
-    filename: cmd.parameters.filename,
+    file: cmd.parameters.filename,
     line: cmd.parameters.line,
     debug: cmd.parameters.debug_script,
     async: true,
   };
 
   resp.body.value = yield this.execute_(script, args, scriptTimeout, opts);
 };
 
@@ -2500,18 +2523,18 @@ GeckoDriver.prototype.switchToShadowRoot
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  * @throws {InvalidCookieDomainError}
- *     If |cookie| is for a different domain than the active document's
- *     host.
+ *     If <var>cookie</var> is for a different domain than the active
+ *     document's host.
  */
 GeckoDriver.prototype.addCookie = function(cmd, resp) {
   assert.content(this.context);
   assert.window(this.getCurrentWindow());
   assert.noUserPrompt(this.dialog);
 
   let {protocol, hostname} = this.currentURL;
 
@@ -2526,18 +2549,18 @@ GeckoDriver.prototype.addCookie = functi
   }
 
   cookie.add(newCookie, {restrictToHost: hostname});
 };
 
 /**
  * Get all the cookies for the current domain.
  *
- * This is the equivalent of calling {@code document.cookie} and parsing
- * the result.
+ * This is the equivalent of calling <code>document.cookie</code> and
+ * parsing the result.
  *
  * @throws {UnsupportedOperationError}
  *     Not available in current context.
  * @throws {NoSuchWindowError}
  *     Top-level browsing context has been discarded.
  * @throws {UnexpectedAlertOpenError}
  *     A modal dialog is open, blocking this operation.
  */
@@ -2756,27 +2779,27 @@ GeckoDriver.prototype.deleteSession = fu
  *
  * @param {string=} id
  *     Optional web element reference to take a screenshot of.
  *     If undefined, a screenshot will be taken of the document element.
  * @param {Array.<string>=} highlights
  *     List of web elements to highlight.
  * @param {boolean} full
  *     True to take a screenshot of the entire document element. Is not
- *     considered if {@code id} is not defined. Defaults to true.
+ *     considered if <var>id</var> is not defined. Defaults to true.
  * @param {boolean=} hash
  *     True if the user requests a hash of the image data.
  * @param {boolean=} scroll
  *     Scroll to element if |id| is provided.  If undefined, it will
  *     scroll to the element.
  *
  * @return {string}
- *     If |hash| is false, PNG image encoded as Base64 encoded string.
- *     If |hash| is True, hex digest of the SHA-256 hash of the base64
- *     encoded string.
+ *     If <var>hash</var> is false, PNG image encoded as Base64 encoded
+ *     string.  If <var>hash</var> is true, hex digest of the SHA-256
+ *     hash of the Base64 encoded string.
  */
 GeckoDriver.prototype.takeScreenshot = function(cmd, resp) {
   let win = assert.window(this.getCurrentWindow());
 
   let {id, highlights, full, hash} = cmd.parameters;
   highlights = highlights || [];
   let format = hash ? capture.Format.Hash : capture.Format.Base64;
 
@@ -3045,17 +3068,17 @@ GeckoDriver.prototype.acceptConnections 
 }
 
 /**
  * Quits the application with the provided flags.
  *
  * Marionette will stop accepting new connections before ending the
  * current session, and finally attempting to quit the application.
  *
- * Optional {@code nsIAppStartup} flags may be provided as
+ * Optional {@link nsIAppStartup} flags may be provided as
  * an array of masks, and these will be combined by ORing
  * them with a bitmask.  The available masks are defined in
  * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIAppStartup.
  *
  * Crucially, only one of the *Quit flags can be specified. The |eRestart|
  * flag may be bit-wise combined with one of the *Quit flags to cause
  * the application to restart after it quits.
  *
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -17,41 +17,42 @@ const {
   JavaScriptError,
   NoSuchElementError,
   StaleElementReferenceError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 Cu.import("chrome://marionette/content/wait.js");
 
 const logger = Log.repository.getLogger("Marionette");
 
+this.EXPORTED_SYMBOLS = ["element"];
+
+const DOCUMENT_POSITION_DISCONNECTED = 1;
+const XMLNS = "http://www.w3.org/1999/xhtml";
+
+const uuidGen = Cc["@mozilla.org/uuid-generator;1"]
+    .getService(Ci.nsIUUIDGenerator);
+
 /**
  * This module provides shared functionality for dealing with DOM-
  * and web elements in Marionette.
  *
  * A web element is an abstraction used to identify an element when it
  * is transported across the protocol, between remote- and local ends.
  *
  * Each element has an associated web element reference (a UUID) that
  * uniquely identifies the the element across all browsing contexts. The
  * web element reference for every element representing the same element
  * is the same.
  *
- * The @code{element.Store} provides a mapping between web element
+ * The {@link element.Store} provides a mapping between web element
  * references and DOM elements for each browsing context.  It also provides
  * functionality for looking up and retrieving elements.
+ *
+ * @namespace
  */
-
-this.EXPORTED_SYMBOLS = ["element"];
-
-const DOCUMENT_POSITION_DISCONNECTED = 1;
-const XMLNS = "http://www.w3.org/1999/xhtml";
-
-const uuidGen = Cc["@mozilla.org/uuid-generator;1"]
-    .getService(Ci.nsIUUIDGenerator);
-
 this.element = {};
 
 element.Key = "element-6066-11e4-a52e-4f735466cecf";
 element.LegacyKey = "ELEMENT";
 
 element.Strategy = {
   ClassName: "class name",
   Selector: "css selector",
@@ -66,16 +67,19 @@ element.Strategy = {
 };
 
 /**
  * Stores known/seen elements and their associated web element
  * references.
  *
  * Elements are added by calling |add(el)| or |addAll(elements)|, and
  * may be queried by their web element reference using |get(element)|.
+ *
+ * @class
+ * @memberof element
  */
 element.Store = class {
   constructor() {
     this.els = {};
     this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   }
 
   clear() {
@@ -231,17 +235,17 @@ element.Store = class {
  * @param {string} strategy
  *     Search strategy whereby to locate the element(s).
  * @param {string} selector
  *     Selector search pattern.  The selector must be compatible with
  *     the chosen search |strategy|.
  * @param {Object.<string, ?>} opts
  *     Options.
  *
- * @return {Promise: (nsIDOMElement|Array<nsIDOMElement>)}
+ * @return {Promise.<(nsIDOMElement|Array.<nsIDOMElement>)>}
  *     Single element or a sequence of elements.
  *
  * @throws InvalidSelectorError
  *     If |strategy| is unknown.
  * @throws InvalidSelectorError
  *     If |selector| is malformed.
  * @throws NoSuchElementError
  *     If a single element is requested, this error will throw if the
@@ -607,17 +611,17 @@ element.makeWebElement = function(uuid) 
     [element.LegacyKey]: uuid,
   };
 };
 
 /**
  * Checks if |ref| has either |element.Key| or |element.LegacyKey|
  * as properties.
  *
- * @param {?} ref
+ * @param {Object.<string, string>} ref
  *     Object that represents a web element reference.
  * @return {boolean}
  *     True if |ref| has either expected property.
  */
 element.isWebElementReference = function(ref) {
   let properties = Object.getOwnPropertyNames(ref);
   return properties.includes(element.Key) ||
       properties.includes(element.LegacyKey);
--- a/testing/marionette/error.js
+++ b/testing/marionette/error.js
@@ -42,16 +42,17 @@ const BUILTIN_ERRORS = new Set([
   "ReferenceError",
   "SyntaxError",
   "TypeError",
   "URIError",
 ]);
 
 this.EXPORTED_SYMBOLS = ["error", "error.pprint"].concat(Array.from(ERRORS));
 
+/** @namespace */
 this.error = {};
 
 /**
  * Check if |val| is an instance of the |Error| prototype.
  *
  * Because error objects may originate from different globals, comparing
  * the prototype of the left hand side with the prototype property from
  * the right hand side, which is what |instanceof| does, will not work.
@@ -228,24 +229,38 @@ class WebDriverError extends Error {
     this.status = "webdriver error";
 
     // Error's ctor does not preserve x' stack
     if (error.isError(x)) {
       this.stack = x.stack;
     }
   }
 
+  /**
+   * @return {Object.<string, string>}
+   *     JSON serialisation of error prototype.
+   */
   toJSON() {
     return {
       error: this.status,
       message: this.message || "",
       stacktrace: this.stack || "",
     }
   }
 
+  /**
+   * Unmarshals a JSON error representation to the appropriate Marionette
+   * error type.
+   *
+   * @param {Object.<string, string>} json
+   *     Error object.
+   *
+   * @return {Error}
+   *     Error prototype.
+   */
   static fromJSON(json) {
     if (typeof json.error == "undefined") {
       let s = JSON.stringify(json);
       throw new TypeError("Undeserialisable error type: " + s);
     }
     if (!STATUSES.has(json.error)) {
       throw new TypeError("Not of WebDriverError descent: " + json.error);
     }
@@ -257,16 +272,17 @@ class WebDriverError extends Error {
     }
     if ("stacktrace" in json) {
       err.stack = json.stacktrace;
     }
     return err;
   }
 }
 
+/** The Gecko a11y API indicates that the element is not accessible. */
 class ElementNotAccessibleError extends WebDriverError {
   constructor(message) {
     super(message);
     this.status = "element not accessible";
   }
 }
 
 /**
@@ -305,30 +321,39 @@ class ElementClickInterceptedError exten
       }
     }
 
     super(msg);
     this.status = "element click intercepted";
   }
 }
 
+/**
+ * A command could not be completed because the element is not pointer-
+ * or keyboard interactable.
+ */
 class ElementNotInteractableError extends WebDriverError {
   constructor(message) {
     super(message);
     this.status = "element not interactable";
   }
 }
 
+/**
+ * Navigation caused the user agent to hit a certificate warning, which
+ * is usually the result of an expired or invalid TLS certificate.
+ */
 class InsecureCertificateError extends WebDriverError {
   constructor(message) {
     super(message);
     this.status = "insecure certificate";
   }
 }
 
+/** The arguments passed to a command are either invalid or malformed. */
 class InvalidArgumentError extends WebDriverError {
   constructor(message) {
     super(message);
     this.status = "invalid argument";
   }
 }
 
 class InvalidCookieDomainError extends WebDriverError {
--- a/testing/marionette/evaluate.js
+++ b/testing/marionette/evaluate.js
@@ -27,183 +27,185 @@ const ARGUMENTS = "__webDriverArguments"
 const CALLBACK = "__webDriverCallback";
 const COMPLETE = "__webDriverComplete";
 const DEFAULT_TIMEOUT = 10000; // ms
 const FINISH = "finish";
 const MARIONETTE_SCRIPT_FINISHED = "marionetteScriptFinished";
 const ELEMENT_KEY = "element";
 const W3C_ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf";
 
+/** @namespace */
 this.evaluate = {};
 
 /**
  * Evaluate a script in given sandbox.
  *
- * If the option {@code directInject} is not specified, the script will
- * be executed as a function with the {@code args} argument applied.
+ * If the option var>directInject</var> is not specified, the script
+ * will be executed as a function with the <var>args</var> argument
+ * applied.
  *
- * The arguments provided by the {@code args} argument are exposed through
- * the {@code arguments} object available in the script context, and if
- * the script is executed asynchronously with the {@code async}
- * option, an additional last argument that is synonymous to the
- * {@code marionetteScriptFinished} global is appended, and can be
- * accessed through {@code arguments[arguments.length - 1]}.
+ * The arguments provided by the <var>args</var> argument are exposed
+ * through the <code>arguments</code> object available in the script
+ * context, and if the script is executed asynchronously with the
+ * <var>async</var> option, an additional last argument that is synonymous
+ * to the <code>marionetteScriptFinished</code> global is appended, and
+ * can be accessed through <code>arguments[arguments.length - 1]</code>.
  *
- * The {@code timeout} option specifies the duration for how long the
- * script should be allowed to run before it is interrupted and aborted.
- * An interrupted script will cause a ScriptTimeoutError to occur.
+ * The <var>timeout</var> option specifies the duration for how long
+ * the script should be allowed to run before it is interrupted and aborted.
+ * An interrupted script will cause a {@link ScriptTimeoutError} to occur.
  *
- * The {@code async} option indicates that the script will not return
- * until the {@code marionetteScriptFinished} global callback is invoked,
- * which is analogous to the last argument of the {@code arguments}
- * object.
+ * The <var>async</var> option indicates that the script will
+ * not return until the <code>marionetteScriptFinished</code> global
+ * callback is invoked, which is analogous to the last argument of the
+ * <code>arguments</code> object.
  *
- * The option {@code directInject} causes the script to be evaluated
+ * The option <var>directInject</var> causes the script to be evaluated
  * without being wrapped in a function and the provided arguments will
  * be disregarded.  This will cause such things as root scope return
  * statements to throw errors because they are not used inside a function.
  *
- * The {@code filename} option is used in error messages to provide
+ * The <var>file</var> option is used in error messages to provide
  * information on the origin script file in the local end.
  *
- * The {@code line} option is used in error messages, along with
- * {@code filename}, to provide the line number in the origin script
+ * The <var>line</var> option is used in error messages, along with
+ * <var>filename</var>, to provide the line number in the origin script
  * file on the local end.
  *
- * @param {nsISandbox) sb
- *     The sandbox the script will be evaluted in.
+ * @param {nsISandbox} sb
+ *     Sandbox the script will be evaluted in.
  * @param {string} script
- *     The script to evaluate.
+ *     Script to evaluate.
  * @param {Array.<?>=} args
  *     A sequence of arguments to call the script with.
- * @param {Object.<string, ?>=} opts
- *     Dictionary of options:
- *
- *       async (boolean)
- *         Indicates if the script should return immediately or wait
- *         for the callback be invoked before returning.
- *       debug (boolean)
- *         Attaches an {@code onerror} event listener.
- *       directInject (boolean)
- *         Evaluates the script without wrapping it in a function.
- *       filename (string)
- *         File location of the program in the client.
- *       line (number)
- *         Line number of the program in the client.
- *       sandboxName (string)
- *         Name of the sandbox.  Elevated system privileges, equivalent
- *         to chrome space, will be given if it is "system".
- *       timeout (boolean)
- *         Duration in milliseconds before interrupting the script.
+ * @param {boolean=} [async=false] async
+ *     Indicates if the script should return immediately or wait for
+ *     the callback to be invoked before returning.
+ * @param {boolean=} [debug=false] debug
+ *     Attaches an <code>onerror</code> event listener.
+ * @param {string=} [file="dummy file"] file
+ *     File location of the program in the client.
+ * @param {number=} [line=0] line
+ *     Line number of th eprogram in the client.
+ * @param {string=} sandboxName
+ *     Name of the sandbox.  Elevated system privileges, equivalent to
+ *     chrome space, will be given if it is <tt>system</tt>.
+ * @param {number=} [timeout=DEFAULT_TIMEOUT] timeout
+ *     Duration in milliseconds before interrupting the script.
  *
  * @return {Promise}
  *     A promise that when resolved will give you the return value from
  *     the script.  Note that the return value requires serialisation before
  *     it can be sent to the client.
  *
  * @throws {JavaScriptError}
- *   If an Error was thrown whilst evaluating the script.
+ *   If an {@link Error} was thrown whilst evaluating the script.
  * @throws {ScriptTimeoutError}
  *   If the script was interrupted due to script timeout.
  */
-evaluate.sandbox = function(sb, script, args = [], opts = {}) {
+evaluate.sandbox = function(sb, script, args = [],
+    {
+      async = false,
+      debug = false,
+      directInject = false,
+      file = "dummy file",
+      line = 0,
+      sandboxName = null,
+      timeout = DEFAULT_TIMEOUT,
+    } = {}) {
   let scriptTimeoutID, timeoutHandler, unloadHandler;
 
   let promise = new Promise((resolve, reject) => {
     let src = "";
     sb[COMPLETE] = resolve;
     timeoutHandler = () => reject(new ScriptTimeoutError("Timed out"));
     unloadHandler = sandbox.cloneInto(
         () => reject(new JavaScriptError("Document was unloaded")),
         sb);
 
     // wrap in function
-    if (!opts.directInject) {
-      if (opts.async) {
+    if (!directInject) {
+      if (async) {
         sb[CALLBACK] = sb[COMPLETE];
       }
       sb[ARGUMENTS] = sandbox.cloneInto(args, sb);
 
       // callback function made private
       // so that introspection is possible
       // on the arguments object
-      if (opts.async) {
+      if (async) {
         sb[CALLBACK] = sb[COMPLETE];
         src += `${ARGUMENTS}.push(rv => ${CALLBACK}(rv));`;
       }
 
       src += `(function() { ${script} }).apply(null, ${ARGUMENTS})`;
 
       // marionetteScriptFinished is not WebDriver conformant,
       // hence it is only exposed to immutable sandboxes
-      if (opts.sandboxName) {
+      if (sandboxName) {
         sb[MARIONETTE_SCRIPT_FINISHED] = sb[CALLBACK];
       }
     }
 
     // onerror is not hooked on by default because of the inability to
     // differentiate content errors from chrome errors.
     //
     // see bug 1128760 for more details
-    if (opts.debug) {
+    if (debug) {
       sb.window.onerror = (msg, url, line) => {
         let err = new JavaScriptError(`${msg} at ${url}:${line}`);
         reject(err);
       };
     }
 
     // timeout and unload handlers
-    const timeout = opts.timeout || DEFAULT_TIMEOUT;
     scriptTimeoutID = setTimeout(timeoutHandler, timeout);
     sb.window.onunload = unloadHandler;
 
-    const file = opts.filename || "dummy file";
-    const line = opts.line || 0;
-
     let res;
     try {
       res = Cu.evalInSandbox(src, sb, "1.8", file, 0);
     } catch (e) {
       let err = new JavaScriptError(e, {
         fnName: "execute_script",
         file,
         line,
         script,
       });
       reject(err);
     }
 
-    if (!opts.async) {
+    if (!async) {
       resolve(res);
     }
   });
 
   return promise.then(res => {
     clearTimeout(scriptTimeoutID);
     sb.window.removeEventListener("unload", unloadHandler);
     return res;
   });
 };
 
 /**
  * Convert any web elements in arbitrary objects to DOM elements by
  * looking them up in the seen element store.
  *
- * @param {?} obj
+ * @param {Object} obj
  *     Arbitrary object containing web elements.
  * @param {element.Store} seenEls
  *     Element store to use for lookup of web element references.
  * @param {Window} win
  *     Window.
  * @param {ShadowRoot} shadowRoot
  *     Shadow root.
  *
- * @return {?}
- *     Same object as provided by |obj| with the web elements replaced
- *     by DOM elements.
+ * @return {Object}
+ *     Same object as provided by <var>obj</var> with the web elements
+ *     replaced by DOM elements.
  */
 evaluate.fromJSON = function(obj, seenEls, win, shadowRoot = undefined) {
   switch (typeof obj) {
     case "boolean":
     case "number":
     case "string":
     default:
       return obj;
@@ -241,24 +243,24 @@ evaluate.fromJSON = function(obj, seenEl
 
 /**
  * Convert arbitrary objects to JSON-safe primitives that can be
  * transported over the Marionette protocol.
  *
  * Any DOM elements are converted to web elements by looking them up
  * and/or adding them to the element store provided.
  *
- * @param {?} obj
+ * @param {Object} obj
  *     Object to be marshaled.
  * @param {element.Store} seenEls
  *     Element store to use for lookup of web element references.
  *
- * @return {?}
- *     Same object as provided by |obj| with the elements replaced by
- *     web elements.
+ * @return {Object}
+ *     Same object as provided by <var>obj</var> with the elements
+ *     replaced by web elements.
  */
 evaluate.toJSON = function(obj, seenEls) {
   const t = Object.prototype.toString.call(obj);
 
   // null
   if (t == "[object Undefined]" || t == "[object Null]") {
     return null;
 
@@ -299,23 +301,23 @@ evaluate.toJSON = function(obj, seenEls)
   return rv;
 };
 
 /**
  * Cu.isDeadWrapper does not return true for a dead sandbox that was
  * assosciated with and extension popup. This provides a way to still
  * test for a dead object.
  *
- * @param {?} obj
+ * @param {Object} obj
  *     A potentially dead object.
  * @param {string} prop
  *     Name of a property on the object.
  *
  * @returns {boolean}
- *     True if |obj| is dead, false otherwise.
+ *     True if <var>obj</var> is dead, false otherwise.
  */
 evaluate.isDead = function(obj, prop) {
   try {
     obj[prop];
   } catch (e) {
     if (e.message.includes("dead object")) {
       return true;
     }
@@ -326,32 +328,32 @@ evaluate.isDead = function(obj, prop) {
 
 this.sandbox = {};
 
 /**
  * Provides a safe way to take an object defined in a privileged scope and
  * create a structured clone of it in a less-privileged scope.  It returns
  * a reference to the clone.
  *
- * Unlike for |Components.utils.cloneInto|, |obj| may contain functions
- * and DOM elemnets.
+ * Unlike for {@link Components.utils.cloneInto}, <var>obj</var> may
+ * contain functions and DOM elemnets.
  */
 sandbox.cloneInto = function(obj, sb) {
   return Cu.cloneInto(obj, sb, {cloneFunctions: true, wrapReflectors: true});
 };
 
 /**
- * Augment given sandbox by an adapter that has an {@code exports}
+ * Augment given sandbox by an adapter that has an <code>exports</code>
  * map property, or a normal map, of function names and function
  * references.
  *
  * @param {Sandbox} sb
  *     The sandbox to augment.
  * @param {Object} adapter
- *     Object that holds an {@code exports} property, or a map, of
+ *     Object that holds an <code>exports</code> property, or a map, of
  *     function names and function references.
  *
  * @return {Sandbox}
  *     The augmented sandbox.
  */
 sandbox.augment = function(sb, adapter) {
   function* entries(obj) {
     for (let key of Object.keys(obj)) {
@@ -420,16 +422,18 @@ sandbox.createSimpleTest = function(wind
   sb[FINISH] = () => sb[COMPLETE](harness.generate_results());
   return sb;
 };
 
 /**
  * Sandbox storage.  When the user requests a sandbox by a specific name,
  * if one exists in the storage this will be used as long as its window
  * reference is still valid.
+ *
+ * @memberof evaluate
  */
 this.Sandboxes = class {
   /**
    * @param {function(): Window} windowFn
    *     A function that returns the references to the current Window
    *     object.
    */
   constructor(windowFn) {
@@ -445,17 +449,17 @@ this.Sandboxes = class {
    * Factory function for getting a sandbox by name, or failing that,
    * creating a new one.
    *
    * If the sandbox' window does not match the provided window, a new one
    * will be created.
    *
    * @param {string} name
    *     The name of the sandbox to get or create.
-   * @param {boolean} fresh
+   * @param {boolean=} [fresh=false] fresh
    *     Remove old sandbox by name first, if it exists.
    *
    * @return {Sandbox}
    *     A used or fresh sandbox.
    */
   get(name = "default", fresh = false) {
     let sb = this.boxes_.get(name);
     if (sb) {
@@ -469,15 +473,13 @@ this.Sandboxes = class {
       } else {
         sb = sandbox.create(this.window_);
       }
       this.boxes_.set(name, sb);
     }
     return sb;
   }
 
-  /**
-   * Clears cache of sandboxes.
-   */
+  /** Clears cache of sandboxes. */
   clear() {
     this.boxes_.clear();
   }
 };
--- a/testing/marionette/event.js
+++ b/testing/marionette/event.js
@@ -33,16 +33,19 @@ function getDOMWindowUtils(win) {
     win = window;
   }
 
   // this assumes we are operating in chrome space
   return win.QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIDOMWindowUtils);
 }
 
+/** @namespace */
+this.event = {};
+
 event.MouseEvents = {
   click: 0,
   dblclick: 1,
   mousedown: 2,
   mouseup: 3,
   mouseover: 4,
   mouseout: 5,
 };
@@ -1288,17 +1291,17 @@ event.sendKeyUp = function(keyToSend, mo
   delete modifiers.type;
 };
 
 /**
  * Synthesize a key event for a single key.
  *
  * @param {string} keyToSend
  *     Code point or normalized key value
- * @param {?} modifiers
+ * @param {Object.<string, boolean>} modifiers
  *     Object with properties used in KeyboardEvent (shiftkey, repeat, ...)
  *     as well as, the event |type| such as keydown. All properties
  *     are optional.
  * @param {Window=} window
  *     Window object.  If |window| is undefined, the event is synthesized
  *     in current window.
  */
 event.sendSingleKey = function(keyToSend, modifiers, window = undefined) {
--- a/testing/marionette/frame.js
+++ b/testing/marionette/frame.js
@@ -6,16 +6,17 @@
 
 const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 this.EXPORTED_SYMBOLS = ["frame"];
 
+/** @namespace */
 this.frame = {};
 
 const FRAME_SCRIPT = "chrome://marionette/content/listener.js";
 
 // list of OOP frames that has the frame script loaded
 var remoteFrames = [];
 
 /**
--- a/testing/marionette/interaction.js
+++ b/testing/marionette/interaction.js
@@ -18,19 +18,17 @@ const {
 } = Cu.import("chrome://marionette/content/error.js", {});
 Cu.import("chrome://marionette/content/element.js");
 Cu.import("chrome://marionette/content/event.js");
 
 Cu.importGlobalProperties(["File"]);
 
 this.EXPORTED_SYMBOLS = ["interaction"];
 
-/**
- * XUL elements that support disabled attribute.
- */
+/** XUL elements that support disabled attribute. */
 const DISABLED_ATTRIBUTE_SUPPORTED_XUL = new Set([
   "ARROWSCROLLBOX",
   "BUTTON",
   "CHECKBOX",
   "COLORPICKER",
   "COMMAND",
   "DATEPICKER",
   "DESCRIPTION",
@@ -55,100 +53,98 @@ const DISABLED_ATTRIBUTE_SUPPORTED_XUL =
   "TAB",
   "TABS",
   "TEXTBOX",
   "TIMEPICKER",
   "TOOLBARBUTTON",
   "TREE",
 ]);
 
-/**
- * XUL elements that support checked property.
- */
+/** XUL elements that support checked property. */
 const CHECKED_PROPERTY_SUPPORTED_XUL = new Set([
   "BUTTON",
   "CHECKBOX",
   "LISTITEM",
   "TOOLBARBUTTON",
 ]);
 
-/**
- * XUL elements that support selected property.
- */
+/** XUL elements that support selected property. */
 const SELECTED_PROPERTY_SUPPORTED_XUL = new Set([
   "LISTITEM",
   "MENU",
   "MENUITEM",
   "MENUSEPARATOR",
   "RADIO",
   "RICHLISTITEM",
   "TAB",
 ]);
 
 /**
- * Common form controls that user can change the value property interactively.
+ * Common form controls that user can change the value property
+ * interactively.
  */
 const COMMON_FORM_CONTROLS = new Set([
   "input",
   "textarea",
   "select",
 ]);
 
 /**
- * Input elements that do not fire "input" and "change" events when value
- * property changes.
+ * Input elements that do not fire <tt>input</tt> and <tt>change</tt>
+ * events when value property changes.
  */
 const INPUT_TYPES_NO_EVENT = new Set([
   "checkbox",
   "radio",
   "file",
   "hidden",
   "image",
   "reset",
   "button",
   "submit",
 ]);
 
+/** @namespace */
 this.interaction = {};
 
 /**
  * Interact with an element by clicking it.
  *
  * The element is scrolled into view before visibility- or interactability
  * checks are performed.
  *
- * Selenium-style visibility checks will be performed if |specCompat|
- * is false (default).  Otherwise pointer-interactability checks will be
- * performed.  If either of these fail an
- * {@code ElementNotInteractableError} is thrown.
+ * Selenium-style visibility checks will be performed
+ * if <var>specCompat</var> is false (default).  Otherwise
+ * pointer-interactability checks will be performed.  If either of these
+ * fail an {@link ElementNotInteractableError} is thrown.
  *
- * If |strict| is enabled (defaults to disabled), further accessibility
- * checks will be performed, and these may result in an
- * {@code ElementNotAccessibleError} being returned.
+ * If <var>strict</var> is enabled (defaults to disabled), further
+ * accessibility checks will be performed, and these may result in an
+ * {@link ElementNotAccessibleError} being returned.
  *
- * When |el| is not enabled, an {@code InvalidElementStateError}
+ * When <var>el</var> is not enabled, an {@link InvalidElementStateError}
  * is returned.
  *
- * @param {DOMElement|XULElement} el
+ * @param {(DOMElement|XULElement)} el
  *     Element to click.
- * @param {boolean=} strict
+ * @param {boolean=} [strict=false] strict
  *     Enforce strict accessibility tests.
- * @param {boolean=} specCompat
+ * @param {boolean=} [specCompat=false] specCompat
  *     Use WebDriver specification compatible interactability definition.
  *
  * @throws {ElementNotInteractableError}
  *     If either Selenium-style visibility check or
  *     pointer-interactability check fails.
  * @throws {ElementClickInterceptedError}
- *     If |el| is obscured by another element and a click would not hit,
- *     in |specCompat| mode.
+ *     If <var>el</var> is obscured by another element and a click would
+ *     not hit, in <var>specCompat</var> mode.
  * @throws {ElementNotAccessibleError}
- *     If |strict| is true and element is not accessible.
+ *     If <var>strict</var> is true and element is not accessible.
  * @throws {InvalidElementStateError}
- *     If |el| is not enabled.
+ *     If <var>el</var> is not enabled.
  */
 interaction.clickElement = function* (
     el, strict = false, specCompat = false) {
   const a11y = accessibility.get(strict);
   if (element.isXULElement(el)) {
     yield chromeClick(el, a11y);
   } else if (specCompat) {
     yield webdriverClickElement(el, a11y);
@@ -259,31 +255,34 @@ function* seleniumClickElement(el, a11y)
     let rects = el.getClientRects();
     let centre = element.getInViewCentrePoint(rects[0], win);
     let opts = {};
     event.synthesizeMouseAtPoint(centre.x, centre.y, opts, win);
   }
 }
 
 /**
- * Select <option> element in a <select> list.
+ * Select <tt>&lt;option&gt;</tt> element in a <tt>&lt;select&gt;</tt>
+ * list.
  *
  * Because the dropdown list of select elements are implemented using
  * native widget technology, our trusted synthesised events are not able
  * to reach them.  Dropdowns are instead handled mimicking DOM events,
  * which for obvious reasons is not ideal, but at the current point in
  * time considered to be good enough.
  *
  * @param {HTMLOptionElement} option
  *     Option element to select.
  *
- * @throws TypeError
- *     If |el| is a XUL element or not an <option> element.
- * @throws Error
- *     If unable to find |el|'s parent <select> element.
+ * @throws {TypeError}
+ *     If <var>el</var> is a XUL element or not an <tt>&lt;option&gt;</tt>
+ *     element.
+ * @throws {Error}
+ *     If unable to find <var>el</var>'s parent <tt>&lt;select&gt;</tt>
+ *     element.
  */
 interaction.selectOption = function(el) {
   if (element.isXULElement(el)) {
     throw new Error("XUL dropdowns not supported");
   }
   if (el.localName != "option") {
     throw new TypeError("Invalid elements");
   }
@@ -313,17 +312,18 @@ interaction.selectOption = function(el) 
  * If the document is unloaded during this request, the promise is
  * rejected.
  *
  * @param {Window} win
  *     Associated window.
  *
  * @return {Promise}
  *     Promise is accepted once event queue is flushed, or rejected if
- *     |win| has closed or been unloaded before the queue can be flushed.
+ *     <var>win</var> has closed or been unloaded before the queue can
+ *     be flushed.
  */
 interaction.flushEventLoop = function* (win) {
   return new Promise(resolve => {
     let handleEvent = event => {
       win.removeEventListener("beforeunload", this);
       resolve();
     };
 
@@ -333,20 +333,21 @@ interaction.flushEventLoop = function* (
     }
 
     win.addEventListener("beforeunload", handleEvent);
     win.requestAnimationFrame(handleEvent);
   });
 };
 
 /**
- * Appends |path| to an <input type=file>'s file list.
+ * Appends <var>path</var> to an <tt>&lt;input type=file&gt;</tt>'s
+ * file list.
  *
  * @param {HTMLInputElement} el
- *     An <input type=file> element.
+ *     An <tt>&lt;input type=file&gt;</tt> element.
  * @param {string} path
  *     Full path to file.
  */
 interaction.uploadFile = function* (el, path) {
   let file = yield File.createFromFileName(path).then(file => {
     return file;
   }, () => {
     return null;
@@ -377,18 +378,18 @@ interaction.uploadFile = function* (el, 
 /**
  * Sets a form element's value.
  *
  * @param {DOMElement} el
  *     An form element, e.g. input, textarea, etc.
  * @param {string} value
  *     The value to be set.
  *
- * @throws TypeError
- *     If |el| is not an supported form element.
+ * @throws {TypeError}
+ *     If <var>el</var> is not an supported form element.
  */
 interaction.setFormControlValue = function* (el, value) {
   if (!COMMON_FORM_CONTROLS.has(el.localName)) {
     throw new TypeError("This function is for form elements only");
   }
 
   el.value = value;
 
@@ -404,17 +405,17 @@ interaction.setFormControlValue = functi
  * Send keys to element.
  *
  * @param {DOMElement|XULElement} el
  *     Element to send key events to.
  * @param {Array.<string>} value
  *     Sequence of keystrokes to send to the element.
  * @param {boolean} ignoreVisibility
  *     Flag to enable or disable element visibility tests.
- * @param {boolean=} strict
+ * @param {boolean=} [strict=false] strict
  *     Enforce strict accessibility tests.
  */
 interaction.sendKeysToElement = function(
     el, value, ignoreVisibility, strict = false) {
   let win = getWindow(el);
   let a11y = accessibility.get(strict);
   return a11y.getAccessible(el, true).then(acc => {
     a11y.assertActionable(acc, el);
@@ -422,17 +423,17 @@ interaction.sendKeysToElement = function
   });
 };
 
 /**
  * Determine the element displayedness of an element.
  *
  * @param {DOMElement|XULElement} el
  *     Element to determine displayedness of.
- * @param {boolean=} strict
+ * @param {boolean=} [strict=false] strict
  *     Enforce strict accessibility tests.
  *
  * @return {boolean}
  *     True if element is displayed, false otherwise.
  */
 interaction.isElementDisplayed = function(el, strict = false) {
   let win = getWindow(el);
   let displayed = atom.isElementDisplayed(el, win);
@@ -479,17 +480,17 @@ interaction.isElementEnabled = function(
 /**
  * Determines if the referenced element is selected or not.
  *
  * This operation only makes sense on input elements of the Checkbox-
  * and Radio Button states, or option elements.
  *
  * @param {DOMElement|XULElement} el
  *     Element to test if is selected.
- * @param {boolean=} strict
+ * @param {boolean=} [strict=false] strict
  *     Enforce strict accessibility tests.
  *
  * @return {boolean}
  *     True if element is selected, false otherwise.
  */
 interaction.isElementSelected = function(el, strict = false) {
   let selected = true;
   let win = getWindow(el);
--- a/testing/marionette/l10n.js
+++ b/testing/marionette/l10n.js
@@ -23,16 +23,17 @@ Cu.import("resource://gre/modules/XPCOMU
 XPCOMUtils.defineLazyServiceGetter(
     this, "domParser", "@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
 
 const {NoSuchElementError} =
     Cu.import("chrome://marionette/content/error.js", {});
 
 this.EXPORTED_SYMBOLS = ["l10n"];
 
+/** @namespace */
 this.l10n = {};
 
 /**
  * Retrieve the localized string for the specified entity id.
  *
  * Example:
  *     localizeEntity(["chrome://global/locale/about.dtd"], "about.version")
  *
--- a/testing/marionette/legacyaction.js
+++ b/testing/marionette/legacyaction.js
@@ -13,16 +13,17 @@ Cu.import("chrome://marionette/content/e
 
 const CONTEXT_MENU_DELAY_PREF = "ui.click_hold_context_menus.delay";
 const DEFAULT_CONTEXT_MENU_DELAY = 750;  // ms
 
 this.EXPORTED_SYMBOLS = ["legacyaction"];
 
 const logger = Log.repository.getLogger("Marionette");
 
+/** @namespace */
 this.legacyaction = this.action = {};
 
 /**
  * Functionality for (single finger) action chains.
  */
 action.Chain = function (checkForInterrupted) {
   // for assigning unique ids to all touches
   this.nextTouchId = 1000;
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -710,31 +710,31 @@ function deleteSession(msg) {
 
 /**
  * Send asynchronous reply to chrome.
  *
  * @param {UUID} uuid
  *     Unique identifier of the request.
  * @param {AsyncContentSender.ResponseType} type
  *     Type of response.
- * @param {?=} data
+ * @param {*} [Object] data
  *     JSON serialisable object to accompany the message.  Defaults to
  *     an empty dictionary.
  */
 function sendToServer(uuid, data = undefined) {
   let channel = new proxy.AsyncMessageChannel(
       () => this,
       sendAsyncMessage.bind(this));
   channel.reply(uuid, data);
 }
 
 /**
  * Send asynchronous reply with value to chrome.
  *
- * @param {?} obj
+ * @param {Object} obj
  *     JSON serialisable object of arbitrary type and complexity.
  * @param {UUID} uuid
  *     Unique identifier of the request.
  */
 function sendResponse(obj, uuid) {
   sendToServer(uuid, obj);
 }
 
--- a/testing/marionette/message.js
+++ b/testing/marionette/message.js
@@ -16,33 +16,49 @@ this.EXPORTED_SYMBOLS = [
   "Command",
   "Message",
   "MessageOrigin",
   "Response",
 ];
 
 const logger = Log.repository.getLogger("Marionette");
 
+/**
+ * Messages may originate from either the server or the client.
+ * Because the remote protocol is full duplex, both endpoints may be the
+ * origin of both commands and responses.
+ *
+ * @enum
+ * @see {@link Message}
+ */
 const MessageOrigin = {
+  /** Indicates that the message originates from the client. */
   Client: 0,
+  /** Indicates that the message originates from the server. */
   Server: 1,
 };
 
+/**
+ * Representation of the packets transproted over the wire.
+ *
+ * @class
+ */
 this.Message = {};
 
 /**
  * Converts a data packet into a Command or Response type.
  *
  * @param {Array.<number, number, ?, ?>} data
  *     A four element array where the elements, in sequence, signifies
  *     message type, message ID, method name or error, and parameters
  *     or result.
  *
- * @return {(Command,Response)}
- *     Based on the message type, a Command or Response instance.
+ * @return {Message}
+ *     Based on the message type, a {@link Command} or {@link Response}
+ *     instance.
  *
  * @throws {TypeError}
  *     If the message type is not recognised.
  */
 Message.fromMsg = function(data) {
   switch (data[0]) {
     case Command.TYPE:
       return Command.fromMsg(data);
@@ -90,17 +106,17 @@ Message.fromMsg = function(data) {
  * are called when the client returns with a response.  These are
  * {@code function onerror({Object})}, {@code function onresult({Object})},
  * and {@code function onresult({Response})}.
  *
  * @param {number} msgId
  *     Message ID unique identifying this message.
  * @param {string} name
  *     Command name.
- * @param {Object<string, ?>} params
+ * @param {Object.<string, ?>} params
  *     Command parameters.
  */
 class Command {
   constructor(msgID, name, params = {}) {
     this.id = assert.integer(msgID);
     this.name = assert.string(name);
     this.parameters = assert.object(params);
 
@@ -185,32 +201,39 @@ const validator = {
  *
  * For example setting the {@code error} property on the body when
  * {@code value}, {@code sessionId}, or {@code capabilities} have been
  * set previously will cause an error.
  */
 const ResponseBody = () => new Proxy({}, validator);
 
 /**
+ * @callback ResponseCallback
+ *
+ * @param {Response} resp
+ *     Response to handle.
+ */
+
+/**
  * Represents the response returned from the remote end after execution
  * of its corresponding command.
  *
  * The response is a mutable object passed to each command for
  * modification through the available setters.  To send data in a response,
  * you modify the body property on the response.  The body property can
  * also be replaced completely.
  *
  * The response is sent implicitly by CommandProcessor when a command
  * has finished executing, and any modifications made subsequent to that
  * will have no effect.
  *
  * @param {number} msgID
  *     Message ID tied to the corresponding command request this is a
  *     response for.
- * @param {function(Response|Message)} respHandler
+ * @param {ResponseHandler} respHandler
  *     Function callback called on sending the response.
  */
 class Response {
   constructor(msgID, respHandler = () => {}) {
     this.id = assert.integer(msgID);
     this.respHandler_ = assert.callable(respHandler);
 
     this.error = null;
--- a/testing/marionette/modal.js
+++ b/testing/marionette/modal.js
@@ -9,18 +9,18 @@ const {utils: Cu} = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 
 this.EXPORTED_SYMBOLS = ["modal"];
 
 const COMMON_DIALOG = "chrome://global/content/commonDialog.xul";
 
 const isFirefox = () => Services.appinfo.name == "Firefox";
 
-this.modal = {};
-modal = {
+/** @namespace */
+this.modal = {
   COMMON_DIALOG_LOADED: "common-dialog-loaded",
   TABMODAL_DIALOG_LOADED: "tabmodal-dialog-loaded",
   handlers: {
     "common-dialog-loaded": new Set(),
     "tabmodal-dialog-loaded": new Set(),
   },
 };
 
--- a/testing/marionette/navigate.js
+++ b/testing/marionette/navigate.js
@@ -5,33 +5,34 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.importGlobalProperties(["URL"]);
 
 this.EXPORTED_SYMBOLS = ["navigate"];
 
+/** @namespace */
 this.navigate = {};
 
 /**
  * Determines if we expect to get a DOM load event (DOMContentLoaded)
- * on navigating to the |future| URL.
+ * on navigating to the <code>future</code> URL.
  *
  * @param {string} current
  *     URL the browser is currently visiting.
  * @param {string=} future
  *     Destination URL, if known.
  *
  * @return {boolean}
  *     Full page load would be expected if future is followed.
  *
  * @throws TypeError
- *     If |current| is not defined, or any of |current| or |future|
- *     are invalid URLs.
+ *     If <code>current</code> is not defined, or any of
+ *     <code>current</code> or <code>future</code>  are invalid URLs.
  */
 navigate.isLoadEventExpected = function(current, future = undefined) {
   // assume we will go somewhere exciting
   if (typeof current == "undefined") {
     throw TypeError("Expected at least one URL");
   }
 
   // Assume we will go somewhere exciting
--- a/testing/marionette/packets.js
+++ b/testing/marionette/packets.js
@@ -46,16 +46,18 @@ this.EXPORTED_SYMBOLS = ["RawPacket", "P
 
 // The transport's previous check ensured the header length did not
 // exceed 20 characters.  Here, we opt for the somewhat smaller, but still
 // large limit of 1 TiB.
 const PACKET_LENGTH_MAX = Math.pow(2, 40);
 
 /**
  * A generic Packet processing object (extended by two subtypes below).
+ *
+ * @class
  */
 function Packet(transport) {
   this._transport = transport;
   this._length = 0;
 }
 
 /**
  * Attempt to initialize a new Packet based on the incoming packet header
--- a/testing/marionette/proxy.js
+++ b/testing/marionette/proxy.js
@@ -28,16 +28,17 @@ var ownPriorityGetterTrap = {
   get: (obj, prop) => {
     if (obj.hasOwnProperty(prop)) {
       return obj[prop];
     }
     return (...args) => obj.send(prop, args);
   },
 };
 
+/** @namespace */
 this.proxy = {};
 
 /**
  * Creates a transparent interface between the chrome- and content
  * contexts.
  *
  * Calls to this object will be proxied via the message manager to a
  * content frame script, and responses are returend as promises.
@@ -217,31 +218,33 @@ proxy.AsyncMessageChannel = class {
   /**
    * Reply to an asynchronous request.
    *
    * Passing an WebDriverError prototype will cause the receiving channel
    * to throw this error.
    *
    * Usage:
    *
+   * <pre><code>
    *     let channel = proxy.AsyncMessageChannel(
    *         messageManager, sendAsyncMessage.bind(this));
    *
    *     // throws in requester:
    *     channel.reply(uuid, new WebDriverError());
    *
    *     // returns with value:
    *     channel.reply(uuid, "hello world!");
    *
    *     // returns with undefined:
    *     channel.reply(uuid);
+   * </pre></code>
    *
    * @param {UUID} uuid
    *     Unique identifier of the request.
-   * @param {?=} obj
+   * @param {*} obj
    *     Message data to reply with.
    */
   reply(uuid, obj = undefined) {
     // TODO(ato): Eventually the uuid will be hidden in the dispatcher
     // in listener, and passing it explicitly to this function will be
     // unnecessary.
     if (typeof obj == "undefined") {
       this.sendReply_(uuid, proxy.AsyncMessageChannel.ReplyType.Ok);
@@ -348,17 +351,17 @@ class AsyncChromeSender {
   }
 
   /**
    * Call registered function in chrome context.
    *
    * @param {string} name
    *     Function to call in the chrome, e.g. for "Marionette:foo", use
    *     "foo".
-   * @param {?} args
+   * @param {*} args
    *     Argument list to pass the function.  Must be JSON serialisable.
    *
    * @return {Promise}
    *     A promise that resolves to the value sent back.
    */
   send(name, args) {
     let uuid = uuidgen.generateUUID().toString();
 
--- a/testing/marionette/reftest.js
+++ b/testing/marionette/reftest.js
@@ -32,20 +32,26 @@ const STATUS = {
   PASS: "PASS",
   FAIL: "FAIL",
   ERROR: "ERROR",
   TIMEOUT: "TIMEOUT",
 };
 
 /**
  * Implements an fast runner for web-platform-tests format reftests
- * c.f. http://web-platform-tests.org/writing-tests/reftests.html
+ * c.f. http://web-platform-tests.org/writing-tests/reftests.html.
+ *
+ * @namespace
  */
-let reftest = {};
+this.reftest = {};
 
+/**
+ * @memberof reftest
+ * @class Runner
+ */
 reftest.Runner = class {
   constructor(driver) {
     this.driver = driver;
     this.canvasCache = new Map([[null, []]]);
     this.windowUtils = null;
     this.lastURL = null;
     this.remote = Preferences.get(PREF_E10S);
   }
--- a/testing/marionette/server.js
+++ b/testing/marionette/server.js
@@ -32,16 +32,18 @@ const {DebuggerTransport} =
 XPCOMUtils.defineLazyServiceGetter(
     this, "env", "@mozilla.org/process/environment;1", "nsIEnvironment");
 
 const logger = Log.repository.getLogger("Marionette");
 
 const {KeepWhenOffline, LoopbackOnly} = Ci.nsIServerSocket;
 
 this.EXPORTED_SYMBOLS = ["server"];
+
+/** @namespace */
 this.server = {};
 
 const PROTOCOL_VERSION = 3;
 
 const ENV_ENABLED = "MOZ_MARIONETTE";
 
 const PREF_CONTENT_LISTENER = "marionette.contentListener";
 const PREF_PORT = "marionette.port";
@@ -543,17 +545,17 @@ server.TCPConnection = class {
     }.bind(this));
 
     req.then(sendResponse, sendError).catch(error.report);
   }
 
   /**
    * Fail-safe creation of a new instance of |message.Response|.
    *
-   * @param {?} msgID
+   * @param {number} msgID
    *     Message ID to respond to.  If it is not a number, -1 is used.
    *
    * @return {message.Response}
    *     Response to the message with |msgID|.
    */
   createResponse(msgID) {
     if (typeof msgID != "number") {
       msgID = -1;
@@ -586,17 +588,17 @@ server.TCPConnection = class {
    * The message is sent over the debugger transport socket.
    *
    * The command ID is a unique identifier assigned to the client's request
    * that is used to distinguish the asynchronous responses.
    *
    * Whilst responses to commands are synchronous and must be sent in the
    * correct order.
    *
-   * @param {Command,Response} msg
+   * @param {Message} msg
    *     The command or response to send.
    */
   send(msg) {
     msg.origin = MessageOrigin.Server;
     if (msg instanceof Command) {
       this.commands_.set(msg.id, msg);
       this.sendToEmulator(msg);
     } else if (msg instanceof Response) {
@@ -615,30 +617,30 @@ server.TCPConnection = class {
   sendToClient(resp) {
     this.driver.responseCompleted();
     this.sendMessage(resp);
   }
 
   /**
    * Marshal message to the Marionette message format and send it.
    *
-   * @param {Command,Response} msg
+   * @param {Message} msg
    *     The message to send.
    */
   sendMessage(msg) {
     this.log_(msg);
     let payload = msg.toMsg();
     this.sendRaw(payload);
   }
 
   /**
    * Send the given payload over the debugger transport socket to the
    * connected client.
    *
-   * @param {Object} payload
+   * @param {Object.<string, ?>} payload
    *     The payload to ship.
    */
   sendRaw(payload) {
     this.conn.send(payload);
   }
 
   log_(msg) {
     let a = (msg.origin == MessageOrigin.Client ? " -> " : " <- ");
--- a/testing/marionette/session.js
+++ b/testing/marionette/session.js
@@ -22,32 +22,37 @@ const logger = Log.repository.getLogger(
 const {pprint} = error;
 
 // Enable testing this module, as Services.appinfo.* is not available
 // in xpcshell tests.
 const appinfo = {name: "<missing>", version: "<missing>"};
 try { appinfo.name = Services.appinfo.name.toLowerCase(); } catch (e) {}
 try { appinfo.version = Services.appinfo.version; } catch (e) {}
 
-/** State associated with a WebDriver session. */
+/**
+ * State associated with a WebDriver session.
+ *
+ * @namespace
+ */
 this.session = {};
 
 /** Representation of WebDriver session timeouts. */
 session.Timeouts = class {
   constructor() {
     // disabled
     this.implicit = 0;
     // five mintues
     this.pageLoad = 300000;
     // 30 seconds
     this.script = 30000;
   }
 
   toString() { return "[object session.Timeouts]"; }
 
+  /** Marshals timeout durations to a JSON Object. */
   toJSON() {
     return {
       implicit: this.implicit,
       pageLoad: this.pageLoad,
       script: this.script,
     };
   }
 
@@ -73,25 +78,39 @@ session.Timeouts = class {
           throw new InvalidArgumentError("Unrecognised timeout: " + typ);
       }
     }
 
     return t;
   }
 };
 
-/** Enum of page loading strategies. */
+/**
+ * Enum of page loading strategies.
+ *
+ * @enum
+ */
 session.PageLoadStrategy = {
+  /** No page load strategy.  Navigation will return immediately. */
   None: "none",
+  /**
+   * Eager, causing navigation to complete when the document reaches
+   * the <code>interactive</code> ready state.
+   */
   Eager: "eager",
+  /**
+   * Normal, causing navigation to return when the document reaches the
+   * <code>complete</code> ready state.
+   */
   Normal: "normal",
 };
 
 /** Proxy configuration object representation. */
 session.Proxy = class {
+  /** @class */
   constructor() {
     this.proxyType = null;
     this.httpProxy = null;
     this.httpProxyPort = null;
     this.sslProxy = null;
     this.sslProxyPort = null;
     this.ftpProxy = null;
     this.ftpProxyPort = null;
@@ -154,32 +173,40 @@ session.Proxy = class {
 
       default:
         return false;
     }
   }
 
   toString() { return "[object session.Proxy]"; }
 
+  /**
+   * @return {Object.<string, (number|string)>}
+   *     JSON serialisation of proxy object.
+   */
   toJSON() {
     return marshal({
       proxyType: this.proxyType,
       httpProxy: this.httpProxy,
       httpProxyPort: this.httpProxyPort,
       sslProxy: this.sslProxy,
       sslProxyPort: this.sslProxyPort,
       ftpProxy: this.ftpProxy,
       ftpProxyPort: this.ftpProxyPort,
       socksProxy: this.socksProxy,
       socksProxyPort: this.socksProxyPort,
       socksProxyVersion: this.socksProxyVersion,
       proxyAutoconfigUrl: this.proxyAutoconfigUrl,
     });
   }
 
+  /**
+   * @param {Object.<string, ?>} json
+   *     JSON Object to unmarshal.
+   */
   static fromJSON(json) {
     let p = new session.Proxy();
     if (typeof json == "undefined" || json === null) {
       return p;
     }
 
     assert.object(json);
 
@@ -214,16 +241,17 @@ session.Proxy = class {
     }
 
     return p;
   }
 };
 
 /** WebDriver session capabilities representation. */
 session.Capabilities = class extends Map {
+  /** @class */
   constructor() {
     super([
       // webdriver
       ["browserName", appinfo.name],
       ["browserVersion", appinfo.version],
       ["platformName", Services.sysinfo.getProperty("name").toLowerCase()],
       ["platformVersion", Services.sysinfo.getProperty("version")],
       ["pageLoadStrategy", session.PageLoadStrategy.Normal],
@@ -237,43 +265,55 @@ session.Capabilities = class extends Map
       // proprietary
       ["specificationLevel", 0],
       ["moz:processID", Services.appinfo.processID],
       ["moz:profile", maybeProfile()],
       ["moz:accessibilityChecks", false],
     ]);
   }
 
+  /**
+   * @param {string} key
+   *     Capability name.
+   * @param {(string|number|boolean)} value
+   *     JSON-safe capability value.
+   */
   set(key, value) {
     if (key === "timeouts" && !(value instanceof session.Timeouts)) {
       throw new TypeError();
     } else if (key === "proxy" && !(value instanceof session.Proxy)) {
       throw new TypeError();
     }
 
     return super.set(key, value);
   }
 
+  /** @return {string} */
   toString() { return "[object session.Capabilities]"; }
 
+  /**
+   * JSON serialisation of capabilities object.
+   *
+   * @return {Object.<string, ?>}
+   */
   toJSON() {
     return marshal(this);
   }
 
   /**
    * Unmarshal a JSON object representation of WebDriver capabilities.
    *
    * @param {Object.<string, ?>=} json
    *     WebDriver capabilities.
    * @param {boolean=} merge
-   *     If providing |json| with |desiredCapabilities| or
-   *     |requiredCapabilities| fields, or both, it should be set to
-   *     true to merge these before parsing.  This indicates
-   *     that the input provided is from a client and not from
-   *     |session.Capabilities#toJSON|.
+   *     If providing <var>json</var> with <tt>desiredCapabilities</tt> or
+   *     <tt>requiredCapabilities</tt> fields, or both, it should be
+   *     set to true to merge these before parsing.  This indicates that
+   *     the input provided is from a client and not from
+   *     {@link session.Capabilities#toJSON}.
    *
    * @return {session.Capabilities}
    *     Internal representation of WebDriver capabilities.
    */
   static fromJSON(json, {merge = false} = {}) {
     if (typeof json == "undefined" || json === null) {
       json = {};
     }
--- a/testing/marionette/stream-utils.js
+++ b/testing/marionette/stream-utils.js
@@ -54,16 +54,17 @@ const BUFFER_SIZE = 0x8000;
  *     Promise is resolved when copying completes or rejected if any
  *     (unexpected) errors occur.
  */
 function copyStream(input, output, length) {
   let copier = new StreamCopier(input, output, length);
   return copier.copy();
 }
 
+/** @class */
 function StreamCopier(input, output, length) {
   EventEmitter.decorate(this);
   this._id = StreamCopier._nextId++;
   this.input = input;
   // Save off the base output stream, since we know it's async as we've
   // required
   this.baseAsyncOutput = output;
   if (IOUtil.outputStreamIsBuffered(output)) {
@@ -191,36 +192,35 @@ StreamCopier.prototype = {
   },
 
   _debug(msg) {
   },
 
 };
 
 /**
- * Read from a stream, one byte at a time, up to the next |delimiter|
- * character, but stopping if we've read |count| without finding it.
- * Reading also terminates early if there are less than |count| bytes
- * available on the stream.  In that case, we only read as many bytes as
- * the stream currently has to offer.
- *
- * TODO: This implementation could be removed if bug 984651 is fixed,
- * which provides a native version of the same idea.
+ * Read from a stream, one byte at a time, up to the next
+ * <var>delimiter</var> character, but stopping if we've read |count|
+ * without finding it.  Reading also terminates early if there are less
+ * than <var>count</var> bytes available on the stream.  In that case,
+ * we only read as many bytes as the stream currently has to offer.
  *
  * @param {nsIInputStream} stream
  *     Input stream to read from.
  * @param {string} delimiter
  *     Character we're trying to find.
  * @param {number} count
  *     Max number of characters to read while searching.
  *
  * @return {string}
  *     Collected data.  If the delimiter was found, this string will
  *     end with it.
  */
+// TODO: This implementation could be removed if bug 984651 is fixed,
+// which provides a native version of the same idea.
 function delimitedRead(stream, delimiter, count) {
   let scriptableStream;
   if (stream instanceof Ci.nsIScriptableInputStream) {
     scriptableStream = stream;
   } else {
     scriptableStream = new ScriptableInputStream(stream);
   }
 
--- a/testing/marionette/transport.js
+++ b/testing/marionette/transport.js
@@ -100,16 +100,18 @@ const PACKET_HEADER_MAX = 200;
  *                 copied.  See stream-utils.js.
  *
  * - onClosed(reason) - called when the connection is closed. |reason|
  *   is an optional nsresult or object, typically passed when the
  *   transport is closed due to some error in a underlying stream.
  *
  * See ./packets.js and the Remote Debugging Protocol specification for
  * more details on the format of these packets.
+ *
+ * @class
  */
 function DebuggerTransport(input, output) {
   EventEmitter.decorate(this);
 
   this._input = input;
   this._scriptableInput = new ScriptableInputStream(input);
   this._output = output;
 
@@ -712,25 +714,26 @@ LocalDebuggerTransport.prototype = {
     }
   },
 };
 
 /**
  * A transport for the debugging protocol that uses nsIMessageManagers to
  * exchange packets with servers running in child processes.
  *
- * In the parent process, |mm| should be the nsIMessageSender for the
- * child process. In a child process, |mm| should be the child process
- * message manager, which sends packets to the parent.
+ * In the parent process, <var>mm</var> should be the nsIMessageSender
+ * for the child process. In a child process, |mm| should be the child
+ * process message manager, which sends packets to the parent.
  *
- * |prefix| is a string included in the message names, to distinguish
- * multiple servers running in the same child process.
+ * <var>prefix</var> is a string included in the message names, to
+ * distinguish multiple servers running in the same child process.
  *
- * This transport exchanges messages named 'debug:<prefix>:packet', where
- * <prefix> is |prefix|, whose data is the protocol packet.
+ * This transport exchanges messages named <tt>debug:PREFIX:packet</tt>,
+ * where <tt>PREFIX</tt> is <var>prefix</var>, whose data is the protocol
+ * packet.
  */
 function ChildDebuggerTransport(mm, prefix) {
   EventEmitter.decorate(this);
 
   this._mm = mm;
   this._messageName = "debug:" + prefix + ":packet";
 }
 
--- a/testing/marionette/wait.js
+++ b/testing/marionette/wait.js
@@ -5,20 +5,38 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("chrome://marionette/content/error.js");
 
 this.EXPORTED_SYMBOLS = ["wait"];
 
-/** Implicit wait utilities. */
+/**
+ * Poll-waiting utilities.
+ *
+ * @namespace
+ */
 this.wait = {};
 
 /**
+ * @callback WaitCondition
+ *
+ * @param {function(*)} resolve
+ *     To be called when the condition has been met.  Will return the
+ *     resolved value.
+ * @param {function} reject
+ *     To be called when the condition has not been met.  Will cause
+ *     the condition to be revaluated or time out.
+ *
+ * @return {*}
+ *     The value from calling <code>resolve</code>.
+ */
+
+/**
  * Runs a promise-like function off the main thread until it is resolved
  * through |resolve| or |rejected| callbacks.  The function is guaranteed
  * to be run at least once, irregardless of the timeout.
  *
  * The |func| is evaluated every |interval| for as long as its runtime
  * duration does not exceed |interval|.  Evaluations occur sequentially,
  * meaning that evaluations of |func| are queued if the runtime evaluation
  * duration of |func| is greater than |interval|.
@@ -28,40 +46,42 @@ this.wait = {};
  * an argument indicates that the expected wait condition was met and
  * will return the passed value to the caller.  Conversely, calling
  * |reject| will evaluate |func| again until the |timeout| duration has
  * elapsed or |func| throws.  The passed value to |reject| will also be
  * returned to the caller once the wait has expired.
  *
  * Usage:
  *
+ * <pre><code>
  *     let els = wait.until((resolve, reject) => {
  *       let res = document.querySelectorAll("p");
  *       if (res.length > 0) {
  *         resolve(Array.from(res));
  *       } else {
  *         reject([]);
  *       }
  *     });
+ * </pre></code>
  *
- * @param {function(resolve: function(?), reject: function(?)): ?} func
+ * @param {WaitCondition} func
  *     Function to run off the main thread.
  * @param {number=} timeout
  *     Desired timeout.  If 0 or less than the runtime evaluation time
  *     of |func|, |func| is guaranteed to run at least once.  The default
  *     is 2000 milliseconds.
  * @param {number=} interval
  *     Duration between each poll of |func| in milliseconds.  Defaults to
  *     10 milliseconds.
  *
- * @return {Promise: ?}
+ * @return {Promise.<*>}
  *     Yields the value passed to |func|'s |resolve| or |reject|
  *     callbacks.
  *
- * @throws {?}
+ * @throws {*}
  *     If |func| throws, its error is propagated.
  */
 wait.until = function(func, timeout = 2000, interval = 10) {
   const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
   return new Promise((resolve, reject) => {
     const start = new Date().getTime();
     const end = start + timeout;