WinAppDriver icon indicating copy to clipboard operation
WinAppDriver copied to clipboard

Appium WebDriverException: Failed to Locate Application Window for Custom Desktop App

Open ofriDev opened this issue 1 year ago • 10 comments

I have a desktop application written in Flet Python, compiled to exe using pyinstaller. I'm trying to add a CI/CD pipeline that will perform UI tests. For this, I am using Appium and WinAppDriver over Python.

I did a test on Notepad — it works great. When I try it on my application, it fails with the following error: selenium.common.exceptions.WebDriverException: Message: Failed to locate opened application window with appId: C:\Users\TEST\Desktop\EXE\dist\app\app.exe, and processId: 2904

The script manages to open the application, but still fails with this error.

The code base of the script from https://github.com/victorkipruto/desktop-automation/tree/master

Here is my main script code

from selenium.webdriver.common.keys import Keys

from src.automaton import webdriver
from src.automaton.options import DesktopOptions

caps = DesktopOptions()
caps.set_capability("app",r"C:\Users\TEST\Desktop\EXE\dist\app\app.exe")
caps.set_capability("automationName", "Windows")
caps.set_capability("newCommandTimeout", 60)
caps.set_capability("ms:waitForAppLaunch", "5")

driver = webdriver.Remote(
    command_executor='http://127.0.0.1:4723',
    options=caps
)

ofriDev avatar Jan 06 '25 11:01 ofriDev

Does you application has a splash screen?

anunay1 avatar Jan 07 '25 17:01 anunay1

Does you application has a splash screen?

No.

For one app it takes a while to load (5 sec, and show a gray screen till full load).

But I checked this issue and I've done a light / skinny app with only some buttons and text fields, and it still crashed with the same error.

ofriDev avatar Jan 07 '25 17:01 ofriDev

@ofriDev Try this

Shakevg avatar Jan 08 '25 07:01 Shakevg

@ofriDev Try this

It seems it works, but not connecting to my app. for validate I'm trying to get all the elements in the app like so:

elem: WebElement = driver.find_element(AppiumBy.XPATH, "//*")
print(elem)

And I got dict[str, str]: {'ELEMENT': '42.65552'}

This is not all my elements in the app (length wise) and I can't know what this element is because it is not indicative; it doesn't display the element's text.

My whole code:

from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.remote.webelement import WebElement

from src.automaton import webdriver
from src.automaton.options import DesktopOptions



try:
    caps = DesktopOptions()
    caps.set_capability("app", r"C:\Users\TEST\Desktop\EXE\dist\app\app.exe")
    caps.set_capability("automationName", "Windows")
    caps.set_capability("newCommandTimeout", 60)
    caps.set_capability("ms:waitForAppLaunch", "5")
    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4723',
        options=caps
    )
except Exception as e:
    caps = DesktopOptions()
    caps.set_capability("app", r"Root")
    caps.set_capability("automationName", "Windows")
    caps.set_capability("newCommandTimeout", 60)
    caps.set_capability("ms:waitForAppLaunch", "5")
    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4723',
        options=caps
    )


elem: WebElement = driver.find_element(AppiumBy.XPATH, "//*")
print(elem)

ofriDev avatar Jan 09 '25 09:01 ofriDev

In except try to connect to the existing app using process or Desktop session

Shakevg avatar Jan 09 '25 13:01 Shakevg

In except try to connect to the existing app using process or Desktop session

It's still not solving the issue. Getting the error: selenium.common.exceptions.WebDriverException: Message: Bad capabilities. Specify either app or appTopLevelWindow to create a session (In the except block)

It seems its getting the right handle, but not recognize it as appTopLevelWindow.

from appium.options.windows import WindowsOptions
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.remote.webelement import WebElement

from src.automaton import webdriver
from src.automaton.options import DesktopOptions
import win32gui

def find_window_handle():
    handleList = []
    def findit(hwnd,ctx):
        if win32gui.GetWindowText(hwnd) == "app": # check the title
            handleList.append(hwnd)

    win32gui.EnumWindows(findit,None)
    return handleList


try:
    caps = DesktopOptions()
    caps.set_capability("app", r"C:\Users\TEST\Desktop\EXE\dist\app\app.exe")
    caps.set_capability("automationName", "Windows")
    caps.set_capability("newCommandTimeout", 60)
    caps.set_capability("ms:waitForAppLaunch", "5")
    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4723',
        options=caps
    )
except Exception as e:
    handle = hex(find_window_handle()[0])
    print(handle)
    caps = DesktopOptions()
    caps.set_capability("automationName", "Windows")
    caps.set_capability("newCommandTimeout", 60)
    caps.set_capability("ms:waitForAppLaunch", "5")
    caps.set_capability("appTopLevelWindow", handle)
    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4723',
        options=caps
    )


elem: WebElement = driver.find_element(AppiumBy.XPATH, "//*")
print(elem)

ofriDev avatar Jan 12 '25 08:01 ofriDev

it should be elem: WebElement = driver.find_elements(AppiumBy.XPATH, "//*") print(elem)

not elem: WebElement = driver.find_element(AppiumBy.XPATH, "//*") print(elem)

anunay1 avatar Jan 13 '25 20:01 anunay1

it should be elem: WebElement = driver.find_elements(AppiumBy.XPATH, "//*") print(elem)

not elem: WebElement = driver.find_element(AppiumBy.XPATH, "//*") print(elem)

This is a step ahead of the problem. The problem is before this line. The script fails in the except block due to incorrect caps. selenium.common.exceptions.WebDriverException: Message: Bad capabilities. Specify either app or appTopLevelWindow to create a session

Updated code:

from appium.options.windows import WindowsOptions
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.remote.webelement import WebElement

from src.automaton import webdriver
from src.automaton.options import DesktopOptions
import win32gui

def find_window_handle():
    handleList = []
    def findit(hwnd,ctx):
        if win32gui.GetWindowText(hwnd) == "app": # check the title
            handleList.append(hwnd)

    win32gui.EnumWindows(findit,None)
    return handleList


try:
    caps = DesktopOptions()
    caps.set_capability("app", r"C:\Users\TEST\Desktop\EXE\dist\app\app.exe")
    caps.set_capability("automationName", "Windows")
    caps.set_capability("newCommandTimeout", 60)
    caps.set_capability("ms:waitForAppLaunch", "5")
    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4723',
        options=caps
    )
except Exception as e:
    handle = hex(find_window_handle()[0])
    print(handle)
    caps = DesktopOptions()
    caps.set_capability("automationName", "Windows")
    caps.set_capability("newCommandTimeout", 60)
    caps.set_capability("ms:waitForAppLaunch", "5")
    caps.set_capability("appTopLevelWindow", handle)
    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4723',
        options=caps
    )


elem: list[WebElement] = driver.find_elements(AppiumBy.XPATH, "//*")
print(elem)

ofriDev avatar Jan 14 '25 08:01 ofriDev

oh ok. Are you using selenium 4? selenium 4 is not supported yet. Need to move to 3.

anunay1 avatar Jan 14 '25 10:01 anunay1

oh ok. Are you using selenium 4? selenium 4 is not supported yet. Need to move to 3.

I see. Unfortunately Now it's not working at all. I downgraded to Selenium-3.141.0 & Appium-Python-Client-1.3.0 & Updated the code for these versions, and now it doesn't even open the app and gives no response in the driver.

Exception: ValueError: Timeout value connect was <object object at 0x0000025315308660>, but it must be an int, float or None.

My updated code:

from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
import win32gui


def find_window_handle():
    handleList = []
    def findit(hwnd, ctx):
        if win32gui.GetWindowText(hwnd) == "app":  # check the title
            handleList.append(hwnd)

    win32gui.EnumWindows(findit, None)
    return handleList


try:
    # Set capabilities directly using DesiredCapabilities
    caps = {
        "app": r"C:\Users\TEST\Desktop\EXE\dist\app\app.exe",
        "automationName": "Windows",
        "newCommandTimeout": 60,
        "ms:waitForAppLaunch": "5",
    }

    # Initialize the Appium driver using the defined capabilities
    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4723/wd/hub',  # Tried also http://127.0.0.1:4723/
        desired_capabilities=caps
    )
except Exception as e:
    # If initialization fails, find the window handle and retry with appTopLevelWindow capability
    handles = find_window_handle()
    if len(handles) == 0:
        raise Exception("Program not found")

    handle = hex(find_window_handle()[0])
    print(handle)

    # Set capabilities directly using DesiredCapabilities
    caps = {
        "appTopLevelWindow": handle,
        "automationName": "Windows",
        "newCommandTimeout": 60,
        "ms:waitForAppLaunch": "5",
    }

    driver = webdriver.Remote(
        command_executor='http://127.0.0.1:4723/wd/hub',  # Tried also http://127.0.0.1:4723/
        desired_capabilities=caps
    )

# Find elements using By.XPATH and print them
elem: list[WebElement] = driver.find_elements(By.XPATH, "//*")
print(elem)

ofriDev avatar Jan 16 '25 10:01 ofriDev