forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			483 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			483 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 | 
						|
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const { AppConstants } = ChromeUtils.import(
 | 
						|
  "resource://gre/modules/AppConstants.jsm"
 | 
						|
);
 | 
						|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 | 
						|
const { XPCOMUtils } = ChromeUtils.import(
 | 
						|
  "resource://gre/modules/XPCOMUtils.jsm"
 | 
						|
);
 | 
						|
 | 
						|
const {
 | 
						|
  InvalidArgumentError,
 | 
						|
  InvalidSessionIDError,
 | 
						|
  JavaScriptError,
 | 
						|
  NoSuchWindowError,
 | 
						|
  UnexpectedAlertOpenError,
 | 
						|
  UnsupportedOperationError,
 | 
						|
} = ChromeUtils.import("chrome://marionette/content/error.js");
 | 
						|
const { pprint } = ChromeUtils.import("chrome://marionette/content/format.js");
 | 
						|
 | 
						|
XPCOMUtils.defineLazyModuleGetters(this, {
 | 
						|
  evaluate: "chrome://marionette/content/evaluate.js",
 | 
						|
  browser: "chrome://marionette/content/browser.js",
 | 
						|
});
 | 
						|
 | 
						|
this.EXPORTED_SYMBOLS = ["assert"];
 | 
						|
 | 
						|
const isFennec = () => AppConstants.platform == "android";
 | 
						|
const isFirefox = () =>
 | 
						|
  Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
 | 
						|
const isThunderbird = () =>
 | 
						|
  Services.appinfo.ID == "{3550f703-e582-4d05-9a08-453d09bdfdc6}";
 | 
						|
 | 
						|
/**
 | 
						|
 * Shorthands for common assertions made in Marionette.
 | 
						|
 *
 | 
						|
 * @namespace
 | 
						|
 */
 | 
						|
this.assert = {};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that an arbitrary object is not acyclic.
 | 
						|
 *
 | 
						|
 * @param {*} obj
 | 
						|
 *     Object to test.  This assertion is only meaningful if passed
 | 
						|
 *     an actual object or array.
 | 
						|
 * @param {Error=} [error=JavaScriptError] error
 | 
						|
 *     Error to throw if assertion fails.
 | 
						|
 * @param {string=} message
 | 
						|
 *     Custom message to use for `error` if assertion fails.
 | 
						|
 *
 | 
						|
 * @throws {JavaScriptError}
 | 
						|
 *     If the object is cyclic.
 | 
						|
 */
 | 
						|
assert.acyclic = function(obj, msg = "", error = JavaScriptError) {
 | 
						|
  if (evaluate.isCyclic(obj)) {
 | 
						|
    throw new error(msg || "Cyclic object value");
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that Marionette has a session.
 | 
						|
 *
 | 
						|
 * @param {GeckoDriver} driver
 | 
						|
 *     Marionette driver instance.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {string}
 | 
						|
 *     Current session's ID.
 | 
						|
 *
 | 
						|
 * @throws {InvalidSessionIDError}
 | 
						|
 *     If <var>driver</var> does not have a session ID.
 | 
						|
 */
 | 
						|
assert.session = function(driver, msg = "") {
 | 
						|
  assert.that(
 | 
						|
    sessionID => sessionID,
 | 
						|
    msg,
 | 
						|
    InvalidSessionIDError
 | 
						|
  )(driver.sessionID);
 | 
						|
  return driver.sessionID;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that the current browser is Firefox Desktop.
 | 
						|
 *
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @throws {UnsupportedOperationError}
 | 
						|
 *     If current browser is not Firefox.
 | 
						|
 */
 | 
						|
assert.firefox = function(msg = "") {
 | 
						|
  msg = msg || "Only supported in Firefox";
 | 
						|
  assert.that(isFirefox, msg, UnsupportedOperationError)();
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that the current browser is Firefox Desktop or Thunderbird.
 | 
						|
 *
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @throws {UnsupportedOperationError}
 | 
						|
 *     If current browser is not Firefox or Thunderbird.
 | 
						|
 */
 | 
						|
assert.desktop = function(msg = "") {
 | 
						|
  msg = msg || "Only supported in desktop applications";
 | 
						|
  assert.that(
 | 
						|
    obj => isFirefox(obj) || isThunderbird(obj),
 | 
						|
    msg,
 | 
						|
    UnsupportedOperationError
 | 
						|
  )();
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that the current browser is Fennec, or Firefox for Android.
 | 
						|
 *
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @throws {UnsupportedOperationError}
 | 
						|
 *     If current browser is not Fennec.
 | 
						|
 */
 | 
						|
assert.fennec = function(msg = "") {
 | 
						|
  msg = msg || "Only supported in Fennec";
 | 
						|
  assert.that(isFennec, msg, UnsupportedOperationError)();
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that the current <var>context</var> is content.
 | 
						|
 *
 | 
						|
 * @param {string} context
 | 
						|
 *     Context to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {string}
 | 
						|
 *     <var>context</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {UnsupportedOperationError}
 | 
						|
 *     If <var>context</var> is not content.
 | 
						|
 */
 | 
						|
assert.content = function(context, msg = "") {
 | 
						|
  msg = msg || "Only supported in content context";
 | 
						|
  assert.that(
 | 
						|
    c => c.toString() == "content",
 | 
						|
    msg,
 | 
						|
    UnsupportedOperationError
 | 
						|
  )(context);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that the {@link ChromeWindow} is open or that the {@link
 | 
						|
 * browser.Context} has a content browser attached.
 | 
						|
 *
 | 
						|
 * When passed in a {@link ChromeContext} this is equivalent to
 | 
						|
 * testing that the associated <code>window</code> global is open,
 | 
						|
 * and when given {@link browser.Context} it will test that the content
 | 
						|
 * frame, represented by <code><xul:browser></code>, is
 | 
						|
 * connected.
 | 
						|
 *
 | 
						|
 * @param {(ChromeWindow|browser.Context)} context
 | 
						|
 *     Browsing context to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {(ChromeWindow|browser.Context)}
 | 
						|
 *     <var>context</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {NoSuchWindowError}
 | 
						|
 *     If <var>context</var>'s <code>window</code> has been closed.
 | 
						|
 */
 | 
						|
assert.open = function(context, msg = "") {
 | 
						|
  // TODO: The contentBrowser uses a cached tab, which is only updated when
 | 
						|
  // switchToTab is called. Because of that an additional check is needed to
 | 
						|
  // make sure that the chrome window has not already been closed.
 | 
						|
  if (context instanceof browser.Context) {
 | 
						|
    assert.open(context.window);
 | 
						|
  }
 | 
						|
 | 
						|
  msg = msg || "Browsing context has been discarded";
 | 
						|
  return assert.that(
 | 
						|
    ctx => ctx && !ctx.closed,
 | 
						|
    msg,
 | 
						|
    NoSuchWindowError
 | 
						|
  )(context);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that there is no current user prompt.
 | 
						|
 *
 | 
						|
 * @param {modal.Dialog} dialog
 | 
						|
 *     Reference to current dialogue.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @throws {UnexpectedAlertOpenError}
 | 
						|
 *     If there is a user prompt.
 | 
						|
 */
 | 
						|
assert.noUserPrompt = function(dialog, msg = "") {
 | 
						|
  assert.that(
 | 
						|
    d => d === null || typeof d == "undefined",
 | 
						|
    msg,
 | 
						|
    UnexpectedAlertOpenError
 | 
						|
  )(dialog);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is defined.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {?}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not defined.
 | 
						|
 */
 | 
						|
assert.defined = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`Expected ${obj} to be defined`;
 | 
						|
  return assert.that(o => typeof o != "undefined", msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is a finite number.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {number}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not a number.
 | 
						|
 */
 | 
						|
assert.number = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`Expected ${obj} to be finite number`;
 | 
						|
  return assert.that(Number.isFinite, msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is a positive number.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {number}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not a positive integer.
 | 
						|
 */
 | 
						|
assert.positiveNumber = function(obj, msg = "") {
 | 
						|
  assert.number(obj, msg);
 | 
						|
  msg = msg || pprint`Expected ${obj} to be >= 0`;
 | 
						|
  return assert.that(n => n >= 0, msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is callable.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {Function}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not callable.
 | 
						|
 */
 | 
						|
assert.callable = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`${obj} is not callable`;
 | 
						|
  return assert.that(o => typeof o == "function", msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is an unsigned short number.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {number}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not an unsigned short.
 | 
						|
 */
 | 
						|
assert.unsignedShort = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`Expected ${obj} to be >= 0 and < 65536`;
 | 
						|
  return assert.that(n => n >= 0 && n < 65536, msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is an integer.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {number}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not an integer.
 | 
						|
 */
 | 
						|
assert.integer = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`Expected ${obj} to be an integer`;
 | 
						|
  return assert.that(Number.isSafeInteger, msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is a positive integer.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {number}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not a positive integer.
 | 
						|
 */
 | 
						|
assert.positiveInteger = function(obj, msg = "") {
 | 
						|
  assert.integer(obj, msg);
 | 
						|
  msg = msg || pprint`Expected ${obj} to be >= 0`;
 | 
						|
  return assert.that(n => n >= 0, msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is a boolean.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {boolean}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not a boolean.
 | 
						|
 */
 | 
						|
assert.boolean = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`Expected ${obj} to be boolean`;
 | 
						|
  return assert.that(b => typeof b == "boolean", msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is a string.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {string}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not a string.
 | 
						|
 */
 | 
						|
assert.string = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`Expected ${obj} to be a string`;
 | 
						|
  return assert.that(s => typeof s == "string", msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is an object.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {Object}
 | 
						|
 *     obj| is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not an object.
 | 
						|
 */
 | 
						|
assert.object = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`Expected ${obj} to be an object`;
 | 
						|
  return assert.that(o => {
 | 
						|
    // unable to use instanceof because LHS and RHS may come from
 | 
						|
    // different globals
 | 
						|
    let s = Object.prototype.toString.call(o);
 | 
						|
    return s == "[object Object]" || s == "[object nsJSIID]";
 | 
						|
  }, msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>prop</var> is in <var>obj</var>.
 | 
						|
 *
 | 
						|
 * @param {?} prop
 | 
						|
 *     An array element or own property to test if is in <var>obj</var>.
 | 
						|
 * @param {?} obj
 | 
						|
 *     An array or an Object that is being tested.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {?}
 | 
						|
 *     The array element, or the value of <var>obj</var>'s own property
 | 
						|
 *     <var>prop</var>.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If the <var>obj</var> was an array and did not contain <var>prop</var>.
 | 
						|
 *     Otherwise if <var>prop</var> is not in <var>obj</var>, or <var>obj</var>
 | 
						|
 *     is not an object.
 | 
						|
 */
 | 
						|
assert.in = function(prop, obj, msg = "") {
 | 
						|
  if (Array.isArray(obj)) {
 | 
						|
    assert.that(p => obj.includes(p), msg)(prop);
 | 
						|
    return prop;
 | 
						|
  }
 | 
						|
  assert.object(obj, msg);
 | 
						|
  msg = msg || pprint`Expected ${prop} in ${obj}`;
 | 
						|
  assert.that(p => obj.hasOwnProperty(p), msg)(prop);
 | 
						|
  return obj[prop];
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Asserts that <var>obj</var> is an Array.
 | 
						|
 *
 | 
						|
 * @param {?} obj
 | 
						|
 *     Value to test.
 | 
						|
 * @param {string=} msg
 | 
						|
 *     Custom error message.
 | 
						|
 *
 | 
						|
 * @return {Object}
 | 
						|
 *     <var>obj</var> is returned unaltered.
 | 
						|
 *
 | 
						|
 * @throws {InvalidArgumentError}
 | 
						|
 *     If <var>obj</var> is not an Array.
 | 
						|
 */
 | 
						|
assert.array = function(obj, msg = "") {
 | 
						|
  msg = msg || pprint`Expected ${obj} to be an Array`;
 | 
						|
  return assert.that(Array.isArray, msg)(obj);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns a function that is used to assert the |predicate|.
 | 
						|
 *
 | 
						|
 * @param {function(?): boolean} predicate
 | 
						|
 *     Evaluated on calling the return value of this function.  If its
 | 
						|
 *     return value of the inner function is false, <var>error</var>
 | 
						|
 *     is thrown with <var>message</var>.
 | 
						|
 * @param {string=} message
 | 
						|
 *     Custom error message.
 | 
						|
 * @param {Error=} error
 | 
						|
 *     Custom error type by its class.
 | 
						|
 *
 | 
						|
 * @return {function(?): ?}
 | 
						|
 *     Function that takes and returns the passed in value unaltered,
 | 
						|
 *     and which may throw <var>error</var> with <var>message</var>
 | 
						|
 *     if <var>predicate</var> evaluates to false.
 | 
						|
 */
 | 
						|
assert.that = function(predicate, message = "", error = InvalidArgumentError) {
 | 
						|
  return obj => {
 | 
						|
    if (!predicate(obj)) {
 | 
						|
      throw new error(message);
 | 
						|
    }
 | 
						|
    return obj;
 | 
						|
  };
 | 
						|
};
 |