/* 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 context is content. * * @param {string} context * Context to test. * @param {string=} msg * Custom error message. * * @return {string} * context is returned unaltered. * * @throws {UnsupportedOperationError} * If context 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. * * @return {CanonicalBrowsingContext} * browsingContext is returned unaltered. * * @throws {NoSuchWindowError} * If browsingContext 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 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 obj is defined. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {?} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is a finite number. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {number} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is a positive number. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {number} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is a number in the inclusive range lower to upper. * * @param {?} obj * Value to test. * @param {Array} Range * Array range [lower, upper] * @param {string=} msg * Custom error message. * * @return {number} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is callable. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {Function} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is an unsigned short number. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {number} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is an integer. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {number} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is a positive integer. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {number} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is an integer in the inclusive range lower to upper. * * @param {?} obj * Value to test. * @param {Array} Range * Array range [lower, upper] * @param {string=} msg * Custom error message. * * @return {number} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is a boolean. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {boolean} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is a string. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {string} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 obj is an object. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {Object} * obj| is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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 prop is in obj. * * @param {?} prop * An array element or own property to test if is in obj. * @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 obj's own property * prop. * * @throws {InvalidArgumentError} * If the obj was an array and did not contain prop. * Otherwise if prop is not in obj, or obj * 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 obj is an Array. * * @param {?} obj * Value to test. * @param {string=} msg * Custom error message. * * @return {Object} * obj is returned unaltered. * * @throws {InvalidArgumentError} * If obj 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); }; /** * 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, error * is thrown with message. * @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 error with message * if predicate evaluates to false. */ assert.that = function( predicate, message = "", err = lazy.error.InvalidArgumentError ) { return obj => { if (!predicate(obj)) { throw new err(message); } return obj; }; };