Appium WebDriverException: Failed to Locate Application Window for Custom Desktop App
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
)
Does you application has a splash screen?
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 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)
In except try to connect to the existing app using process or Desktop session
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)
it should be elem: WebElement = driver.find_elements(AppiumBy.XPATH, "//*") print(elem)
not elem: WebElement = driver.find_element(AppiumBy.XPATH, "//*") print(elem)
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)
oh ok. Are you using selenium 4? selenium 4 is not supported yet. Need to move to 3.
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)