import { browser , ElementArrayFinder , ElementFinder , ExpectedConditions as EC } from 'protractor' ; import * as mixins from '../mixins' ; import { DEFAULT_WAIT } from '../support' ; type NumberComparerFn = ( x : number ) => boolean ; type NumberComparer = number | NumberComparerFn ; function makeNumberComparer ( compare ) { if ( typeof compare == 'number' ) { return ( n ) => n >= compare ; } return compare ; } /**
 * to use with browser.wait to wait for multiple elements to present
 * e.g.
 *  browser.wait(untilCount($('foobar'), n => n >= 5 ))
 *  browser.wait(untilCount($('foobar'), 5)) // same as above
 */ function untilCount ( elements , expectation ) { let compare = makeNumberComparer ( expectation ) ; return ( ) => elements . count ( ) . then ( compare ) ; } export interface BaseElementInterface { untilDisplayed ( wait ? ) : Promise < any > ; untilPresent ( wait ? ) : Promise < any > ; untilClickable ( wait ? ) : Promise < any > ; clickWhenReady ( wait ? ) : Promise < any > ; } export class BaseElement extends ElementFinder implements BaseElementInterface { name : string = '' ; log ! : ( action : string , ... msg : string [ ] ) => void ; debug ! : ( context : string , ... msg : string [ ] ) => void ; fail ! : ( action : string , ... msg : string [ ] ) => void ; param { ElementFinder } elementFinder param { string } name constructor ( wrapped , name = 'unnamed' ) { super ( wrapped . browser_ , wrapped . elementArrayFinder_ ) ; this . name = name ; } async untilClickable ( timeout ? ) { try { await this . waitFor ( 'clickable' , EC . elementToBeClickable ( this ) , timeout ) ; } catch ( e ) { this . fail ( 'ERROR Element: ' , this . name , 'is not clickable' ) ; } } async untilPresent ( timeout ? ) { try { await this . waitFor ( 'present' , EC . presenceOf ( this ) , timeout ) ; } catch ( e ) { this . fail ( 'ERROR Element: ' , this . name , 'is not present' ) ; } } async untilDisplayed ( timeout ? ) { try { await this . waitFor ( 'visible' , EC . visibilityOf ( this ) , timeout ) ; } catch ( e ) { this . fail ( 'ERROR Element: ' , this . name , 'is not displayed' ) ; } } async untilTextIsPresent ( text , timeout ? ) { try { let condition = EC . textToBePresentInElement ( this , text ) ; await this . waitFor ( `text ${ text }` , condition , timeout ) ; } catch ( e ) { this . fail ( 'ERROR Element: ' , this . name , 'text is not present' ) ; } } async untilTextIsPresentInValue ( text , timeout ? ) { try { let condition = EC . textToBePresentInElementValue ( this , text ) ; await this . waitFor ( `text ${ text }` , condition , timeout ) ; } catch ( e ) { this . fail ( 'ERROR Element: ' , this . name , 'text is not present in value' ) ; } } async untilHidden ( timeout ? ) { try { await this . waitFor ( 'hidden' , EC . invisibilityOf ( this ) , timeout ) ; } catch ( e ) { this . debug ( 'Element: ' , this . name , ' no longer exists.' ) ; } } async untilAbsent ( timeout ? ) { await this . waitFor ( 'absence' , EC . stalenessOf ( this ) , timeout ) ; } async clickWhenReady ( timeout ? ) { await this . run ( 'click' , async ( ) => { await this . untilDisplayed ( timeout ) ; await this . untilClickable ( timeout ) ; await this . click ( ) ; } ) ; } async ready ( ) { await this . untilDisplayed ( ) ; } private async waitFor ( msg , condition , timeout ? ) { let wait = timeout || DEFAULT_WAIT ; this . debug ( `waiting for "${ msg }"` , `  | timeout: '${ wait }'` ) ; await browser . wait ( condition , wait ) ; this . debug ( `waiting for "${ msg }"` , '  - OK' ) ; } async run ( msg , fn ) { this . debug ( msg , '- ACTION STARTED' ) ; await fn ( ) ; this . debug ( msg , '- DONE' ) ; } async getTextWhenReady ( timeout ? ) { await this . untilDisplayed ( timeout ) ; return this . getText ( ) ; } async scrollIntoView ( ) { await browser . executeScript ( 'arguments[0].scrollIntoView(true)' , this . getWebElement ( ) ) ; } } export class BaseElementArray extends ElementArrayFinder { log ! : ( action : string , ... msg : string [ ] ) => void ; debug ! : ( context : string , ... msg : string [ ] ) => void ; constructor ( wrapped , name = 'unnamed' ) { super ( wrapped . browser_ , wrapped . getWebElements , wrapped . locator_ , wrapped . actionResults_ ) ; this . name = name ; } async untilCount ( compare , wait ? , msg ? ) { await browser . wait ( untilCount ( this , compare ) , wait , msg ) ; } async ready ( count = 1 ) { await this . untilCount ( count ) ; await this . each ( async ( item , index ) => { let tempItem = new BaseElement ( item , this . name + ' - ' + index ) ; await tempItem . ready ( ) ; } ) ; } async getTextWhenReady ( ) { await this . ready ( ) ; return this . getText ( ) ; } async untilHidden ( ) { await this . each ( async ( item , index ) => { let tempItem = new BaseElement ( item , this . name + ' - ' + index ) ; try { await tempItem . untilHidden ( ) ; } catch ( e ) { this . debug ( 'Element: ' , tempItem . name , ' no longer exists.' ) ; } } ) ; } } export class Clickable extends BaseElement { async ready ( ) { await this . run ( 'ready' , async ( ) => { await super . ready ( ) ; await this . untilClickable ( ) ; } ) ; } } mixins . applyMixins ( BaseElement , [ mixins . Logging ] ) ; mixins . applyMixins ( BaseElementArray , [ mixins . Logging ] ) ;