import { Application } from "../../automation" ; import * as assert from "assert" ; import AndroidEmulatorManager from "./helpers/androidEmulatorManager" ; import { AppiumClient , AppiumHelper , Platform } from "./helpers/appiumHelper" ; import AutomationHelper from "./helpers/AutomationHelper" ; import IosSimulatorManager from "./helpers/iosSimulatorManager" ; import { LaunchConfigurationManager } from "./helpers/launchConfigurationManager" ; import { SmokeTestLogger } from "./helpers/smokeTestLogger" ; import { SmokeTestsConstants } from "./helpers/smokeTestsConstants" ; import { TestRunArguments } from "./helpers/testConfigProcessor" ; import TestProject from "./helpers/testProject" ; import { sleep } from "./helpers/utilities" ; import { androidEmulatorManager , iosSimulatorManager , vscodeManager } from "./main" ; const HERMES_APP_PACKAGE_NAME = `com.${ SmokeTestsConstants . HermesAppName . toLocaleLowerCase ( ) }` ; const HERMES_APP_BUNDLE_ID = `org.reactjs.native.example.${ SmokeTestsConstants . HermesAppName }` ; const HERMES_APP_ACTIVITY_NAME = `com.${ SmokeTestsConstants . HermesAppName . toLocaleLowerCase ( ) }.MainActivity` ; const RNAndroidHermesDebugConfigName = "Debug Android Hermes - Experimental" ; const RNIosHermesDebugConfigName = "Debug iOS Hermes - Experimental" ; const RNHermesAttachConfigName = "Attach to Hermes application - Experimental" ; const TestHermesButtonName = "Test Button" ; const RNHermesSetBreakpointOnLine = 11 ; const hermesTestTime = SmokeTestsConstants . hermesTestTimeout ; export function startDirectDebugTests ( project , testParameters ) { describe ( "Direct debugging" , ( ) => { let app ; let client ; let automationHelper ; async function initApp ( workspaceOrFolder , sessionName ? , locale ? ) { app = await vscodeManager . runVSCode ( workspaceOrFolder , sessionName , locale ) ; automationHelper = new AutomationHelper ( app ) ; return app ; } async function disposeAll ( ) { try { SmokeTestLogger . info ( "Dispose all ..." ) ; if ( app ) { SmokeTestLogger . info ( "Stopping React Native packager ..." ) ; await stopPackager ( ) ; SmokeTestLogger . info ( "Stopping application ..." ) ; await app . stop ( ) ; app = null ; } if ( client ) { SmokeTestLogger . info ( "Closing application ..." ) ; await client . closeApp ( ) ; SmokeTestLogger . info ( "Deleting session ..." ) ; await client . deleteSession ( ) ; client = null ; } SmokeTestLogger . info ( "Clearing android application ..." ) ; AndroidEmulatorManager . closeApp ( HERMES_APP_PACKAGE_NAME ) ; } catch ( error ) { SmokeTestLogger . error ( "Error while disposeAll:" ) ; SmokeTestLogger . error ( error ) ; } } afterEach ( disposeAll ) ; async function stopPackager ( ) { if ( app ) { await automationHelper . runCommandWithRetry ( SmokeTestsConstants . stopPackagerCommand ) ; await sleep ( 3000 ) ; } } async function hermesApplicationTest ( testname , platform ) { try { if ( platform !== Platform . Android && platform !== Platform . iOS ) { return assert . fail ( `Passed unsupported platform: ${ platform }` ) ; } let debugConfigName ; switch ( platform ) { case Platform . Android : { debugConfigName = RNAndroidHermesDebugConfigName ; break ; } case Platform . iOS : { debugConfigName = RNIosHermesDebugConfigName ; new LaunchConfigurationManager ( project . workspaceDirectory ) . updateLaunchScenario ( RNIosHermesDebugConfigName , { target : iosSimulatorManager . getSimulator ( ) . id , } ) ; break ; } } app = await initApp ( project . workspaceDirectory , testname ) ; await automationHelper . openFileWithRetry ( "AppTestButton.js" ) ; await app . workbench . editors . scrollTop ( ) ; SmokeTestLogger . info ( `${ testname }: AppTestButton.js file is opened` ) ; await app . workbench . debug . setBreakpointOnLine ( RNHermesSetBreakpointOnLine ) ; SmokeTestLogger . info ( `${ testname }: Breakpoint is set on line ${ RNHermesSetBreakpointOnLine }` ) ; SmokeTestLogger . info ( `${ testname }: Chosen debug configuration: ${ debugConfigName }` ) ; SmokeTestLogger . info ( `${ testname }: Starting debugging` ) ; await automationHelper . runDebugScenarioWithRetry ( debugConfigName ) ; let opts ; switch ( platform ) { case Platform . Android : { opts = AppiumHelper . prepareAttachOptsForAndroidActivity ( HERMES_APP_PACKAGE_NAME , HERMES_APP_ACTIVITY_NAME , androidEmulatorManager . getEmulatorId ( ) ) ; await androidEmulatorManager . waitUntilAppIsInstalled ( HERMES_APP_PACKAGE_NAME ) ; break ; } case Platform . iOS : { const buildPath = IosSimulatorManager . getIOSBuildPath ( `${ project . workspaceDirectory }/ios` , `${ SmokeTestsConstants . HermesAppName }.xcworkspace` , "Debug" , SmokeTestsConstants . HermesAppName , "iphonesimulator" ) ; const appPath = `${ buildPath }/${ SmokeTestsConstants . HermesAppName }.app` ; opts = AppiumHelper . prepareAttachOptsForIosApp ( iosSimulatorManager . getSimulator ( ) . name , appPath ) ; await iosSimulatorManager . waitUntilIosAppIsInstalled ( HERMES_APP_BUNDLE_ID ) ; break ; } } client = await AppiumHelper . webdriverAttach ( opts ) ; await app . workbench . debug . waitForDebuggingToStart ( ) ; SmokeTestLogger . info ( `${ testname }: Debugging started` ) ; SmokeTestLogger . info ( `${ testname }: Checking for Hermes mark` ) ; let isHermesWorking = await AppiumHelper . isHermesWorking ( client , platform ) ; assert . strictEqual ( isHermesWorking , true ) ; SmokeTestLogger . info ( `${ testname }: Reattaching to Hermes app` ) ; await automationHelper . disconnectFromDebuggerWithRetry ( ) ; await automationHelper . runDebugScenarioWithRetry ( RNHermesAttachConfigName ) ; SmokeTestLogger . info ( `${ testname }: Reattached successfully` ) ; await sleep ( 7000 ) ; SmokeTestLogger . info ( `${ testname }: Click Test Button` ) ; await automationHelper . waitForStackFrameWithRetry ( sf => sf . name === "AppTestButton.js" && sf . lineNumber === RNHermesSetBreakpointOnLine , `looking for AppTestButton.js and line ${ RNHermesSetBreakpointOnLine }` , 5 , 60 , 1000 , async ( ) => await AppiumHelper . clickTestButton ( client || ( await AppiumHelper . webdriverAttach ( opts ) ) , TestHermesButtonName , platform ) ) ; SmokeTestLogger . info ( `${ testname }: Stack frame found` ) ; await app . workbench . debug . continue ( ) ; await sleep ( SmokeTestsConstants . debugConsoleSearchTimeout ) ; let found = vscodeManager . findStringInLogs ( "Test output from Hermes debuggee" , SmokeTestsConstants . ReactNativeLogFileName ) ; assert . notStrictEqual ( found , false , '"Test output from Hermes debuggee" string is missing in output file' ) ; if ( found ) { SmokeTestLogger . success ( `${ testname }: "Test output from Hermes debuggee" string is found` ) ; } await automationHelper . disconnectFromDebuggerWithRetry ( ) ; SmokeTestLogger . info ( `${ testname }: Debugging is stopped` ) ; } catch ( e ) { SmokeTestLogger . error ( `${ testname } failed: ${ e . toString ( ) }` ) ; await stopPackager ( ) ; return this . skip ( ) ; } } if ( testParameters . RunAndroidTests ) { it ( "Android Hermes app Debug test" , async function ( ) { this . timeout ( hermesTestTime ) ; await hermesApplicationTest . call ( this , "Android Hermes app Debug test" , Platform . Android ) ; } ) ; } if ( process . platform === "darwin" && testParameters . RunIosTests ) { it ( "iOS Hermes app Debug test" , async function ( ) { this . timeout ( hermesTestTime ) ; await hermesApplicationTest . call ( this , "iOS Hermes app Debug test" , Platform . iOS ) ; } ) ; } } ) ; }