1*8d307f52SEvan Baconimport { CommandError } from './errors'; 2*8d307f52SEvan Bacon 3*8d307f52SEvan Bacon/** Await for a given duration of milliseconds. */ 4*8d307f52SEvan Baconexport function delayAsync(timeout: number): Promise<void> { 5*8d307f52SEvan Bacon return new Promise((resolve) => setTimeout(resolve, timeout)); 6*8d307f52SEvan Bacon} 7*8d307f52SEvan Bacon 8*8d307f52SEvan Bacon/** Wait for a given action to return a truthy value. */ 9*8d307f52SEvan Baconexport async function waitForActionAsync<T>({ 10*8d307f52SEvan Bacon action, 11*8d307f52SEvan Bacon interval = 100, 12*8d307f52SEvan Bacon maxWaitTime = 20000, 13*8d307f52SEvan Bacon}: { 14*8d307f52SEvan Bacon action: () => T | Promise<T>; 15*8d307f52SEvan Bacon interval?: number; 16*8d307f52SEvan Bacon maxWaitTime?: number; 17*8d307f52SEvan Bacon}): Promise<T> { 18*8d307f52SEvan Bacon let complete: T; 19*8d307f52SEvan Bacon const start = Date.now(); 20*8d307f52SEvan Bacon do { 21*8d307f52SEvan Bacon const actionStartTime = Date.now(); 22*8d307f52SEvan Bacon complete = await action(); 23*8d307f52SEvan Bacon 24*8d307f52SEvan Bacon const actionTimeElapsed = Date.now() - actionStartTime; 25*8d307f52SEvan Bacon const remainingDelayInterval = interval - actionTimeElapsed; 26*8d307f52SEvan Bacon if (remainingDelayInterval > 0) { 27*8d307f52SEvan Bacon await delayAsync(remainingDelayInterval); 28*8d307f52SEvan Bacon } 29*8d307f52SEvan Bacon if (Date.now() - start > maxWaitTime) { 30*8d307f52SEvan Bacon break; 31*8d307f52SEvan Bacon } 32*8d307f52SEvan Bacon } while (!complete); 33*8d307f52SEvan Bacon 34*8d307f52SEvan Bacon return complete; 35*8d307f52SEvan Bacon} 36*8d307f52SEvan Bacon 37*8d307f52SEvan Bacon/** Resolves a given function or rejects if the provided timeout is passed. */ 38*8d307f52SEvan Baconexport function resolveWithTimeout<T>( 39*8d307f52SEvan Bacon action: () => Promise<T>, 40*8d307f52SEvan Bacon { 41*8d307f52SEvan Bacon timeout, 42*8d307f52SEvan Bacon errorMessage, 43*8d307f52SEvan Bacon }: { 44*8d307f52SEvan Bacon /** Duration in milliseconds to wait before asserting a timeout. */ 45*8d307f52SEvan Bacon timeout: number; 46*8d307f52SEvan Bacon /** Optional error message to use in the assertion. */ 47*8d307f52SEvan Bacon errorMessage?: string; 48*8d307f52SEvan Bacon } 49*8d307f52SEvan Bacon): Promise<T> { 50*8d307f52SEvan Bacon return new Promise((resolve, reject) => { 51*8d307f52SEvan Bacon setTimeout(() => { 52*8d307f52SEvan Bacon reject(new CommandError('TIMEOUT', errorMessage)); 53*8d307f52SEvan Bacon }, timeout); 54*8d307f52SEvan Bacon action().then(resolve, reject); 55*8d307f52SEvan Bacon }); 56*8d307f52SEvan Bacon} 57