import { Application } from "../../automation" ; import * as assert from "assert" ; import * as path from "path" ; import * as cp from "child_process" ; import AndroidEmulatorManager from "./helpers/androidEmulatorManager" ; import TestProject from "./helpers/testProject" ; import { AppiumClient , AppiumHelper , Platform } from "./helpers/appiumHelper" ; import IosSimulatorManager from "./helpers/iosSimulatorManager" ; import { SmokeTestLogger } from "./helpers/smokeTestLogger" ; import { SmokeTestsConstants } from "./helpers/smokeTestsConstants" ; import { TestRunArguments } from "./helpers/testConfigProcessor" ; import { sleep , findStringInFileWithTimeout , retrieveStringsFromLogFileWithTimeout , } from "./helpers/utilities" ; import { androidEmulatorManager , iosSimulatorManager , vscodeManager } from "./main" ; import AutomationHelper from "./helpers/AutomationHelper" ; import { LaunchConfigurationManager } from "./helpers/launchConfigurationManager" ; const RunNetworkInspectorCommand = "Run Network Inspector" ; const StopNetworkInspectorCommand = "Stop Network Inspector" ; const RNAndroidHermesDebugConfigName = "Run Android Hermes - Experimental" ; const RNIosHermesDebugConfigName = "Run iOS Hermes - Experimental" ; 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 NI_FIND_PATTERN_TIMEOUT = 30000 ; const NIDeviceConnectedPattern = "Device connected" ; const ExpressServerPort = 7321 ; const TestNetworkButtonName = "Test Network Button" ; const requestPattern = /%cNetwork request:(.*?)\scolor: #0000ff\s\{(.*?)\}\s\}/gs ; export function startNetworkInspectorTests ( project , testParameters ? ) { describe ( "Network inspector tests" , ( ) => { const expressServerWorkspace = path . join ( project . workspaceDirectory , SmokeTestsConstants . ExpressServerDir ) ; let app ; let client ; let expressServerProcess ; let automationHelper ; async function initApp ( workspaceOrFolder , sessionName ? , locale ? ) { app = await vscodeManager . runVSCode ( workspaceOrFolder , sessionName , locale ) ; automationHelper = new AutomationHelper ( app ) ; return app ; } async function disposeAll ( ) { SmokeTestLogger . info ( "Dispose all ..." ) ; if ( expressServerProcess ) { expressServerProcess . kill ( ) ; expressServerProcess = null ; } SmokeTestLogger . info ( "Stopping Network inspector" ) ; await automationHelper . runCommandWithRetry ( StopNetworkInspectorCommand ) ; await sleep ( 3000 ) ; if ( app ) { SmokeTestLogger . info ( "Stopping React Native packager ..." ) ; await automationHelper . runCommandWithRetry ( SmokeTestsConstants . stopPackagerCommand ) ; await sleep ( 3000 ) ; await app . stop ( ) ; } if ( client ) { SmokeTestLogger . info ( "Closing application ..." ) ; await client . closeApp ( ) ; SmokeTestLogger . info ( "Deleting session ..." ) ; await client . deleteSession ( ) ; client = null ; } } afterEach ( disposeAll ) ; function startExpressServer ( ) { expressServerProcess = cp . spawn ( "node" , [ SmokeTestsConstants . ExpressServerFileName ] , { cwd : expressServerWorkspace , } ) ; } function validatePostRequestResult ( postRequestData ) { const requestTitle = "POST localhost:7321/post_sample" ; const requestBodyStr = '  "Request Body": {\n    "testStr": "test",\n    "testObj": {\n      "testNum": 1234,\n      "testStr1": "test1"\n    }\n  }' ; const responseBodyStr = '  "Response Body": {\n    "testStr": "testSuccess",\n    "testNun": 123,\n    "testArr": [\n      1,\n      2\n    ]\n  }' ; const requestHeadersPattern = /"Request Headers".*?"Content-Type": "application\/json; charset=utf-8".*?\}/s ; const responseHeadersPattern = /"Response Headers".*?"Content-Type": "application\/json; charset=utf-8".*?\}/s ; return ( postRequestData . includes ( requestTitle ) && postRequestData . includes ( requestBodyStr ) && postRequestData . includes ( responseBodyStr ) && requestHeadersPattern . test ( postRequestData ) && responseHeadersPattern . test ( postRequestData ) ) ; } function validateGetRequestResult ( getRequestData ) { const requestTitle = "GET localhost:7321/get_sample" ; const requestQueryParameters = '  "Request Query Parameters": {\n    "param1": "test",\n    "param2": "123"\n  }' ; const responseBodyStr = '  "Response Body": "GET request success: testSuccess"' ; const responseHeadersPattern = /"Response Headers".*?"Content-Type": "text\/html; charset=utf-8".*?\}/s ; return ( getRequestData . includes ( requestTitle ) && getRequestData . includes ( requestQueryParameters ) && getRequestData . includes ( responseBodyStr ) && responseHeadersPattern . test ( getRequestData ) ) ; } async function networkInspectorTest ( testname , platform ) { if ( platform !== Platform . Android && platform !== Platform . iOS ) { return assert . fail ( `Passed unsupported platform: ${ platform }` ) ; } app = await initApp ( project . workspaceDirectory , testname ) ; 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 ; } } SmokeTestLogger . info ( `${ testname }: Launching the application on an ${ platform } emulator via debug config '${ debugConfigName }'` ) ; await automationHelper . runDebugScenarioWithRetry ( debugConfigName ) ; let appiumOpts ; switch ( platform ) { case Platform . Android : { appiumOpts = 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` ; appiumOpts = AppiumHelper . prepareAttachOptsForIosApp ( iosSimulatorManager . getSimulator ( ) . name , appPath ) ; await iosSimulatorManager . waitUntilIosAppIsInstalled ( HERMES_APP_BUNDLE_ID ) ; break ; } } client = await AppiumHelper . webdriverAttach ( appiumOpts ) ; SmokeTestLogger . info ( `${ testname }: Starting Express server` ) ; startExpressServer ( ) ; await sleep ( 2000 ) ; AndroidEmulatorManager . adbReversePort ( ExpressServerPort ) ; SmokeTestLogger . info ( `${ testname }: Starting Network inspector` ) ; await automationHelper . runCommandWithRetry ( RunNetworkInspectorCommand ) ; let logFilePath = "" ; if ( process . env . REACT_NATIVE_TOOLS_LOGS_DIR ) { logFilePath = path . join ( process . env . REACT_NATIVE_TOOLS_LOGS_DIR , SmokeTestsConstants . NetworkInspectorLogFileName ) ; } else { return assert . fail ( "REACT_NATIVE_TOOLS_LOGS_DIR is not defined" ) ; } const deviceConnectedFound = await findStringInFileWithTimeout ( logFilePath , NIDeviceConnectedPattern , NI_FIND_PATTERN_TIMEOUT ) ; if ( ! deviceConnectedFound ) { return assert . fail ( `Couldn't find a connected device` ) ; } SmokeTestLogger . info ( `${ testname }: an ${ platform } emulator is connected to the Network inspector` ) ; await sleep ( 5000 ) ; await AppiumHelper . clickTestButton ( client , TestNetworkButtonName , platform ) ; SmokeTestLogger . info ( `${ testname }: searching for the post request pattern in Network inspector log file...` ) ; const requestResults = await retrieveStringsFromLogFileWithTimeout ( logFilePath , requestPattern , NI_FIND_PATTERN_TIMEOUT ) ; if ( ! requestResults || requestResults . length < 2 ) { return assert . fail ( `Couldn't find request data in logs` ) ; } SmokeTestLogger . info ( `${ testname }: logged Network request ${ requestResults . toString ( ) }` ) ; assert . strictEqual ( validatePostRequestResult ( requestResults [ 0 ] ) , true ) ; assert . strictEqual ( validateGetRequestResult ( requestResults [ 1 ] ) , true ) ; SmokeTestLogger . success ( `${ testname }: logged Network request is correct` ) ; } if ( ! testParameters || testParameters . RunAndroidTests ) { it ( "Network inspector should process GET and POST requests on an Android emulator" , async function ( ) { this . timeout ( SmokeTestsConstants . networkInspectorTestTimeout ) ; await networkInspectorTest . call ( this , "Network inspector Android test" , Platform . Android ) ; } ) ; } if ( process . platform === "darwin" && ( ! testParameters || testParameters . RunIosTests ) ) { it ( "Network inspector should process GET and POST requests on an iOS emulator" , async function ( ) { this . timeout ( SmokeTestsConstants . networkInspectorTestTimeout ) ; await networkInspectorTest . call ( this , "Network inspector iOS test" , Platform . iOS ) ; } ) ; } } ) ; }