import { remote , BrowserObject } from 'webdriverio' ; import SauceLabsAPI from 'saucelabs' ; import { processConfig } from "../process-config" ; import { BrowserMap } from "../browser-info" ; import { waitUntil } from "../utils" ; let connectedDrivers = new Map ( ) ; export function SaucelabsLauncher ( args , config , sauceConnect , browserMap , logger , baseLauncherDecorator , captureTimeoutLauncherDecorator , retryLauncherDecorator ) { baseLauncherDecorator ( this ) ; captureTimeoutLauncherDecorator ( this ) ; retryLauncherDecorator ( this ) ; connectedDrivers . set ( this . id , null ) ; const log = logger . create ( 'SaucelabsLauncher' ) ; const { startConnect , sauceConnectOptions , seleniumCapabilities , browserName } = processConfig ( config , args ) ; this . name = browserName + ' on SauceLabs' ; let pendingHeartBeat ; const heartbeat = ( ) => { const driver = connectedDrivers . get ( this . id ) ; pendingHeartBeat = setTimeout ( async ( ) => { if ( ! driver ) { return ; } try { await driver . getTitle ( ) ; log . debug ( 'Heartbeat to Sauce Labs (%s) - fetching title' , browserName ) ; heartbeat ( ) ; } catch ( ign ) { clearTimeout ( pendingHeartBeat ) ; } return ; } , 60000 ) ; } ; const uploadJobResult = async ( browserData , browserName ) => { const { sessionId , username , accessKey , region , results } = browserData ; const api = new SauceLabsAPI ( { user : username , key : accessKey , region : region , } ) ; try { let oldLogs ; await waitUntil ( { condition : async ( ) => { log . info ( `Check if 'log.json' for browser '${ browserName }' has already been stored.` ) ; oldLogs = await api . downloadJobAsset ( sessionId , 'log.json' ) ; return oldLogs ; } , maxRetries : 25 , } ) ; if ( oldLogs ) { await api . uploadJobAssets ( sessionId , { files : [ { filename : 'log.json' , data : results , } , { filename : 'old-log.json' , data : { someLog : oldLogs } } , ] , } ) ; } } catch ( e ) { log . error ( `There was an error uploading the data to SauceLabs: ${ e . message }` ) ; } } ; this . on ( 'start' , async ( pageUrl ) => { if ( startConnect ) { try { await sauceConnect . establishTunnel ( seleniumCapabilities , sauceConnectOptions ) ; } catch ( error ) { log . error ( error ) ; this . _done ( 'failure' ) ; return ; } } try { const driver = await remote ( seleniumCapabilities ) ; connectedDrivers . set ( this . id , driver ) ; const sessionId = driver . sessionId ; log . info ( '%s session at https://saucelabs.com/tests/%s' , browserName , sessionId ) ; log . debug ( 'Opening "%s" on the selenium client' , pageUrl ) ; browserMap . set ( this . id , { sessionId , username : seleniumCapabilities . user , accessKey : seleniumCapabilities . key , region : seleniumCapabilities . region , headless : seleniumCapabilities . headless , results : [ ] , } ) ; await driver . url ( pageUrl ) ; heartbeat ( ) ; } catch ( e ) { log . error ( e ) ; this . _done ( 'failure' ) ; } } ) ; this . on ( 'kill' , async ( done ) => { if ( pendingHeartBeat ) { clearTimeout ( pendingHeartBeat ) ; } try { const browserData = browserMap . get ( this . id ) ; const driver = connectedDrivers . get ( this . id ) ; await driver . deleteSession ( ) ; await uploadJobResult ( browserData , browserName ) ; } catch ( e ) { log . error ( 'Could not quit the Saucelabs selenium connection. Failure message:' ) ; log . error ( e ) ; } connectedDrivers . delete ( this . id ) ; this . _done ( ) ; return process . nextTick ( done ) ; } ) ; }