microsoft / WinAppDriver

Windows Application Driver
MIT License
3.7k stars 1.4k forks source link

WinAppDriver Word Doc Automation #1330

Closed rajivvemula closed 4 years ago

rajivvemula commented 4 years ago

Hi, I am trying the validate the contents of the Word Document through Appium WinAppDriver generated by the Desktop Application.

How can I do that without opening a blank Word doc?

I am confused about how to create a session for the already opened Word Document. Can anyone please help?

Thanks

trashbat commented 4 years ago

Just checking I've understood correctly: you want to attach a WinAppDriver session to a Word document that is already open, and verify that it contains a particular string? I've done something like this before, here's some Python that should do the trick assuming you know the document title ahead of time:

from appium import webdriver
from selenium.webdriver.common.by import By

winappdriver_url = 'http://127.0.0.1:4723/wd/hub'
window_locator = (By.NAME, 'Super Secret Document.docx - Word')
text_to_find = 'foobar'

desktop_driver = webdriver.Remote(
    command_executor=winappdriver_url,
    desired_capabilities={
        'app': 'Root',
        'platformName': 'Windows',
        'deviceName': 'WINDOWSPC'
    }
)

word_window = desktop_driver.find_element(*window_locator)
app_id = hex(int(word_window.get_attribute('NativeWindowHandle')))

word_driver = webdriver.Remote(
    command_executor=winappdriver_url,
    desired_capabilities={
        'platformName': 'Windows',
        'deviceName': 'WINDOWSPC',
        'appTopLevelWindow': app_id
    }
)

main_document = word_driver.find_element(By.TAG_NAME, 'Document')
sections = main_document.find_elements(By.TAG_NAME, 'Edit')

for section in sections:
    if text_to_find in section.text:
        # We found it!
        pass

There are easier and more reliable ways of programmatically validating the contents of a Word doc, though.

trashbat commented 4 years ago

If you don't know the document title ahead of time, you could loop through every window on the desktop and find the first one that belongs to winword.exe, and then attach to that:

import os

import win32api
import win32con
import win32process
from appium import webdriver
from selenium.webdriver.common.by import By

def get_desktop_driver():
    return webdriver.Remote(
        command_executor=winappdriver_url,
        desired_capabilities={
            'app': 'Root',
            'platformName': 'Windows',
            'deviceName': 'WINDOWSPC'
        }
    )

def get_driver_for_process_name(process_name):
    desktop_driver = get_desktop_driver()
    windows = desktop_driver.find_elements(By.TAG_NAME, 'Window')

    for window in windows:
        hwnd = int(window.get_attribute('NativeWindowHandle'))
        pid = win32process.GetWindowThreadProcessId(hwnd)
        handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, pid[1])
        full_path_to_executable = win32process.GetModuleFileNameEx(handle, 0)
        executable = os.path.split(full_path_to_executable)[-1]

        if executable.lower() == process_name.lower():
            return webdriver.Remote(
                command_executor=winappdriver_url,
                desired_capabilities={
                    'platformName': 'Windows',
                    'deviceName': 'WINDOWSPC',
                    'appTopLevelWindow': hex(hwnd)
                }
            )

    raise ProcessLookupError(f"Couldn't find a window for the '{process_name}' process.")

winappdriver_url = 'http://127.0.0.1:4723/wd/hub'
text_to_find = 'foobar'

word_driver = get_driver_for_process_name('winword.exe')

main_document = word_driver.find_element(By.TAG_NAME, 'Document')
sections = main_document.find_elements(By.TAG_NAME, 'Edit')

for section in sections:
    if text_to_find in section.text:
        # We found it!
        pass
rajivvemula commented 4 years ago

Thanks, @trashbat . My framework is in C#, I will definitely take a look at it and let you know.

Shakevg commented 4 years ago

@rajivvemula you can use next method #534 (comment)

Call as:

rajivvemula commented 4 years ago

@rajivvemula you can use next method #534 (comment)

Call as:

  • by process name CreateSessionForAlreadyRunningApp("WINWORD.exe")
  • by document title CreateSessionForAlreadyRunningApp("title")

It worked. Thanks so much. Closing the comment.

ManojVegiTR commented 2 years ago

winappdriver_url = 'http://127.0.0.1:4723' window_locator = (By.NAME, 'Test.docx - Compatibility Mode - Word')

desktop_driver = webdriver.Remote( command_executor=winappdriver_url, desired_capabilities={ 'app': 'Root', 'platformName': 'Windows', 'deviceName': 'WINDOWSPC' } )

*word_window = desktop_driver.find_element(window_locator) app_id = hex(int(word_window.get_attribute('NativeWindowHandle')))**

Getting error at word_window , we are getting dict but not webdriver object. So the error is word_window dict has no get attribute .

Traceback (most recent call last): File "C:\Users\C281379\PycharmProjects\pythonProject\structure_testing.py", line 21, in app_top_level_handle = word_window.get_attribute("NativeWindowHandle") AttributeError: 'dict' object has no attribute 'get_attribute'

leonardo-spy commented 2 years ago

winappdriver_url = 'http://127.0.0.1:4723' window_locator = (By.NAME, 'Test.docx - Compatibility Mode - Word')

desktop_driver = webdriver.Remote( command_executor=winappdriver_url, desired_capabilities={ 'app': 'Root', 'platformName': 'Windows', 'deviceName': 'WINDOWSPC' } )

*_word_window = desktop_driver.find_element(_window_locator)__ app_id = hex(int(word_window.get_attribute('NativeWindowHandle')))

Getting error at word_window , we are getting dict but not webdriver object. So the error is word_window dict has no get attribute .

Traceback (most recent call last): File "C:\Users\C281379\PycharmProjects\pythonProject\structure_testing.py", line 21, in app_top_level_handle = word_window.get_attribute("NativeWindowHandle") AttributeError: 'dict' object has no attribute 'get_attribute'

bug in Selenium 4.0, try use pip install appium-python-client==1.3.0 to update selenium in 3.14.1