@@ -19,9 +19,9 @@ import * as fs from 'fs';
19
19
import * as util from 'util' ;
20
20
import { ConsoleMessage } from './console' ;
21
21
import * as dom from './dom' ;
22
- import { TimeoutError } from './errors' ;
22
+ import { TimeoutError , NotConnectedError } from './errors' ;
23
23
import { Events } from './events' ;
24
- import { assert , helper , RegisteredListener } from './helper' ;
24
+ import { assert , helper , RegisteredListener , debugInput } from './helper' ;
25
25
import * as js from './javascript' ;
26
26
import * as network from './network' ;
27
27
import { Page } from './page' ;
@@ -693,72 +693,82 @@ export class Frame {
693
693
return result ! ;
694
694
}
695
695
696
+ private async _retryWithSelectorIfNotConnected < R > (
697
+ selector : string , options : types . TimeoutOptions ,
698
+ action : ( handle : dom . ElementHandle < Element > , deadline : number ) => Promise < R > ) : Promise < R > {
699
+ const deadline = this . _page . _timeoutSettings . computeDeadline ( options ) ;
700
+ while ( ! helper . isPastDeadline ( deadline ) ) {
701
+ try {
702
+ const { world, task } = selectors . _waitForSelectorTask ( selector , 'attached' , deadline ) ;
703
+ const handle = await this . _scheduleRerunnableTask ( task , world , deadline , `selector "${ selector } "` ) ;
704
+ const element = handle . asElement ( ) as dom . ElementHandle < Element > ;
705
+ try {
706
+ return await action ( element , deadline ) ;
707
+ } finally {
708
+ element . dispose ( ) ;
709
+ }
710
+ } catch ( e ) {
711
+ if ( ! ( e instanceof NotConnectedError ) )
712
+ throw e ;
713
+ debugInput ( 'Element was detached from the DOM, retrying' ) ;
714
+ }
715
+ }
716
+ throw new TimeoutError ( `waiting for selector "${ selector } " failed: timeout exceeded` ) ;
717
+ }
718
+
696
719
async click ( selector : string , options : dom . ClickOptions & types . PointerActionWaitOptions & types . NavigatingActionWaitOptions = { } ) {
697
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
698
- await handle . click ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
699
- handle . dispose ( ) ;
720
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
721
+ ( handle , deadline ) => handle . click ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
700
722
}
701
723
702
724
async dblclick ( selector : string , options : dom . MultiClickOptions & types . PointerActionWaitOptions & types . NavigatingActionWaitOptions = { } ) {
703
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
704
- await handle . dblclick ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
705
- handle . dispose ( ) ;
725
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
726
+ ( handle , deadline ) => handle . dblclick ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
706
727
}
707
728
708
729
async fill ( selector : string , value : string , options : types . NavigatingActionWaitOptions = { } ) {
709
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
710
- await handle . fill ( value , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
711
- handle . dispose ( ) ;
730
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
731
+ ( handle , deadline ) => handle . fill ( value , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
712
732
}
713
733
714
- async focus ( selector : string , options ?: types . TimeoutOptions ) {
715
- const { handle } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
716
- await handle . focus ( ) ;
717
- handle . dispose ( ) ;
734
+ async focus ( selector : string , options : types . TimeoutOptions = { } ) {
735
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
736
+ ( handle , deadline ) => handle . focus ( ) ) ;
718
737
}
719
738
720
- async hover ( selector : string , options ?: dom . PointerActionOptions & types . PointerActionWaitOptions ) {
721
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
722
- await handle . hover ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
723
- handle . dispose ( ) ;
739
+ async hover ( selector : string , options : dom . PointerActionOptions & types . PointerActionWaitOptions = { } ) {
740
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
741
+ ( handle , deadline ) => handle . hover ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
724
742
}
725
743
726
- async selectOption ( selector : string , values : string | dom . ElementHandle | types . SelectOption | string [ ] | dom . ElementHandle [ ] | types . SelectOption [ ] , options ?: types . NavigatingActionWaitOptions ) : Promise < string [ ] > {
727
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
728
- const result = await handle . selectOption ( values , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
729
- handle . dispose ( ) ;
730
- return result ;
744
+ async selectOption ( selector : string , values : string | dom . ElementHandle | types . SelectOption | string [ ] | dom . ElementHandle [ ] | types . SelectOption [ ] , options : types . NavigatingActionWaitOptions = { } ) : Promise < string [ ] > {
745
+ return await this . _retryWithSelectorIfNotConnected ( selector , options ,
746
+ ( handle , deadline ) => handle . selectOption ( values , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
731
747
}
732
748
733
- async setInputFiles ( selector : string , files : string | types . FilePayload | string [ ] | types . FilePayload [ ] , options ?: types . NavigatingActionWaitOptions ) : Promise < void > {
734
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
735
- const result = await handle . setInputFiles ( files , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
736
- handle . dispose ( ) ;
737
- return result ;
749
+ async setInputFiles ( selector : string , files : string | types . FilePayload | string [ ] | types . FilePayload [ ] , options : types . NavigatingActionWaitOptions = { } ) : Promise < void > {
750
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
751
+ ( handle , deadline ) => handle . setInputFiles ( files , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
738
752
}
739
753
740
- async type ( selector : string , text : string , options ?: { delay ?: number } & types . NavigatingActionWaitOptions ) {
741
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
742
- await handle . type ( text , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
743
- handle . dispose ( ) ;
754
+ async type ( selector : string , text : string , options : { delay ?: number } & types . NavigatingActionWaitOptions = { } ) {
755
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
756
+ ( handle , deadline ) => handle . type ( text , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
744
757
}
745
758
746
- async press ( selector : string , key : string , options ?: { delay ?: number } & types . NavigatingActionWaitOptions ) {
747
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
748
- await handle . press ( key , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
749
- handle . dispose ( ) ;
759
+ async press ( selector : string , key : string , options : { delay ?: number } & types . NavigatingActionWaitOptions = { } ) {
760
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
761
+ ( handle , deadline ) => handle . press ( key , helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
750
762
}
751
763
752
- async check ( selector : string , options ?: types . PointerActionWaitOptions & types . NavigatingActionWaitOptions ) {
753
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
754
- await handle . check ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
755
- handle . dispose ( ) ;
764
+ async check ( selector : string , options : types . PointerActionWaitOptions & types . NavigatingActionWaitOptions = { } ) {
765
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
766
+ ( handle , deadline ) => handle . check ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
756
767
}
757
768
758
- async uncheck ( selector : string , options ?: types . PointerActionWaitOptions & types . NavigatingActionWaitOptions ) {
759
- const { handle, deadline } = await this . _waitForSelectorInUtilityContext ( selector , options ) ;
760
- await handle . uncheck ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ;
761
- handle . dispose ( ) ;
769
+ async uncheck ( selector : string , options : types . PointerActionWaitOptions & types . NavigatingActionWaitOptions = { } ) {
770
+ await this . _retryWithSelectorIfNotConnected ( selector , options ,
771
+ ( handle , deadline ) => handle . uncheck ( helper . optionsWithUpdatedTimeout ( options , deadline ) ) ) ;
762
772
}
763
773
764
774
async waitFor ( selectorOrFunctionOrTimeout : ( string | number | Function ) , options : types . WaitForFunctionOptions & types . WaitForElementOptions = { } , arg ?: any ) : Promise < js . JSHandle | null > {
@@ -773,14 +783,6 @@ export class Frame {
773
783
return Promise . reject ( new Error ( 'Unsupported target type: ' + ( typeof selectorOrFunctionOrTimeout ) ) ) ;
774
784
}
775
785
776
- private async _waitForSelectorInUtilityContext ( selector : string , options ?: types . WaitForElementOptions ) : Promise < { handle : dom . ElementHandle < Element > , deadline : number } > {
777
- const { waitFor = 'attached' } = options || { } ;
778
- const deadline = this . _page . _timeoutSettings . computeDeadline ( options ) ;
779
- const { world, task } = selectors . _waitForSelectorTask ( selector , waitFor , deadline ) ;
780
- const result = await this . _scheduleRerunnableTask ( task , world , deadline , `selector "${ selectorToString ( selector , waitFor ) } "` ) ;
781
- return { handle : result . asElement ( ) as dom . ElementHandle < Element > , deadline } ;
782
- }
783
-
784
786
async waitForFunction < R , Arg > ( pageFunction : types . Func1 < Arg , R > , arg : Arg , options ?: types . WaitForFunctionOptions ) : Promise < types . SmartHandle < R > > ;
785
787
async waitForFunction < R > ( pageFunction : types . Func1 < void , R > , arg ?: any , options ?: types . WaitForFunctionOptions ) : Promise < types . SmartHandle < R > > ;
786
788
async waitForFunction < R , Arg > ( pageFunction : types . Func1 < Arg , R > , arg : Arg , options : types . WaitForFunctionOptions = { } ) : Promise < types . SmartHandle < R > > {
0 commit comments