import * as action from '../actions' ; import { PlaywrightFluent } from '../fluent-api' ; import { ClickOptions , defaultClickOptions , defaultHoverOptions , defaultVerboseOptions , HoverOptions , Point , SelectOptionInfo , SerializableDOMRect , VerboseOptions , } from '../actions' ; import { ElementHandle } from 'playwright' ; type Action = ( handles : ElementHandle < Element > [ ] ) => Promise < ElementHandle < Element > [ ] > ; interface ActionInfoWithoutParam { name : 'parent' | 'nextSibling' | 'previousSibling' | 'unknown' ; } interface ActionInfoWithSelector { name : 'querySelectorAllInPage' | 'find' ; selector : string ; } interface ActionInfoWithText { name : 'withText' | 'withExactText' | 'withValue' | 'withPlaceholder' ; text : string ; } interface ActionInfoWithIndex { name : 'nth' ; index : number ; } type ActionInfo = ActionInfoWithoutParam | ActionInfoWithSelector | ActionInfoWithText | ActionInfoWithIndex ; interface SelectorState { actions : ActionInfo [ ] ; chainingHistory : string ; } export class SelectorFluent { private chainingHistory = '' ; private pwf : PlaywrightFluent ; private actionInfos : ActionInfo [ ] = [ ] ; private getActionFrom ( actionInfo ) { switch ( actionInfo . name ) { case 'querySelectorAllInPage' : return ( ) => action . querySelectorAllInPage ( actionInfo . selector , this . pwf . currentPageOrFrame ( ) ) ; case 'find' : return ( handles ) => action . querySelectorAllFromHandles ( actionInfo . selector , [ ... handles ] ) ; case 'nth' : return ( handles ) => action . getNthHandle ( actionInfo . index , [ ... handles ] ) ; case 'parent' : return ( handles ) => action . getParentsOf ( [ ... handles ] ) ; case 'nextSibling' : return ( handles ) => action . getNextSiblingsOf ( [ ... handles ] ) ; case 'previousSibling' : return ( handles ) => action . getPreviousSiblingsOf ( [ ... handles ] ) ; case 'withText' : return ( handles ) => action . getHandlesWithText ( actionInfo . text , [ ... handles ] ) ; case 'withExactText' : return ( handles ) => action . getHandlesWithExactText ( actionInfo . text , [ ... handles ] ) ; case 'withValue' : return ( handles ) => action . getHandlesWithValue ( actionInfo . text , [ ... handles ] ) ; case 'withPlaceholder' : return ( handles ) => action . getHandlesWithPlaceholder ( actionInfo . text , [ ... handles ] ) ; default : throw new Error ( `Action '${ actionInfo . name }' is not yet implemented` ) ; } } private async executeActions ( ) { let handles = [ ] ; for ( let index = 0 ; index < this . actionInfos . length ; index ++ ) { const action = this . getActionFrom ( this . actionInfos [ index ] ) ; handles = await action ( [ ... handles ] ) ; } return handles ; } returns { Promise < ElementHandle < Element > [ ] > } memberof public async getAllHandles ( ) { const handles = await this . executeActions ( ) ; return handles ; } param { ( selector : SelectorFluent , index : number ) => Promise < void > } func returns { Promise < void > } memberof example public async forEach ( func ) { const selectorsCount = await this . count ( ) ; for ( let i = 1 ; i <= selectorsCount ; i ++ ) { const selectorItem = this . nth ( i ) ; await func ( selectorItem , i ) ; } } returns { Promise < ElementHandle < Element > | null > } memberof obsolete public async getFirstHandleOrNull ( ) { const handles = await this . executeActions ( ) ; if ( handles . length === 0 ) { return null ; } return handles [ 0 ] ; } returns { Promise < ElementHandle < Element > | null > } memberof public async getHandle ( ) { const handles = await this . executeActions ( ) ; if ( handles . length === 0 ) { return null ; } return handles [ 0 ] ; } returns { Promise < number > } memberof public async count ( ) { const handles = await this . executeActions ( ) ; return handles . length ; } /**
     *
     */ constructor ( selector , pwf , stringifiedState ? ) { this . pwf = pwf ; if ( stringifiedState ) { const state = JSON . parse ( stringifiedState ) as SelectorState ; this . chainingHistory = state . chainingHistory ; this . actionInfos = state . actions ; return ; } this . chainingHistory = `selector(${ selector })` ; this . actionInfos . push ( { name : 'querySelectorAllInPage' , selector } ) ; } public toString ( ) { return this . chainingHistory ; } private createSelectorFrom ( selector , actions , chainingHistory ) { const state = { actions , chainingHistory , } ; return new SelectorFluent ( selector , this . pwf , JSON . stringify ( state ) ) ; } public find ( selector ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'find' , selector } ) ; const chainingHistory = `${ this . chainingHistory }
  .find(${ selector })` ; return this . createSelectorFrom ( selector , actions , chainingHistory ) ; } param { string } text returns { SelectorFluent } memberof public withText ( text ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'withText' , text } ) ; const chainingHistory = `${ this . chainingHistory }
  .withText(${ text })` ; return this . createSelectorFrom ( text , actions , chainingHistory ) ; } param { string } text returns { SelectorFluent } memberof public withExactText ( text ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'withExactText' , text } ) ; const chainingHistory = `${ this . chainingHistory }
  .withExactText(${ text })` ; return this . createSelectorFrom ( text , actions , chainingHistory ) ; } param { string } text returns { SelectorFluent } memberof public withValue ( text ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'withValue' , text } ) ; const chainingHistory = `${ this . chainingHistory }
  .withValue(${ text })` ; return this . createSelectorFrom ( text , actions , chainingHistory ) ; } param { string } text returns { SelectorFluent } memberof public withPlaceholder ( text ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'withPlaceholder' , text } ) ; const chainingHistory = `${ this . chainingHistory }
  .withPlaceholder(${ text })` ; return this . createSelectorFrom ( text , actions , chainingHistory ) ; } public parent ( ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'parent' } ) ; const chainingHistory = `${ this . chainingHistory }
  .parent()` ; return this . createSelectorFrom ( '' , actions , chainingHistory ) ; } public nextSibling ( ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'nextSibling' } ) ; const chainingHistory = `${ this . chainingHistory }
  .nextSibling()` ; return this . createSelectorFrom ( '' , actions , chainingHistory ) ; } public previousSibling ( ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'previousSibling' } ) ; const chainingHistory = `${ this . chainingHistory }
  .previousSibling()` ; return this . createSelectorFrom ( '' , actions , chainingHistory ) ; } param { number } index returns { SelectorFluent } memberof example public nth ( index ) { const actions = [ ... this . actionInfos ] ; actions . push ( { name : 'nth' , index } ) ; const chainingHistory = `${ this . chainingHistory }
  .nth(${ index })` ; return this . createSelectorFrom ( '' , actions , chainingHistory ) ; } returns { Promise < boolean > } memberof public async exists ( ) { const handle = await this . getHandle ( ) ; if ( handle === null ) { return false ; } return true ; } returns { Promise < boolean > } memberof public async doesNotExist ( ) { const handle = await this . getHandle ( ) ; if ( handle === null ) { return true ; } return false ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isVisible ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const isElementVisible = await action . isHandleVisible ( handle , verboseOptions ) ; return isElementVisible ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isVisibleInViewport ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const isElementVisible = await action . isHandleVisibleInViewport ( handle , verboseOptions ) ; return isElementVisible ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isNotVisible ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const isElementNotVisible = await action . isHandleNotVisible ( handle , verboseOptions ) ; return isElementNotVisible ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isNotVisibleInViewport ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const isElementNotVisible = await action . isHandleNotVisibleInViewport ( handle , verboseOptions ) ; return isElementNotVisible ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isEnabled ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const isElementEnabled = await action . isHandleEnabled ( handle , verboseOptions ) ; return isElementEnabled ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isDisabled ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const isElementDisabled = await action . isHandleDisabled ( handle , verboseOptions ) ; return isElementDisabled ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isReadOnly ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const isElementReadOnly = await action . isHandleReadOnly ( handle , verboseOptions ) ; return isElementReadOnly ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isNotReadOnly ( options = defaultVerboseOptions ) { const isReadOnly = await this . isReadOnly ( options ) ; return ! isReadOnly ; } public async innerText ( ) { const handle = await this . getHandle ( ) ; const innerText = await action . getInnerTextOfHandle ( handle ) ; return innerText ; } public async value ( ) { const handle = await this . getHandle ( ) ; const value = await action . getValueOfHandle ( handle ) ; return value ; } public async classList ( ) { const handle = await this . getHandle ( ) ; const result = await action . getClassListOfHandle ( handle ) ; return result ; } public async getAttribute ( attributeName ) { const handle = await this . getHandle ( ) ; const result = await action . getAttributeOfHandle ( attributeName , handle ) ; return result ; } returns { ( Promise < string | null > ) } memberof public async placeholder ( ) { return this . getAttribute ( 'placeholder' ) ; } returns { ( Promise < SerializableDOMRect | null > ) } memberof public async clientRectangle ( ) { const handle = await this . getHandle ( ) ; const result = await action . getClientRectangleOfHandle ( handle ) ; return result ; } returns { ( Promise < Point | null > ) } memberof public async position ( ) { const handle = await this . getHandle ( ) ; const result = await action . getClientRectangleOfHandle ( handle ) ; if ( result ) { const x = result . left + result . width / 2 ; const y = result . top + result . height / 2 ; return { x , y , } ; } return null ; } returns { ( Promise < Point | null > ) } memberof public async leftPosition ( ) { const handle = await this . getHandle ( ) ; const result = await action . getClientRectangleOfHandle ( handle ) ; if ( result ) { const x = result . left ; const y = result . top + result . height / 2 ; return { x , y , } ; } return null ; } returns { ( Promise < Point | null > ) } memberof public async rightPosition ( ) { const handle = await this . getHandle ( ) ; const result = await action . getClientRectangleOfHandle ( handle ) ; if ( result ) { const x = result . left + result . width ; const y = result . top + result . height / 2 ; return { x , y , } ; } return null ; } param { string } attributeName param { string } expectedAttributeValue returns { Promise < boolean > } memberof public async hasAttributeWithValue ( attributeName , expectedAttributeValue ) { const handle = await this . getHandle ( ) ; const result = await action . hasHandleAttribute ( handle , attributeName , expectedAttributeValue ) ; return result ; } param { string } expectedClass returns { Promise < boolean > } memberof public async hasClass ( expectedClass ) { const handle = await this . getHandle ( ) ; const result = await action . hasHandleClass ( handle , expectedClass ) ; return result ; } param { string } expectedClass returns { Promise < boolean > } memberof public async doesNotHaveClass ( expectedClass ) { const handle = await this . getHandle ( ) ; const result = await action . hasNotHandleClass ( handle , expectedClass ) ; return result ; } param { Partial < VerboseOptions > } options returns { Promise < boolean > } memberof public async isChecked ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const result = await action . isHandleChecked ( handle , verboseOptions ) ; return result ; } public async isUnchecked ( options = defaultVerboseOptions ) { const verboseOptions = { ... defaultVerboseOptions , options , } ; const handle = await this . getHandle ( ) ; const result = await action . isHandleUnchecked ( handle , verboseOptions ) ; return result ; } public async options ( ) { const handle = await this . getHandle ( ) ; const result = await action . getAllOptionsOfHandle ( handle , this . toString ( ) ) ; return result ; } public async allSelectedOptions ( ) { const handle = await this . getHandle ( ) ; const allOptions = await action . getAllOptionsOfHandle ( handle , this . toString ( ) ) ; return allOptions . filter ( ( option ) => option . selected ) ; } public async selectedOption ( ) { const handle = await this . getHandle ( ) ; const allOptions = await action . getAllOptionsOfHandle ( handle , this . toString ( ) ) ; const selectedOption = allOptions . find ( ( option ) => option . selected ) ; return selectedOption ; } param { Partial < HoverOptions > } options returns { Promise < void > } memberof public async hover ( options = defaultHoverOptions ) { const handle = await this . getHandle ( ) ; const hoverOptions = { ... defaultHoverOptions , ... options , } as HoverOptions ; await action . hoverOnHandle ( handle , this . toString ( ) , this . pwf . currentPageOrFrame ( ) , hoverOptions ) ; } param { Partial < ClickOptions > } options returns { Promise < void > } memberof public async click ( options = defaultClickOptions ) { const handle = await this . getHandle ( ) ; const clickOptions = { ... defaultClickOptions , ... options , } as ClickOptions ; await action . clickOnHandle ( handle , this . toString ( ) , this . pwf . currentPageOrFrame ( ) , clickOptions ) ; } }