import { getMethods , sleep , trimStack } from './lib/util' ; import Element from './Element' ; import { Task , CancellablePromise } from '@theintern/common' ; import Session from './Session' ; import Locator , { Strategy } from './lib/Locator' ; import { LogEntry , Geolocation , WebDriverCookie } from './interfaces' ; /**
 * The Command class is a chainable, subclassable object type that can be used
 * to execute commands serially against a remote WebDriver environment. The
 * standard Command class includes methods from the [[Session]] and [[Element]]
 * classes, so you can perform all standard session and element operations that
 * come with Leadfoot without being forced to author long promise chains.
 *
 * In order to use the Command class, you first need to pass it a [[Session]]
 * instance for it to use:
 *
 * ```js
 * const command = new Command(session);
 * ```
 *
 * Once you have created the Command, you can then start chaining methods, and
 * they will execute in order one after another:
 *
 * ```js
 * command.get('http://example.com')
 *     .findByTagName('h1')
 *     .getVisibleText()
 *     .then(function (text) {
 *         assert.strictEqual(text, 'Example Domain');
 *     });
 * ```
 *
 * Because these operations are asynchronous, you need to use a `then` callback
 * in order to retrieve the value from the last method. Command objects are
 * PromiseLikes, which means that they can be used with any Promises/A+ or
 * ES6-conformant Promises implementation, though there are some specific
 * differences in the arguments and context that are provided to callbacks; see
 * [[Command.Command.then]] for more details.
 *
 * Because Commands are promise-like, they may also be used with `async/await`:
 *
 * ```js
 * const page = await command.get('http://example.com');
 * const h1 = await page.findByTagName('h1');
 * const text = await h1.getVisibleText();
 * assert.strictEqual(text, 'Example Domain');
 * ```
 *
 * ---
 *
 * Each call on a Command generates a new Command object, which means that
 * certain operations can be parallelised:
 *
 * ```js
 * command = command.get('http://example.com');
 * Promise.all([
 *     command.getPageTitle(),
 *     command.findByTagName('h1').getVisibleText()
 * ]).then(results => {
 *     assert.strictEqual(results[0], results[1]);
 * });
 * ```
 *
 * In this example, the commands on line 3 and 4 both depend upon the `get`
 * call completing successfully but are otherwise independent of each other and
 * so execute here in parallel. This is different from commands in Intern 1
 * which were always chained onto the last called method within a given test.
 *
 * ---
 *
 * Command objects actually encapsulate two different types of interaction:
 * *session* interactions, which operate against the entire browser session,
 * and *element* interactions, which operate against specific elements taken
 * from the currently loaded page. Things like navigating the browser, moving
 * the mouse cursor, and executing scripts are session interactions; things
 * like getting text displayed on the page, typing into form fields, and
 * getting element attributes are element interactions.
 *
 * Session interactions can be performed at any time, from any Command. On the
 * other hand, to perform element interactions, you first need to retrieve one
 * or more elements to interact with. This can be done using any of the `find`
 * or `findAll` methods, by the `getActiveElement` method, or by returning
 * elements from `execute` or `executeAsync` calls. The retrieved elements are
 * stored internally as the *element context* of all chained Commands. When an
 * element method is called on a chained Command with a single element context,
 * the result will be returned as-is:
 *
 * ```js
 * command = command.get('http://example.com')
 *     // finds one element -> single element context
 *     .findByTagName('h1')
 *     .getVisibleText()
 *     .then(text => {
 *         // `text` is the text from the element context
 *         assert.strictEqual(text, 'Example Domain');
 *     });
 * ```
 *
 * When an element method is called on a chained Command with a multiple
 * element context, the result will be returned as an array:
 *
 * ```js
 * command = command.get('http://example.com')
 *     // finds multiple elements -> multiple element context
 *     .findAllByTagName('p')
 *     .getVisibleText()
 *     .then(texts => {
 *         // `texts` is an array of text from each of the `p` elements
 *         assert.deepEqual(texts, [
 *             'This domain is established to be used for […]',
 *             'More information...'
 *         ]);
 *     });
 * ```
 *
 * The `find` and `findAll` methods are special and change their behaviour
 * based on the current element filtering state of a given command. If a
 * command has been filtered by element, the `find` and `findAll` commands will
 * only find elements *within* the currently filtered set of elements.
 * Otherwise, they will find elements throughout the page.
 *
 * Some method names, like `click`, are identical for both Session and Element
 * APIs; in this case, the element APIs are suffixed with the word `Element` in
 * order to identify them uniquely.
 *
 * ---
 *
 * Commands can be subclassed in order to add additional functionality without
 * making direct modifications to the default Command prototype that might
 * break other parts of the system:
 *
 * ```ts
 * class CustomCommand extends Command {
 *     login(username: string, password: string) {
 *         return new this.constructor(this, function () {
 *             return this.parent
 *                 .findById('username')
 *                 .click()
 *                 .type(username)
 *                 .end()
 *
 *                 .findById('password')
 *                 .click()
 *                 .type(password)
 *                 .end()
 *
 *                 .findById('login')
 *                 .click()
 *                 .end();
 *         });
 *     }
 * }
 * ```
 *
 * >  ⚠️Note that returning `this`, or a command chain starting from `this`,
 * from a callback or command initialiser will deadlock the Command, as it
 * waits for itself to settle before settling.
 */ export default class Command < T , P = any , StringResult extends string | string [ ] = string > extends Locator < Command < Element , P , string > , Command < Element [ ] , P , string [ ] > , Command < void , P , StringResult > > implements PromiseLike < T > { param { module:leadfoot/Command } target param { string } key param { Function } originalFn static addSessionMethod < Us , Ps , Ss extends string | string [ ] > ( target , key , originalFn ) { if ( key . charAt ( 0 ) !== '_' && ! ( < any > target ) [ key ] && typeof originalFn === 'function' ) { ( < any > target ) [ key ] = function ( this , ... args ) : Command < Us , Ps , Ss > { return new ( this . constructor as typeof Command ) < Us , Ps , Ss > ( this , function ( this , setContext ) { const parentContext = this . _context ; const session = this . _session ; let promise ; const fn = ( < any > session ) [ key ] || originalFn ; if ( fn . usesElement && parentContext . length && ( ! args [ 0 ] || ! args [ 0 ] . elementId ) ) { args = Array . prototype . slice . call ( args , 0 ) ; if ( parentContext . isSingle ) { promise = fn . apply ( session , [ parentContext [ 0 ] ] . concat ( args ) ) ; } else { promise = Task . all ( parentContext . map ( ( element ) => fn . apply ( session , [ element ] . concat ( args ) ) ) ) ; } } else { promise = fn . apply ( session , args ) ; } if ( fn . createsContext ) { promise = promise . then ( function ( newContext ) { setContext ( newContext ) ; return newContext ; } ) ; } return < CancellablePromise < Us > > promise ; } ) ; } ; } } param { module:leadfoot/Command } target param { string } key static addElementMethod < Us , Ps , Ss extends string | string [ ] > ( target , key ) { const anyTarget = < any > target ; if ( key . charAt ( 0 ) !== '_' ) { const targetKey = key + ( anyTarget [ key ] ? 'Element' : '' ) ; anyTarget [ targetKey ] = function ( this , ... args ) : Command < Us , Ps , Ss > { return new ( this . constructor as typeof Command ) < Us , Ps , Ss > ( this , function ( setContext ) { const parentContext = this . _context ; let promise ; let fn = ( < any > parentContext ) [ 0 ] && ( < any > parentContext ) [ 0 ] [ key ] ; if ( parentContext . isSingle ) { promise = fn . apply ( parentContext [ 0 ] , args ) ; } else { promise = Task . all ( parentContext . map ( function ( element ) { return element [ key ] . apply ( element , args ) ; } ) ) ; } if ( fn && fn . createsContext ) { promise = promise . then ( function ( newContext ) { setContext ( newContext ) ; return newContext ; } ) ; } return < CancellablePromise < Us > > promise ; } ) ; } ; } } private _parent : Command < P , any , StringResult > | undefined ; private _session : Session ; private _context ! : Context ; private _task : CancellablePromise < any > ; param parent param initialiser param errback constructor ( parentOrSession , initialiser ? , errback ? ) { super ( ) ; const self = this ; let session ; const trace = { } ; function setContext ( contextValue ) { let context ; if ( ! Array . isArray ( contextValue ) ) { context = < Context > [ contextValue ] ; context . isSingle = true ; } else { context = contextValue ; } const parent = < Command < P , any , StringResult > > parentOrSession ; if ( ! ( 'depth' in context ) ) { context . depth = parent ? parent . context . depth ! + 1 : 0 ; } self . _context = context ; } function fixStack ( error ) { error . stack = error . stack + trimStack ( trace . stack ) ; throw error ; } if ( parentOrSession instanceof Command ) { this . _parent = parentOrSession ; session = this . _session = parentOrSession . session ; } else if ( parentOrSession instanceof Session ) { session = this . _session = parentOrSession ; parentOrSession = null ; } else { throw new Error ( 'A parent Command or Session must be provided to a new Command' ) ; } getMethods ( session ) . forEach ( name => { const key = < keyof Session > name ; if ( session [ key ] !== Session . prototype [ key ] ) { Command . addSessionMethod ( this , key , ( < any > session ) [ key ] ) ; } } ) ; Error . captureStackTrace ( trace , Command ) ; let parentCommand = < Command < P , any , StringResult > > parentOrSession ; this . _task = ( parentCommand ? parentCommand . promise : Task . resolve ( undefined ) ) . then ( function ( returnValue ) { self . _context = parentCommand ? parentCommand . context : TOP_CONTEXT ; return returnValue ; } , function ( error ) { self . _context = parentCommand ? parentCommand . context : TOP_CONTEXT ; throw error ; } ) . then ( initialiser && function ( returnValue ) { return Task . resolve ( returnValue ) . then ( initialiser . bind ( self , setContext ) ) . catch ( fixStack ) ; } , errback && function ( error ) { return Task . reject ( error ) . catch ( errback . bind ( self , setContext ) ) . catch ( fixStack ) ; } ) ; } /**
     * The parent Command of the Command, if one exists. This will be defined
     * for all commands but the top-level Session command (i.e., in most
     * contexts user code will call it).
     */ get parent ( ) { return this . _parent ! ; } /**
     * The parent Session of the Command.
     */ get session ( ) { return this . _session ; } /**
     * The filtered elements that will be used if an element-specific method is
     * invoked. Note that this property is not valid until the parent Command
     * has been settled. The context array also has two additional properties:
     *
     * * `isSingle` (boolean): If true, the context will always contain a
     *   single element. This is used to differentiate between methods that
     *   should still return scalar values (`find`) and methods that should
     *   return arrays of values even if there is only one element in the
     *   context (`findAll`).
     * * `depth` (number): The depth of the context within the command chain.
     *   This is used to prevent traversal into higher filtering levels by
     *   [[Command.Command.end]].
     */ get context ( ) { return this . _context ; } readonly get promise ( ) { return this . _task ; } param ms sleep ( ms ) { return new ( this . constructor as typeof Command ) < void , any , StringResult > ( this , function ( ) { return sleep ( ms ) ; } ) ; } param numCommandsToPop end ( numCommandsToPop = 1 ) { return new ( this . constructor as typeof Command ) < void , any , StringResult > ( this , function ( setContext ) { let command = this ; let depth = this . context . depth ; while ( depth && numCommandsToPop && ( command = command . parent ) ) { if ( command . context . depth != null && command . context . depth < depth ) { -- numCommandsToPop ; depth = command . context . depth ; } } setContext ( command ! . context ) ; } ) ; } /**
     * Adds a callback to be invoked once the previously chained operation has
     * completed.
     *
     * This method is compatible with the `Promise#then` API, with two
     * important differences:
     *
     * 1. The context (`this`) of the callback is set to the Command object,
     *    rather than being `undefined`. This allows promise helpers to be
     *    created that can retrieve the appropriate session and element
     *    contexts for execution.
     * 2. A second non-standard `setContext` argument is passed to the
     *    callback. This `setContext` function can be called at any time before
     *    the callback fulfills its return value and expects either a single
     *    [[Element]] or an array of Elements to be provided as its only
     *    argument. The provided element(s) will be used as the context for
     *    subsequent element method invocations (`click`, etc.). If the
     *    `setContext` method is not called, the element context from the
     *    parent will be passed through unmodified.
     */ then < U = T , R = never > ( callback ? , errback ? ) { function runCallback ( newCommand , callback , errback , value , setContext ) ; function runCallback ( newCommand , callback , errback , value , setContext ) ; function runCallback ( newCommand , callback , errback , value , setContext ) { const returnValue = callback ? callback . call ( newCommand , ( value as unknown ) as T , setContext ) : errback ! . call ( newCommand , value ) ; if ( returnValue instanceof Command ) { let maybeCommand = returnValue ; do { if ( maybeCommand === newCommand ) { throw new Error ( 'Deadlock: do not use `return this` from a Command callback' ) ; } } while ( ( maybeCommand = getParent < StringResult > ( maybeCommand ) ) ) ; } return returnValue ; } return new ( this . constructor as typeof Command ) ( this , callback ? function ( setContext , value ) { return runCallback ( ( this as unknown ) as Command < T , P , StringResult > , callback , undefined , value , setContext ) ; } : undefined , errback ? function ( setContext , value ) { return ( runCallback ( ( this as unknown ) as Command < T , P , StringResult > , undefined , errback , value , setContext ) as unknown ) as U | PromiseLike < U > ; } : undefined ) ; } /**
     * Adds a callback to be invoked when any of the previously chained
     * operations have failed.
     */ catch < R = never > ( errback ) { return this . then ( null , errback ) ; } /**
     * Adds a callback to be invoked once the previously chained operations
     * have resolved.
     */ finally ( callback ) { this . _task = this . _task . finally ( callback ) ; return this ; } /**
     * Cancels all outstanding chained operations of the Command. Calling this
     * method will cause this command and all subsequent chained commands to
     * fail with a CancelError.
     */ cancel ( ) { this . _task . cancel ( ) ; return this ; } find ( strategy , value ) { return this . _callFindElementMethod ( 'find' , strategy , value ) ; } findAll ( strategy , value ) { return this . _callFindElementMethod ( 'findAll' , strategy , value ) ; } findDisplayed ( strategy , value ) { return this . _callFindElementMethod ( 'findDisplayed' , strategy , value ) ; } /**
     * a function that, when called, creates a new Command that retrieves
     * elements from the parent context and uses them as the context for the
     * newly created Command.
     */ private _callFindElementMethod ( method , strategy , value ) ; private _callFindElementMethod ( method , strategy , value ) ; private _callFindElementMethod ( method , strategy , value ) { return new ( this . constructor as typeof Command ) < any , any , any > ( this , function ( setContext ) { const parentContext = this . _context ; let task ; if ( parentContext . length && parentContext . isSingle ) { task = parentContext [ 0 ] [ method ] ( strategy , value ) ; } else if ( parentContext . length ) { task = Task . all ( parentContext . map ( element => element [ method ] ( strategy , value ) ) ) . then ( elements => Array . prototype . concat . apply ( [ ] , elements ) ) ; } else { task = this . session [ method ] ( strategy , value ) ; } return task . then ( newContext => { setContext ( newContext ) ; return newContext ; } ) ; } ) ; } private _callElementMethod < U > ( method , ... args ) { return new ( this . constructor as typeof Command ) < U , any , StringResult > ( this , function ( setContext ) { const parentContext = this . _context ; let task ; let fn = parentContext [ 0 ] && parentContext [ 0 ] [ method ] ; if ( parentContext . isSingle ) { task = fn . apply ( parentContext [ 0 ] , args ) ; } else { task = ( Task . all ( parentContext . map ( element => ( element [ method ] as Function ) ( ... args ) ) ) . then ( values => Array . prototype . concat . apply ( [ ] , values ) ) as unknown ) as CancellablePromise < U > ; } if ( fn && fn . createsContext ) { task = task . then ( function ( newContext ) { setContext ( < any > newContext ) ; return newContext ; } ) ; } return task ; } ) ; } private _callSessionMethod < U > ( method , ... args ) { return new ( this . constructor as typeof Command ) < U , any , StringResult > ( this , function ( setContext ) { const parentContext = this . _context ; const session = this . _session ; let task ; const sessionMethod = ( ... args ) => { return ( < Function > session [ method ] ) ( ... args ) ; } ; if ( ( < any > session [ method ] ) . usesElement && parentContext . length && ( ! args [ 0 ] || ! args [ 0 ] . elementId ) ) { if ( parentContext . isSingle ) { task = sessionMethod ( ... [ parentContext [ 0 ] , ... args ] ) ; } else { task = ( Task . all ( parentContext . map ( element => sessionMethod ( ... [ element , ... args ] ) ) ) . then ( values => Array . prototype . concat . apply ( [ ] , values ) ) as unknown ) as CancellablePromise < U > ; } } else { task = sessionMethod ( ... args ) ; } if ( ( < any > session [ method ] ) . createsContext ) { task = task . then ( newContext => { setContext ( < any > newContext ) ; return newContext ; } ) ; } return task ; } ) ; } param type returns getTimeout ( type ) { return this . _callSessionMethod < number > ( 'getTimeout' , type ) ; } param type param ms setTimeout ( type , ms ) { return this . _callSessionMethod < void > ( 'setTimeout' , type , ms ) ; } returns getCurrentWindowHandle ( ) { return this . _callSessionMethod < string > ( 'getCurrentWindowHandle' ) ; } /**
     * Gets a list of identifiers for all currently open windows.
     */ getAllWindowHandles ( ) { return this . _callSessionMethod < string [ ] > ( 'getAllWindowHandles' ) ; } /**
     * Gets the URL that is loaded in the focused window/frame.
     */ getCurrentUrl ( ) { return this . _callSessionMethod < string > ( 'getCurrentUrl' ) ; } /**
     * Navigates the focused window/frame to a new URL.
     */ get ( url ) { return this . _callSessionMethod < void > ( 'get' , url ) ; } /**
     * Navigates the focused window/frame forward one page using the browser’s
     * navigation history.
     */ goForward ( ) { return this . _callSessionMethod < void > ( 'goForward' ) ; } /**
     * Navigates the focused window/frame back one page using the browser’s
     * navigation history.
     */ goBack ( ) { return this . _callSessionMethod < void > ( 'goBack' ) ; } /**
     * Reloads the current browser window/frame.
     */ refresh ( ) { return this . _callSessionMethod < void > ( 'refresh' ) ; } param script param args returns execute < T = any > ( script , args ? ) { return this . _callSessionMethod < T > ( 'execute' , script , args ) ; } param script param args returns executeAsync < T = any > ( script , args ? ) { return this . _callSessionMethod < T > ( 'executeAsync' , script , args ) ; } /**
     * Gets a screenshot of the focused window and returns it in PNG format.
     */ takeScreenshot ( ) { return this . _callSessionMethod < Buffer > ( 'takeScreenshot' ) ; } /**
     * Gets a list of input method editor engines available to the remote
     * environment. As of April 2014, no known remote environments support IME
     * functions.
     */ getAvailableImeEngines ( ) { return this . _callSessionMethod < string [ ] > ( 'getAvailableImeEngines' ) ; } /**
     * Gets the currently active input method editor for the remote environment.
     * As of April 2014, no known remote environments support IME functions.
     */ getActiveImeEngine ( ) { return this . _callSessionMethod < string > ( 'getActiveImeEngine' ) ; } /**
     * Returns whether or not an input method editor is currently active in the
     * remote environment. As of April 2014, no known remote environments
     * support IME functions.
     */ isImeActivated ( ) { return this . _callSessionMethod < boolean > ( 'isImeActivated' ) ; } /**
     * Deactivates any active input method editor in the remote environment.
     * As of April 2014, no known remote environments support IME functions.
     */ deactivateIme ( ) { return this . _callSessionMethod < void > ( 'deactivateIme' ) ; } param engine activateIme ( engine ) { return this . _callSessionMethod < void > ( 'activateIme' , engine ) ; } param id switchToFrame ( id ) { return this . _callSessionMethod < void > ( 'switchToFrame' , id ) ; } param handle switchToWindow ( handle ) { return this . _callSessionMethod < void > ( 'switchToWindow' , handle ) ; } /**
     * Switches the currently focused frame to the parent of the currently
     * focused frame.
     */ switchToParentFrame ( ) { return this . _callSessionMethod < void > ( 'switchToParentFrame' ) ; } /**
     * Closes the currently focused window. In most environments, after the
     * window has been closed, it is necessary to explicitly switch to whatever
     * window is now focused.
     */ closeCurrentWindow ( ) { return this . _callSessionMethod < void > ( 'closeCurrentWindow' ) ; } param windowHandle param width param height setWindowSize ( width , height ) ; setWindowSize ( windowHandle , width , height ) ; setWindowSize ( ... args ) { return this . _callSessionMethod < void > ( 'setWindowSize' , ... args ) ; } param windowHandle returns getWindowSize ( _windowHandle ? ) { return this . _callSessionMethod < { width : number ; height : number ; } > ( 'getWindowSize' ) ; } param windowHandle param x param y setWindowPosition ( x , y ) ; setWindowPosition ( windowHandle , x , y ) ; setWindowPosition ( ... args ) { return this . _callSessionMethod < void > ( 'setWindowPosition' , ... args ) ; } param windowHandle returns getWindowPosition ( windowHandle ? ) { return this . _callSessionMethod < { x : number ; y : number ; } > ( 'getWindowPosition' , windowHandle ) ; } param windowHandle maximizeWindow ( windowHandle ? ) { return this . _callSessionMethod < void > ( 'maximizeWindow' , windowHandle ) ; } /**
     * Gets all cookies set on the current page.
     */ getCookies ( ) { return this . _callSessionMethod < WebDriverCookie [ ] > ( 'getCookies' ) ; } /**
     * Sets a cookie on the current page.
     */ setCookie ( cookie ) { return this . _callSessionMethod < void > ( 'setCookie' , cookie ) ; } /**
     * Clears all cookies for the current page.
     */ clearCookies ( ) { return this . _callSessionMethod < void > ( 'clearCookies' ) ; } param name deleteCookie ( name ) { return this . _callSessionMethod < void > ( 'deleteCookie' , name ) ; } /**
     * Gets the HTML loaded in the focused window/frame. This markup is
     * serialised by the remote environment so may not exactly match the HTML
     * provided by the Web server.
     */ getPageSource ( ) { return this . _callSessionMethod < string > ( 'getPageSource' ) ; } /**
     * Gets the title of the top-level browsing context of the current window
     * or tab.
     */ getPageTitle ( ) { return this . _callSessionMethod < string > ( 'getPageTitle' ) ; } /**
     * Gets the currently focused element from the focused window/frame.
     */ getActiveElement ( ) { return this . _callSessionMethod < Element > ( 'getActiveElement' ) ; } param keys pressKeys ( keys ) { return this . _callSessionMethod < void > ( 'pressKeys' , keys ) ; } /**
     * Gets the current screen orientation.
     */ getOrientation ( ) { return this . _callSessionMethod < 'portrait' | 'landscape' > ( 'getOrientation' ) ; } param orientation setOrientation ( orientation ) { return this . _callSessionMethod < void > ( 'setOrientation' , orientation ) ; } /**
     * Gets the text displayed in the currently active alert pop-up.
     */ getAlertText ( ) { return this . _callSessionMethod < string > ( 'getAlertText' ) ; } param text typeInPrompt ( text ) { return this . _callSessionMethod < void > ( 'typeInPrompt' , text ) ; } /**
     * Accepts an alert, prompt, or confirmation pop-up. Equivalent to clicking
     * the 'OK' button.
     */ acceptAlert ( ) { return this . _callSessionMethod < void > ( 'acceptAlert' ) ; } /**
     * Dismisses an alert, prompt, or confirmation pop-up. Equivalent to
     * clicking the 'OK' button of an alert pop-up or the 'Cancel' button of a
     * prompt or confirmation pop-up.
     */ dismissAlert ( ) { return this . _callSessionMethod < void > ( 'dismissAlert' ) ; } param element param xOffset param yOffset moveMouseTo ( element ? , xOffset ? , yOffset ? ) ; moveMouseTo ( xOffset ? , yOffset ? ) ; moveMouseTo ( ... args ) { return this . _callSessionMethod < void > ( 'moveMouseTo' , ... args ) ; } param button clickMouseButton ( button ? ) { return this . _callSessionMethod < void > ( 'clickMouseButton' , button ) ; } param button pressMouseButton ( button ? ) { return this . _callSessionMethod < void > ( 'pressMouseButton' , button ) ; } param button releaseMouseButton ( button ? ) { return this . _callSessionMethod < void > ( 'releaseMouseButton' , button ) ; } /**
     * Double-clicks the primary mouse button.
     */ doubleClick ( ) { return this . _callSessionMethod < void > ( 'doubleClick' ) ; } param element tap ( element ) { return this . _callSessionMethod < void > ( 'tap' , element ) ; } param x param y pressFinger ( x , y ) { return this . _callSessionMethod < void > ( 'pressFinger' , x , y ) ; } param x param y releaseFinger ( x , y ) { return this . _callSessionMethod < void > ( 'releaseFinger' , x , y ) ; } param x param y moveFinger ( x , y ) { return this . _callSessionMethod < void > ( 'moveFinger' , x , y ) ; } param element param xOffset param yOffset touchScroll ( xOffset , yOffset ) ; touchScroll ( element ? , xOffset ? , yOffset ? ) ; touchScroll ( ... args ) { return this . _callSessionMethod < void > ( 'touchScroll' , ... args ) ; } method param element doubleTap ( element ? ) { return this . _callSessionMethod < void > ( 'doubleTap' , element ) ; } method param element longTap ( element ? ) { return this . _callSessionMethod < void > ( 'longTap' , element ) ; } param element param xOffset param yOffset param speed flickFinger ( element , xOffset , yOffset , speed ? ) ; flickFinger ( xOffset , yOffset , speed ? ) ; flickFinger ( ... args ) { return this . _callSessionMethod < void > ( 'flickFinger' , ... args ) ; } returns getGeolocation ( ) { return this . _callSessionMethod < Geolocation > ( 'getGeolocation' ) ; } param location setGeolocation ( location ) { return this . _callSessionMethod < void > ( 'setGeolocation' , location ) ; } param type returns getLogsFor ( type ) { return this . _callSessionMethod < LogEntry [ ] > ( 'getLogsFor' , type ) ; } /**
     * Gets the types of logs that are currently available for retrieval from
     * the remote environment.
     */ getAvailableLogTypes ( ) { return this . _callSessionMethod < string [ ] > ( 'getAvailableLogTypes' ) ; } returns getApplicationCacheStatus ( ) { return this . _callSessionMethod < number > ( 'getApplicationCacheStatus' ) ; } /**
     * Terminates the session. No more commands will be accepted by the remote
     * after this point.
     */ quit ( ) { return this . _callSessionMethod < void > ( 'quit' ) ; } param using param value waitForDeleted ( using , value ) { return this . _callSessionMethod < void > ( 'waitForDeleted' , using , value ) ; } /**
     * Gets the timeout for [[Command.Command.executeAsync]] calls.
     */ getExecuteAsyncTimeout ( ) { return this . _callSessionMethod < number > ( 'getExecuteAsyncTimeout' ) ; } param ms setExecuteAsyncTimeout ( ms ) { return this . _callSessionMethod < void > ( 'setExecuteAsyncTimeout' , ms ) ; } /**
     * Gets the timeout for [[Command.Command.find]] calls.
     */ getFindTimeout ( ) { return this . _callSessionMethod < number > ( 'getFindTimeout' ) ; } param ms setFindTimeout ( ms ) { return this . _callSessionMethod < void > ( 'setFindTimeout' , ms ) ; } /**
     * Gets the timeout for [[Command.Command.get]] calls.
     */ getPageLoadTimeout ( ) { return this . _callSessionMethod < number > ( 'getPageLoadTimeout' ) ; } param ms setPageLoadTimeout ( ms ) { return this . _callSessionMethod < void > ( 'setPageLoadTimeout' , ms ) ; } /**
     * Clicks the element. This method works on both mouse and touch platforms.
     */ click ( ) { return this . _callElementMethod < void > ( 'click' ) ; } /**
     * Submits the element, if it is a form, or the form belonging to the
     * element, if it is a form element.
     */ submit ( ) { return this . _callElementMethod < void > ( 'submit' ) ; } /**
     * Gets the visible text within the element. `<br>` elements are converted
     * to line breaks in the returned text, and whitespace is normalised per
     * the usual XML/HTML whitespace normalisation rules.
     */ getVisibleText ( ) { return this . _callElementMethod < StringResult > ( 'getVisibleText' ) ; } param value type ( value ) { return this . _callElementMethod < void > ( 'type' , value ) ; } /**
     * Gets the tag name of the element. For HTML documents, the value is
     * always lowercase.
     */ getTagName ( ) { return this . _callElementMethod < StringResult > ( 'getTagName' ) ; } /**
     * Clears the value of a form element.
     */ clearValue ( ) { return this . _callElementMethod < void > ( 'clearValue' ) ; } /**
     * Returns whether or not a form element is currently selected (for
     * drop-down options and radio buttons), or whether or not the element is
     * currently checked (for checkboxes).
     */ isSelected ( ) { return this . _callElementMethod < boolean > ( 'isSelected' ) ; } /**
     * Returns whether or not a form element can be interacted with.
     */ isEnabled ( ) { return this . _callElementMethod < boolean > ( 'isEnabled' ) ; } param name returns getSpecAttribute ( name ) { return this . _callElementMethod < StringResult > ( 'getSpecAttribute' , name ) ; } param name returns getAttribute < S = StringResult > ( name ) { return this . _callElementMethod < S > ( 'getAttribute' , name ) ; } param name returns getProperty < T = any > ( name ) { return this . _callElementMethod < T > ( 'getProperty' , name ) ; } /**
     * Determines if this element is equal to another element.
     */ equals ( other ) { return this . _callElementMethod < boolean > ( 'equals' , other ) ; } /**
     * Returns whether or not the element would be visible to an actual user.
     * This means that the following types of elements are considered to be not
     * displayed:
     *
     * 1. Elements with `display: none`
     * 2. Elements with `visibility: hidden`
     * 3. Elements positioned outside of the viewport that cannot be scrolled
     *    into view
     * 4. Elements with `opacity: 0`
     * 5. Elements with no `offsetWidth` or `offsetHeight`
     */ isDisplayed ( ) { return this . _callElementMethod < boolean > ( 'isDisplayed' ) ; } /**
     * Gets the position of the element relative to the top-left corner of the
     * document, taking into account scrolling and CSS transformations (if they
     * are supported).
     */ getPosition ( ) { return this . _callElementMethod < { x : number ; y : number ; } > ( 'getPosition' ) ; } /**
     * Gets the size of the element, taking into account CSS transformations
     * (if they are supported).
     */ getSize ( ) { return this . _callElementMethod < { width : number ; height : number ; } > ( 'getSize' ) ; } param propertyName getComputedStyle ( propertyName ) { return this . _callElementMethod < StringResult > ( 'getComputedStyle' , propertyName ) ; } } /**
 * The method passed to Command `then` callbacks that can be used to manually
 * set the Command chain context
 */ export interface SetContextMethod { ( context ) : void ; } /**
 * The current Context of a Command
 */ export interface Context extends Array < any > { isSingle ? : boolean ; depth ? : number ; } const TOP_CONTEXT = [ ] ; TOP_CONTEXT . isSingle = true ; TOP_CONTEXT . depth = 0 ; let chaiAsPromised = null ; try { chaiAsPromised = require ( 'chai-as-promised' ) ; } catch ( error ) { } if ( chaiAsPromised ) { ( < any > chaiAsPromised ) . transferPromiseness = function ( assertion , promise ) { assertion . then = promise . then . bind ( promise ) ; for ( let method in promise ) { if ( typeof promise [ method ] === 'function' ) { assertion [ method ] = promise [ method ] . bind ( promise ) ; } } } ; } function getParent < S extends string | string [ ] > ( value ) { return value && value . parent ; }