import SaucelabsAPI , { SauceConnectInstance } from 'saucelabs' ; const MAX_SC_START_TRIALS = 3 ; /**
 * Service that can be used to create a SauceConnect tunnel automatically. This can be used
 * in case developers don't set up the tunnel using the plain SauceConnect binaries.
 */ export function SauceConnect ( emitter , logger ) { const log = logger . create ( 'launcher.SauceConnect' ) ; let activeInstancePromise = null ; let scStartTrials = 0 ; this . establishTunnel = async ( seleniumCapabilities , sauceConnectOptions ) => { if ( activeInstancePromise ) { return activeInstancePromise ; } const api = new SaucelabsAPI ( seleniumCapabilities ) ; return activeInstancePromise = api . startSauceConnect ( { logger : log . debug . bind ( log ) , ... sauceConnectOptions } ) . catch ( ( err ) => { ++ scStartTrials ; /**
             * fail starting Sauce Connect eventually
             */ if ( ! err . message . includes ( 'ENOENT' ) || scStartTrials >= MAX_SC_START_TRIALS ) { throw err ; } log . debug ( `Failed to start Sauce Connect Proxy due to ${ err . stack }` ) ; log . debug ( `Retrying ${ scStartTrials }/${ MAX_SC_START_TRIALS }` ) ; return this . establishTunnel ( seleniumCapabilities , sauceConnectOptions ) ; } ) ; } ; emitter . on ( 'exit' , async ( doneFn ) => { if ( activeInstancePromise ) { log . debug ( 'Shutting down Sauce Connect' ) ; try { const tunnelInstance = await activeInstancePromise ; await tunnelInstance . close ( ) ; } catch ( err ) { log . error ( `Could not close Sauce Connect Tunnel. Failure message: ${ err . stack }` ) ; } } doneFn ( ) ; } ) ; }