import * as fs from "fs" ; import * as cp from "child_process" ; import * as request from "request" ; import * as URL from "url-parse" ; import { dirname } from "path" ; import { SpawnSyncOptions } from "child_process" ; import { SmokeTestsConstants } from "./smokeTestsConstants" ; import AndroidEmulatorManager from "./androidEmulatorManager" ; import { AppiumHelper } from "./appiumHelper" ; import IosSimulatorManager from "./iosSimulatorManager" ; import { SmokeTestLogger } from "./smokeTestLogger" ; export const npxCommand = process . platform === "win32" ? "npx.cmd" : "npx" ; export const npmCommand = process . platform === "win32" ? "npm.cmd" : "npm" ; export const yarnCommand = process . platform === "win32" ? "yarn.cmd" : "yarn" ; export function nfcall < R > ( fn , ... args ) { return new Promise < R > ( ( c , e ) => fn ( ... args , ( err , r ) => ( err ? e ( err ) : c ( r ) ) ) ) ; } export async function mkdirp ( path , mode ? ) { const mkdir = async ( ) => { try { await nfcall ( fs . mkdir , path , mode ) ; } catch ( err ) { if ( err . code === "EEXIST" ) { const stat = await nfcall < fs . Stats > ( fs . stat , path ) ; if ( stat . isDirectory ( ) ) { return ; } throw new Error ( `'${ path }' exists and is not a directory.` ) ; } throw err ; } } ; if ( path === dirname ( path ) ) { return true ; } try { await mkdir ( ) ; } catch ( err ) { if ( err . code !== "ENOENT" ) { throw err ; } await mkdirp ( dirname ( path ) , mode ) ; await mkdir ( ) ; } return true ; } export function sanitize ( name ) { return name . replace ( /[&*:\/]/g , "" ) ; } export function spawnSync ( command , args ? , options ? ) { const result = cp . spawnSync ( command , args , options ) ; if ( result . stdout ) { SmokeTestLogger . log ( result . stdout . toString ( ) ) ; } if ( result . stderr ) { SmokeTestLogger . error ( result . stderr . toString ( ) ) ; } if ( result . error ) { throw result . error ; } } export function isLoggedInExpo ( ) { const loginPattern = /^\w+\s?$/g ; const unloggedPattern = "Not logged in" ; const command = "expo w" ; const commandResult = execSync ( command ) ; if ( commandResult . includes ( unloggedPattern ) ) { SmokeTestLogger . warn ( `Expo account is not logged in` ) ; return false ; } const matches = commandResult . match ( loginPattern ) ; if ( matches && matches . length ) { const login = matches [ 0 ] . trim ( ) ; SmokeTestLogger . success ( `Logged in Expo as ${ login }` ) ; return true ; } SmokeTestLogger . error ( `There is an unrecognized command '${ command }' result. Output of command: ${ commandResult }` ) ; return false ; } export function execSync ( command , options = { } , logFilePath ? ) { options = Object . assign ( options , { stdio : "pipe" } ) ; let output = "" ; try { output = cp . execSync ( command , options ) . toString ( ) ; } catch ( err ) { output += err . stdout && err . stdout . toString ( ) ; output += err . stderr && err . stderr . toString ( ) ; if ( logFilePath ) { SmokeTestLogger . saveLogsInFile ( output , logFilePath ) ; } throw err ; } if ( logFilePath ) { SmokeTestLogger . saveLogsInFile ( output , logFilePath ) ; } return output ; } param promises export function runInParallel ( promises ) { return new Promise < any [ ] > ( ( resolve , reject ) => { let total = promises . length ; let count = 0 ; let results = [ ] ; const saveResult = ( result ) => { results . push ( result ) ; ++ count ; if ( count === total ) { resolve ( results ) ; } } ; promises . forEach ( promise => { promise . then ( result => { saveResult ( result ) ; } ) . catch ( e => { reject ( e ) ; } ) ; } ) ; } ) ; } export function getContents ( url , token , headers , callback ) { request . get ( toRequestOptions ( url , token , headers ) , function ( error , response , body ) { if ( ! error && response && response . statusCode >= 400 ) { error = new Error ( "Request returned status code: " + response . statusCode + "\nDetails: " + response . body ) ; } callback ( error , body ) ; } ) ; } export function toRequestOptions ( url , token , headers ? ) { headers = headers || { "user-agent" : "nodejs" , } ; if ( token ) { headers [ "Authorization" ] = "token " + token ; } let parsedUrl = new URL ( url ) ; let options = { url : url , headers : headers , } ; if ( process . env . npm_config_strict_ssl !== "true" ) { options . strictSSL = false ; } if ( process . env . npm_config_proxy && parsedUrl . protocol === "http:" ) { options . proxy = process . env . npm_config_proxy ; } else if ( process . env . npm_config_https_proxy && parsedUrl . protocol === "https:" ) { options . proxy = process . env . npm_config_https_proxy ; } return options ; } export async function sleep ( time ) { await new Promise < void > ( resolve => { const timer = setTimeout ( ( ) => { clearTimeout ( timer ) ; resolve ( ) ; } , time ) ; } ) ; } export function findFile ( directoryToSearch , filePattern ) { const dirFiles = fs . readdirSync ( directoryToSearch ) ; let extensionFile = dirFiles . find ( elem => { return filePattern . test ( elem ) ; } ) ; if ( extensionFile ) { return extensionFile ; } return null ; } export function filterProgressBarChars ( str ) { const filterRegExp = /\||\/|\-|\\/ ; str = str . replace ( filterRegExp , "" ) ; return str ; } export function findStringInFile ( filePath , strToFind ) { if ( fs . existsSync ( filePath ) ) { const content = fs . readFileSync ( filePath ) . toString ( ) . trim ( ) ; return content . includes ( strToFind ) ; } return false ; } export async function findStringInFileWithTimeout ( filePath , strToFind , timeout ? ) { const condition = ( ) => findStringInFile ( filePath , strToFind ) ; return waitUntil ( condition , timeout , 3000 ) ; } export function retrieveStringsFromLogFile ( filePath , pattern ) { if ( fs . existsSync ( filePath ) ) { const content = fs . readFileSync ( filePath ) . toString ( ) . trim ( ) ; return content . match ( pattern ) ; } return null ; } export async function retrieveStringsFromLogFileWithTimeout ( filePath , pattern , timeout ? ) { let result = null ; const condition = ( ) => { result = retrieveStringsFromLogFile ( filePath , pattern ) ; return ! ! result ; } ; await waitUntil ( condition , timeout , 3000 ) ; return result ; } export function objectsContains ( object , subObject ) { for ( let i = 0 ; i < Object . keys ( subObject ) . length ; i ++ ) { const key = Object . keys ( subObject ) [ i ] ; if ( typeof subObject [ key ] === "object" && subObject [ key ] !== null ) { if ( typeof object [ key ] === "object" && object [ key ] !== null ) { if ( ! objectsContains ( object [ key ] , subObject [ key ] ) ) { return false ; } } else { return false ; } } else if ( subObject [ key ] !== object [ key ] ) { return false ; } } return true ; } export function waitUntil ( condition , timeout = 30000 , interval = 1000 ) { return new Promise ( resolve => { const rejectTimeout = setTimeout ( ( ) => { cleanup ( ) ; resolve ( false ) ; } , timeout ) ; const сheckInterval = setInterval ( async ( ) => { if ( condition ( ) ) { cleanup ( ) ; resolve ( true ) ; } } , interval ) ; const cleanup = ( ) => { clearTimeout ( rejectTimeout ) ; clearInterval ( сheckInterval ) ; } ; } ) ; } export async function waitForRunningPackager ( filePath ) { const condition = ( ) => { return findStringInFile ( filePath , SmokeTestsConstants . PackagerStartedPattern ) ; } ; const result = await waitUntil ( condition ) ; if ( result ) { SmokeTestLogger . success ( `Packager started pattern is found` ) ; } else { SmokeTestLogger . warn ( `Packager started logging pattern is not found` ) ; } return result ; } export async function smokeTestFail ( message ) { SmokeTestLogger . error ( message ) ; await AndroidEmulatorManager . terminateAllAndroidEmulators ( ) ; if ( process . platform === "darwin" ) { try { await IosSimulatorManager . shutdownAllSimulators ( ) ; } catch ( e ) { SmokeTestLogger . error ( e . toString ( ) ) ; } } await AppiumHelper . terminateAppium ( ) ; process . exit ( 1 ) ; }