563 lines
14 KiB
JavaScript
563 lines
14 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/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
AppInfo: "chrome://remote/content/shared/AppInfo.sys.mjs",
|
|
error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
|
|
pprint: "chrome://remote/content/shared/Format.sys.mjs",
|
|
});
|
|
|
|
/**
|
|
* Shorthands for common assertions made in WebDriver.
|
|
*
|
|
* @namespace
|
|
*/
|
|
export const assert = {};
|
|
|
|
/**
|
|
* Asserts that WebDriver has an active session.
|
|
*
|
|
* @param {WebDriverSession} session
|
|
* WebDriver session instance.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @throws {InvalidSessionIDError}
|
|
* If session does not exist, or has an invalid id.
|
|
*/
|
|
assert.session = function (session, msg = "") {
|
|
msg = msg || "WebDriver session does not exist, or is not active";
|
|
assert.that(
|
|
session => session && typeof session.id == "string",
|
|
msg,
|
|
lazy.error.InvalidSessionIDError
|
|
)(session);
|
|
};
|
|
|
|
/**
|
|
* 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 => isFirefox,
|
|
msg,
|
|
lazy.error.UnsupportedOperationError
|
|
)(lazy.AppInfo.isFirefox);
|
|
};
|
|
|
|
/**
|
|
* Asserts that the current application is Firefox Desktop or Thunderbird.
|
|
*
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @throws {UnsupportedOperationError}
|
|
* If current application is not running on desktop.
|
|
*/
|
|
assert.desktop = function (msg = "") {
|
|
msg = msg || "Only supported in desktop applications";
|
|
assert.that(
|
|
isDesktop => isDesktop,
|
|
msg,
|
|
lazy.error.UnsupportedOperationError
|
|
)(!lazy.AppInfo.isAndroid);
|
|
};
|
|
|
|
/**
|
|
* Asserts that the current application runs on Android.
|
|
*
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @throws {UnsupportedOperationError}
|
|
* If current application is not running on Android.
|
|
*/
|
|
assert.mobile = function (msg = "") {
|
|
msg = msg || "Only supported on Android";
|
|
assert.that(
|
|
isAndroid => isAndroid,
|
|
msg,
|
|
lazy.error.UnsupportedOperationError
|
|
)(lazy.AppInfo.isAndroid);
|
|
};
|
|
|
|
/**
|
|
* Asserts that the current <var>context</var> is content.
|
|
*
|
|
* @param {string} context
|
|
* Context to test.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {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,
|
|
lazy.error.UnsupportedOperationError
|
|
)(context);
|
|
};
|
|
|
|
/**
|
|
* Asserts that the {@link CanonicalBrowsingContext} is open.
|
|
*
|
|
* @param {CanonicalBrowsingContext} browsingContext
|
|
* Canonical browsing context to check.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {CanonicalBrowsingContext}
|
|
* <var>browsingContext</var> is returned unaltered.
|
|
*
|
|
* @throws {NoSuchWindowError}
|
|
* If <var>browsingContext</var> is no longer open.
|
|
*/
|
|
assert.open = function (browsingContext, msg = "") {
|
|
msg = msg || "Browsing context has been discarded";
|
|
return assert.that(
|
|
browsingContext => {
|
|
if (!browsingContext?.currentWindowGlobal) {
|
|
return false;
|
|
}
|
|
|
|
if (browsingContext.isContent && !browsingContext.top.embedderElement) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
msg,
|
|
lazy.error.NoSuchWindowError
|
|
)(browsingContext);
|
|
};
|
|
|
|
/**
|
|
* Asserts that the browsing context is top-level.
|
|
*
|
|
* @param {BrowsingContext} browsingContext
|
|
* Browsing context to check.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {BrowsingContext}
|
|
* <var>browsingContext</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>browsingContext</var> is not top-level.
|
|
*/
|
|
assert.topLevel = function (browsingContext, msg = "") {
|
|
msg = msg || `Browsing context is not top-level`;
|
|
return assert.that(
|
|
() => !browsingContext.parent,
|
|
msg,
|
|
lazy.error.InvalidArgumentError
|
|
)(browsingContext);
|
|
};
|
|
|
|
/**
|
|
* 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,
|
|
lazy.error.UnexpectedAlertOpenError
|
|
)(dialog);
|
|
};
|
|
|
|
/**
|
|
* Asserts that <var>obj</var> is defined.
|
|
*
|
|
* @param {?} obj
|
|
* Value to test.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {?}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not defined.
|
|
*/
|
|
assert.defined = function (obj, msg = "") {
|
|
msg = msg || lazy.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.
|
|
*
|
|
* @returns {number}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not a number.
|
|
*/
|
|
assert.number = function (obj, msg = "") {
|
|
msg = msg || lazy.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.
|
|
*
|
|
* @returns {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 || lazy.pprint`Expected ${obj} to be >= 0`;
|
|
return assert.that(n => n >= 0, msg)(obj);
|
|
};
|
|
|
|
/**
|
|
* Asserts that <var>obj</var> is a number in the inclusive range <var>lower</var> to <var>upper</var>.
|
|
*
|
|
* @param {?} obj
|
|
* Value to test.
|
|
* @param {Array<number>} range
|
|
* Array range [lower, upper]
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {number}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not a number in the specified range.
|
|
*/
|
|
assert.numberInRange = function (obj, range, msg = "") {
|
|
const [lower, upper] = range;
|
|
assert.number(obj, msg);
|
|
msg = msg || lazy.pprint`Expected ${obj} to be >= ${lower} and <= ${upper}`;
|
|
return assert.that(n => n >= lower && n <= upper, msg)(obj);
|
|
};
|
|
|
|
/**
|
|
* Asserts that <var>obj</var> is callable.
|
|
*
|
|
* @param {?} obj
|
|
* Value to test.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {Function}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not callable.
|
|
*/
|
|
assert.callable = function (obj, msg = "") {
|
|
msg = msg || lazy.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.
|
|
*
|
|
* @returns {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 || lazy.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.
|
|
*
|
|
* @returns {number}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not an integer.
|
|
*/
|
|
assert.integer = function (obj, msg = "") {
|
|
msg = msg || lazy.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.
|
|
*
|
|
* @returns {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 || lazy.pprint`Expected ${obj} to be >= 0`;
|
|
return assert.that(n => n >= 0, msg)(obj);
|
|
};
|
|
|
|
/**
|
|
* Asserts that <var>obj</var> is an integer in the inclusive range <var>lower</var> to <var>upper</var>.
|
|
*
|
|
* @param {?} obj
|
|
* Value to test.
|
|
* @param {Array<number>} range
|
|
* Array range [lower, upper]
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {number}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not a number in the specified range.
|
|
*/
|
|
assert.integerInRange = function (obj, range, msg = "") {
|
|
const [lower, upper] = range;
|
|
assert.integer(obj, msg);
|
|
msg = msg || lazy.pprint`Expected ${obj} to be >= ${lower} and <= ${upper}`;
|
|
return assert.that(n => n >= lower && n <= upper, msg)(obj);
|
|
};
|
|
|
|
/**
|
|
* Asserts that <var>obj</var> is a boolean.
|
|
*
|
|
* @param {?} obj
|
|
* Value to test.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {boolean}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not a boolean.
|
|
*/
|
|
assert.boolean = function (obj, msg = "") {
|
|
msg = msg || lazy.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.
|
|
*
|
|
* @returns {string}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not a string.
|
|
*/
|
|
assert.string = function (obj, msg = "") {
|
|
msg = msg || lazy.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.
|
|
*
|
|
* @returns {object}
|
|
* obj| is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not an object.
|
|
*/
|
|
assert.object = function (obj, msg = "") {
|
|
msg = msg || lazy.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>obj</var> is an instance of a specified class.
|
|
* <var>constructor</var> should have a static isInstance method implemented.
|
|
*
|
|
* @param {?} obj
|
|
* Value to test.
|
|
* @param {?} constructor
|
|
* Class constructor.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {object}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not an instance of a specified class.
|
|
*/
|
|
assert.isInstance = function (obj, constructor, msg = "") {
|
|
assert.object(obj, msg);
|
|
assert.object(constructor.prototype, msg);
|
|
|
|
msg =
|
|
msg ||
|
|
lazy.pprint`Expected ${obj} to be an instance of ${constructor.name}`;
|
|
return assert.that(
|
|
o => Object.hasOwn(constructor, "isInstance") && constructor.isInstance(o),
|
|
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.
|
|
*
|
|
* @returns {?}
|
|
* 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 || lazy.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.
|
|
*
|
|
* @returns {object}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not an Array.
|
|
*/
|
|
assert.array = function (obj, msg = "") {
|
|
msg = msg || lazy.pprint`Expected ${obj} to be an Array`;
|
|
return assert.that(Array.isArray, msg)(obj);
|
|
};
|
|
|
|
/**
|
|
* Asserts that <var>obj</var> is a non-empty Array.
|
|
*
|
|
* @param {?} obj
|
|
* Value to test.
|
|
* @param {string=} msg
|
|
* Custom error message.
|
|
*
|
|
* @returns {object}
|
|
* <var>obj</var> is returned unaltered.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>obj</var> is not a non-empty Array.
|
|
*/
|
|
assert.isNonEmptyArray = function (obj, msg = "") {
|
|
msg = msg || lazy.pprint`Expected ${obj} to be a non-empty Array`;
|
|
assert.array(obj, msg);
|
|
assert.that(assertObj => !!assertObj.length, msg)(obj);
|
|
return 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=} err
|
|
* Custom error type by its class.
|
|
*
|
|
* @returns {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 = "",
|
|
err = lazy.error.InvalidArgumentError
|
|
) {
|
|
return obj => {
|
|
if (!predicate(obj)) {
|
|
throw new err(message);
|
|
}
|
|
return obj;
|
|
};
|
|
};
|