@@ -30,6 +30,7 @@ import * as types from './types';
30
30
import { waitForTimeoutWasUsed } from './hints' ;
31
31
import { BrowserContext } from './browserContext' ;
32
32
import { rewriteErrorMessage } from './debug/stackTrace' ;
33
+ import { Progress } from './progress' ;
33
34
34
35
type ContextType = 'main' | 'utility' ;
35
36
type ContextData = {
@@ -441,37 +442,40 @@ export class Frame {
441
442
return selectors . _query ( this , selector ) ;
442
443
}
443
444
444
- async waitForSelector ( selector : string , options ? : types . WaitForElementOptions ) : Promise < dom . ElementHandle < Element > | null > {
445
- if ( options && ( options as any ) . visibility )
445
+ async waitForSelector ( selector : string , options : types . WaitForElementOptions = { } ) : Promise < dom . ElementHandle < Element > | null > {
446
+ if ( ( options as any ) . visibility )
446
447
throw new Error ( 'options.visibility is not supported, did you mean options.state?' ) ;
447
- if ( options && ( options as any ) . waitFor && ( options as any ) . waitFor !== 'visible' )
448
+ if ( ( options as any ) . waitFor && ( options as any ) . waitFor !== 'visible' )
448
449
throw new Error ( 'options.waitFor is not supported, did you mean options.state?' ) ;
449
- const { state = 'visible' } = ( options || { } ) ;
450
+ const { state = 'visible' } = options ;
450
451
if ( ! [ 'attached' , 'detached' , 'visible' , 'hidden' ] . includes ( state ) )
451
452
throw new Error ( `Unsupported waitFor option "${ state } "` ) ;
452
-
453
- const deadline = this . _page . _timeoutSettings . computeDeadline ( options ) ;
454
453
const { world, task } = selectors . _waitForSelectorTask ( selector , state ) ;
455
- const result = await this . _scheduleRerunnableTask ( task , world , deadline , `selector "${ selector } "${ state === 'attached' ? '' : ' to be ' + state } ` ) ;
456
- if ( ! result . asElement ( ) ) {
457
- result . dispose ( ) ;
458
- return null ;
459
- }
460
- const handle = result . asElement ( ) as dom . ElementHandle < Element > ;
461
- const mainContext = await this . _mainContext ( ) ;
462
- if ( handle && handle . _context !== mainContext ) {
463
- const adopted = await this . _page . _delegate . adoptElementHandle ( handle , mainContext ) ;
464
- handle . dispose ( ) ;
465
- return adopted ;
466
- }
467
- return handle ;
454
+ return Progress . runCancelableTask ( async progress => {
455
+ progress . log ( dom . inputLog , `Waiting for selector "${ selector } "${ state === 'attached' ? '' : ' to be ' + state } ...` ) ;
456
+ const result = await this . _scheduleRerunnableTask ( progress , world , task ) ;
457
+ if ( ! result . asElement ( ) ) {
458
+ result . dispose ( ) ;
459
+ return null ;
460
+ }
461
+ const handle = result . asElement ( ) as dom . ElementHandle < Element > ;
462
+ const mainContext = await this . _mainContext ( ) ;
463
+ if ( handle && handle . _context !== mainContext ) {
464
+ const adopted = await this . _page . _delegate . adoptElementHandle ( handle , mainContext ) ;
465
+ handle . dispose ( ) ;
466
+ return adopted ;
467
+ }
468
+ return handle ;
469
+ } , options , this . _page , this . _page . _timeoutSettings ) ;
468
470
}
469
471
470
472
async dispatchEvent ( selector : string , type : string , eventInit ?: Object , options ?: types . TimeoutOptions ) : Promise < void > {
471
- const deadline = this . _page . _timeoutSettings . computeDeadline ( options ) ;
472
473
const task = selectors . _dispatchEventTask ( selector , type , eventInit || { } ) ;
473
- const result = await this . _scheduleRerunnableTask ( task , 'main' , deadline , `selector "${ selector } "` ) ;
474
- result . dispose ( ) ;
474
+ return Progress . runCancelableTask ( async progress => {
475
+ progress . log ( dom . inputLog , `Dispatching "${ type } " event on selector "${ selector } "...` ) ;
476
+ const result = await this . _scheduleRerunnableTask ( progress , 'main' , task ) ;
477
+ result . dispose ( ) ;
478
+ } , options || { } , this . _page , this . _page . _timeoutSettings ) ;
475
479
}
476
480
477
481
async $eval < R , Arg > ( selector : string , pageFunction : types . FuncOn < Element , Arg , R > , arg : Arg ) : Promise < R > ;
@@ -702,7 +706,9 @@ export class Frame {
702
706
try {
703
707
const { world, task } = selectors . _waitForSelectorTask ( selector , 'attached' ) ;
704
708
this . _page . _log ( dom . inputLog , `waiting for the selector "${ selector } "` ) ;
705
- const handle = await this . _scheduleRerunnableTask ( task , world , deadline , `selector "${ selector } "` ) ;
709
+ const handle = await Progress . runCancelableTask (
710
+ progress => this . _scheduleRerunnableTask ( progress , world , task ) ,
711
+ options , this . _page , this . _page . _timeoutSettings ) ;
706
712
this . _page . _log ( dom . inputLog , `...got element for the selector` ) ;
707
713
const element = handle . asElement ( ) as dom . ElementHandle < Element > ;
708
714
try {
@@ -803,20 +809,23 @@ export class Frame {
803
809
async waitForFunction < R > ( pageFunction : types . Func1 < void , R > , arg ?: any , options ?: types . WaitForFunctionOptions ) : Promise < types . SmartHandle < R > > ;
804
810
async waitForFunction < R , Arg > ( pageFunction : types . Func1 < Arg , R > , arg : Arg , options : types . WaitForFunctionOptions = { } ) : Promise < types . SmartHandle < R > > {
805
811
const { polling = 'raf' } = options ;
806
- const deadline = this . _page . _timeoutSettings . computeDeadline ( options ) ;
807
812
if ( helper . isString ( polling ) )
808
813
assert ( polling === 'raf' , 'Unknown polling option: ' + polling ) ;
809
814
else if ( helper . isNumber ( polling ) )
810
815
assert ( polling > 0 , 'Cannot poll with non-positive interval: ' + polling ) ;
811
816
else
812
817
throw new Error ( 'Unknown polling options: ' + polling ) ;
813
818
const predicateBody = helper . isString ( pageFunction ) ? 'return (' + pageFunction + ')' : 'return (' + pageFunction + ')(arg)' ;
814
-
815
- const task = async ( context : dom . FrameExecutionContext ) => context . evaluateHandleInternal ( ( { injected, predicateBody, polling, arg } ) => {
816
- const innerPredicate = new Function ( 'arg' , predicateBody ) as ( arg : any ) => R ;
817
- return injected . poll ( polling , ( ) => innerPredicate ( arg ) ) ;
818
- } , { injected : await context . injectedScript ( ) , predicateBody, polling, arg } ) ;
819
- return this . _scheduleRerunnableTask ( task , 'main' , deadline ) ;
819
+ const task = async ( context : dom . FrameExecutionContext ) => {
820
+ const injectedScript = await context . injectedScript ( ) ;
821
+ return context . evaluateHandleInternal ( ( { injectedScript, predicateBody, polling, arg } ) => {
822
+ const innerPredicate = new Function ( 'arg' , predicateBody ) as ( arg : any ) => R ;
823
+ return injectedScript . poll ( polling , ( ) => innerPredicate ( arg ) ) ;
824
+ } , { injectedScript, predicateBody, polling, arg } ) ;
825
+ } ;
826
+ return Progress . runCancelableTask (
827
+ progress => this . _scheduleRerunnableTask ( progress , 'main' , task ) ,
828
+ options , this . _page , this . _page . _timeoutSettings ) ;
820
829
}
821
830
822
831
async title ( ) : Promise < string > {
@@ -836,9 +845,9 @@ export class Frame {
836
845
this . _parentFrame = null ;
837
846
}
838
847
839
- private _scheduleRerunnableTask < T > ( task : SchedulableTask < T > , contextType : ContextType , deadline : number , title ?: string ) : Promise < types . SmartHandle < T > > {
848
+ private _scheduleRerunnableTask < T > ( progress : Progress , contextType : ContextType , task : SchedulableTask < T > ) : Promise < types . SmartHandle < T > > {
840
849
const data = this . _contextData . get ( contextType ) ! ;
841
- const rerunnableTask = new RerunnableTask ( data , task , deadline , title ) ;
850
+ const rerunnableTask = new RerunnableTask ( data , progress , task ) ;
842
851
if ( data . context )
843
852
rerunnableTask . rerun ( data . context ) ;
844
853
return rerunnableTask . promise ;
@@ -893,38 +902,24 @@ export type SchedulableTask<T> = (context: dom.FrameExecutionContext) => Promise
893
902
894
903
class RerunnableTask < T > {
895
904
readonly promise : Promise < types . SmartHandle < T > > ;
896
- terminate : ( reason : Error ) => void = ( ) => { } ;
897
905
private _task : SchedulableTask < T > ;
898
906
private _resolve : ( result : types . SmartHandle < T > ) => void = ( ) => { } ;
899
907
private _reject : ( reason : Error ) => void = ( ) => { } ;
900
- private _terminatedPromise : Promise < Error > ;
908
+ private _progress : Progress ;
901
909
902
- constructor ( data : ContextData , task : SchedulableTask < T > , deadline : number , title ?: string ) {
910
+ constructor ( data : ContextData , progress : Progress , task : SchedulableTask < T > ) {
903
911
this . _task = task ;
912
+ this . _progress = progress ;
904
913
data . rerunnableTasks . add ( this ) ;
905
-
906
- // Since page navigation requires us to re-install the pageScript, we should track
907
- // timeout on our end.
908
- const timeoutError = new TimeoutError ( `waiting for ${ title || 'function' } failed: timeout exceeded. Re-run with the DEBUG=pw:input env variable to see the debug log.` ) ;
909
- let timeoutTimer : NodeJS . Timer | undefined ;
910
- this . _terminatedPromise = new Promise ( resolve => {
911
- timeoutTimer = setTimeout ( ( ) => resolve ( timeoutError ) , helper . timeUntilDeadline ( deadline ) ) ;
912
- this . terminate = resolve ;
913
- } ) ;
914
-
915
- // This promise is either resolved with the task result, or rejected with a meaningful
916
- // evaluation error.
917
- const resultPromise = new Promise < types . SmartHandle < T > > ( ( resolve , reject ) => {
914
+ this . promise = progress . race ( new Promise < types . SmartHandle < T > > ( ( resolve , reject ) => {
915
+ // The task is either resolved with a value, or rejected with a meaningful evaluation error.
918
916
this . _resolve = resolve ;
919
917
this . _reject = reject ;
920
- } ) ;
921
- const failPromise = this . _terminatedPromise . then ( error => Promise . reject ( error ) ) ;
918
+ } ) ) ;
919
+ }
922
920
923
- this . promise = Promise . race ( [ resultPromise , failPromise ] ) . finally ( ( ) => {
924
- if ( timeoutTimer )
925
- clearTimeout ( timeoutTimer ) ;
926
- data . rerunnableTasks . delete ( this ) ;
927
- } ) ;
921
+ terminate ( error : Error ) {
922
+ this . _progress . cancel ( error ) ;
928
923
}
929
924
930
925
async rerun ( context : dom . FrameExecutionContext ) {
@@ -938,7 +933,7 @@ class RerunnableTask<T> {
938
933
poll = null ;
939
934
copy . evaluate ( p => p . cancel ( ) ) . catch ( e => { } ) . then ( ( ) => copy . dispose ( ) ) ;
940
935
} ;
941
- this . _terminatedPromise . then ( cancelPoll ) ;
936
+ this . _progress . cleanupWhenCanceled ( cancelPoll ) ;
942
937
943
938
try {
944
939
poll = await this . _task ( context ) ;
0 commit comments