diff --git a/README.md b/README.md index 18b23deb..4acf82a8 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ Apps: WinPath: C:\Users\user\AppData\Local\Programs\SomeApp\SomeApp.exe UWPAppName: SOMEAPP.1234567890ABC_defghijklmnop!App MacAppName: com.someapp - + This will add all the necessary capabilities to run on iOS, MacOS, Windows and Android @@ -167,6 +167,9 @@ Devices: - role: localWindows platform: Windows +> [!NOTE] +> For Windows apps, you can set `WinPath` under the app config to `Root` in order to control all Windows screen elements. +If `WinPath` is not provided and `appiumUrl` is either absent or set to `localhost`, the framework will automatically attempt to search for the application window handle on the local machine. You can skip this behavior by setting `appiumUrl` to `127.0.0.1`, which will allow you to manually set the app or `hexMainWindowHandle` inside the role's `capabilities`. ## Create Test Case diff --git a/examples/tests/cases/case_windows_tests.yaml b/examples/tests/cases/case_windows_tests.yaml new file mode 100644 index 00000000..af4f0c54 --- /dev/null +++ b/examples/tests/cases/case_windows_tests.yaml @@ -0,0 +1,33 @@ +RemoteWindowsTestExample: + Roles: + - Role: remoteWindows + App: RootWindows + Actions: + - Type: case + Value: WindowsTestExample + Role: remoteWindows + +LocalWindowsTestExample: + Roles: + - Role: localWindows + App: RootWindows + Actions: + - Type: case + Value: WindowsTestExample + Role: localWindows + +WindowsTestExample: + Actions: + - Type: screenshot + Name: windows_home_screen + - Type: click + Strategy: xpath + Id: "//Text[@Name=\"Search\"]" + - Type: send_keys + Strategy: xpath + Id: "//Edit[@Name=\"Search box\"]" + Value: Settings + - Type: sleep + Time: 2 + - Type: screenshot + Name: windows_search_done \ No newline at end of file diff --git a/examples/tests/cases/config.yaml b/examples/tests/cases/config.yaml index a0333fb6..744654f4 100644 --- a/examples/tests/cases/config.yaml +++ b/examples/tests/cases/config.yaml @@ -6,6 +6,8 @@ Apps: Activity: com.android.vending.AssetBrowserActivity Settings: iOSBundle: com.apple.Preferences + RootWindows: + WinPath: Root # Controls everything on screen chromeDriverPath: chromedriver @@ -29,6 +31,12 @@ Devices: # IOS - role: localiOS platform: iOS + # WINDOWS + - role: remoteWindows + platform: Windows + appiumUrl: http://IP:PORT # Windows device with running Appium server + - role: localWindows + platform: Windows #VARS diff --git a/lib/core/appium_server.rb b/lib/core/appium_server.rb index 24127de7..5d8846cb 100644 --- a/lib/core/appium_server.rb +++ b/lib/core/appium_server.rb @@ -20,8 +20,9 @@ def start @port = @port + 2 opened = `netstat -anp tcp | #{grep_cmd} "#{@port}"`.include?("LISTEN") end + log_debug("Executing: appium --base-path=/wd/hub -p #{@port} >> \"#{folder}/#{@udid}.log\" 2>&1") - spawn("appium --base-path=/wd/hub -p #{@port} >> #{folder}/#{@udid}.log 2>&1") + spawn("appium --base-path=/wd/hub -p #{@port} >> \"#{folder}/#{@udid}.log\" 2>&1") opened = false log_info("Role '#{@role}': Starting Appium server on port #{@port} ", no_date=false, _print=true) diff --git a/lib/core/device_drivers.rb b/lib/core/device_drivers.rb index 71d7f74e..e56fe5d8 100644 --- a/lib/core/device_drivers.rb +++ b/lib/core/device_drivers.rb @@ -69,30 +69,45 @@ def build_mac_caps # assemble basic capabilities for Windows def build_windows_caps - process_check = execute_powershell("Get-Process #{@app}") + caps = { + "platformName" => "Windows", + "automationName" => "Windows", + "newCommandTimeout" => 2000 * 60, + } + if @app_details.key?("WinPath") + caps.merge!({ "app" => @app_details["WinPath"] }) + return caps # No matter if localhost or remote, because Appium will determine window handle automatically + end + + unless @url.include? "localhost" + # Either remote or no need to check for windows handle (127.0.0.1) + return caps + end + + # Running on "localhost" with automatic path to app detection in home directory + if !OS.windows? + log_abort("Cannot run a local windows role on a non-windows operating system!") + end + process_check = execute_powershell("Get-Process \"#{@app}\"") if process_check.include? "Exception" if @app_details.key?("UWPAppName") # launch UWP app spawn("start shell:AppsFolder\\#{@app_details["UWPAppName"]}") else # launch Win32 app - spawn(execute_powershell("where.exe /r $HOME #{@app}.exe")) + app_path = execute_powershell("where.exe /r $HOME \"#{@app}.exe\"").strip + log_debug("Found app path: #{app_path}") + # Array syntax allows to handle any spaces in the filepath. + pid = spawn([app_path, app_path]) + Process.detach(pid) end sleep(5) end - - processWindowHandles = execute_powershell("(Get-Process #{@app}).MainWindowHandle").split("\n") + + # Note: Capabilities app and appTopLevelWindow cannot work together) + processWindowHandles = execute_powershell("(Get-Process \"#{@app}\").MainWindowHandle").split("\n") appMainWindowHandleList = (processWindowHandles.select { |wh| wh.to_i != 0 }) hexMainWindowHandle = appMainWindowHandleList[-1].to_i.to_s(16) + caps.merge!({ "appTopLevelWindow" => "#{hexMainWindowHandle}" }) - caps = { - "platformName" => "Windows", - "forceMjsonwp" => true, - "newCommandTimeout" => 2000 * 60, - } - if @app_details.key?("WinPath") - caps.merge!({ "app" => @app_details["WinPath"] }) - else - caps.merge!({ "appTopLevelWindow" => "#{hexMainWindowHandle}" }) - end return caps end