diff --git a/cdp_patches/input/os_base/windows.py b/cdp_patches/input/os_base/windows.py index 35e251b..84ffacc 100644 --- a/cdp_patches/input/os_base/windows.py +++ b/cdp_patches/input/os_base/windows.py @@ -2,7 +2,7 @@ import ctypes import re import warnings -from typing import Literal, Union +from typing import Literal, Union, List from pywinauto import application, timings from pywinauto.application import WindowSpecification @@ -24,6 +24,18 @@ warnings.filterwarnings("ignore", category=UserWarning, message="32-bit application should be automated using 32-bit Python (you use 64-bit Python)") +def get_top_window(app:application.Application, windows=List[Union[WindowSpecification, HwndWrapper]]) -> WindowSpecification: + if windows is None: + windows = app + # win32_app.top_window(), but without timeout + criteria = {"backend": app.backend.name} + if windows[0].handle: + criteria["handle"] = windows[0].handle + else: + criteria["name"] = windows[0].name + return WindowSpecification(criteria, allow_magic_lookup=app.allow_magic_lookup) + + class WindowsBase: browser_window: Union[WindowSpecification, HwndWrapper] hwnd: int @@ -60,13 +72,7 @@ def get_window( self.browser_window = window break else: - # win32_app.top_window(), but without timeout - criteria = {"backend": self.win32_app.backend.name} - if windows[0].handle: - criteria["handle"] = windows[0].handle - else: - criteria["name"] = windows[0].name - self.browser_window = WindowSpecification(criteria, allow_magic_lookup=self.win32_app.allow_magic_lookup) + self.browser_window = get_top_window(self.win32_app, windows) for child in self.browser_window.iter_children(): if child.element_info.class_name == "Chrome_RenderWidgetHostHWND": @@ -104,13 +110,7 @@ async def async_get_window(self, timeout: float = 1) -> WindowSpecification: self.browser_window = window break else: - # top window, but without timeout - criteria = {"backend": self.win32_app.backend.name} - if windows[0].handle: - criteria["handle"] = windows[0].handle - else: - criteria["name"] = windows[0].name - self.browser_window = WindowSpecification(criteria, allow_magic_lookup=self.win32_app.allow_magic_lookup) + self.browser_window = get_top_window(self.win32_app, windows) for child in self.browser_window.iter_children(): if child.element_info.class_name == "Chrome_RenderWidgetHostHWND": diff --git a/docs/gitbook/input/playwright-usage.md b/docs/gitbook/input/playwright-usage.md index da7f838..b46e61c 100644 --- a/docs/gitbook/input/playwright-usage.md +++ b/docs/gitbook/input/playwright-usage.md @@ -40,23 +40,27 @@ import asyncio from playwright.async_api import async_playwright, Locator from cdp_patches.input import AsyncInput + # Locator Position Helper async def get_locator_pos(locator: Locator): bounding_box = await locator.bounding_box() assert bounding_box + x, y, width, height = bounding_box.get("x"), bounding_box.get("y"), bounding_box.get("width"), bounding_box.get("height") + assert x and y and width and height x, y = x + width // 2, y + height // 2 return x, y + async def main(): async with async_playwright() as playwright: browser = await playwright.chromium.launch() page = await browser.new_page() async_input = await AsyncInput(browser=browser) # Also works with Contexts - + # Example: Click Button # Find Button Coords locator = page.locator("button") @@ -64,5 +68,6 @@ async def main(): # Click Coords => Click Button await async_input.click("left", x, y) + asyncio.run(main()) ``` diff --git a/docs/gitbook/input/selenium-usage.md b/docs/gitbook/input/selenium-usage.md index b82932e..caed533 100644 --- a/docs/gitbook/input/selenium-usage.md +++ b/docs/gitbook/input/selenium-usage.md @@ -2,7 +2,7 @@ -## Sync Usage (Selenium / Sync Selenium-Driverless) +## Sync Usage (Selenium) ```python from selenium import webdriver @@ -45,24 +45,10 @@ with webdriver.Chrome(...) as driver: ```python import asyncio - from selenium_driverless import webdriver -from selenium_driverless.types.webelement import WebElement from selenium_driverless.types.by import By from cdp_patches.input import AsyncInput -# Locator Position Helper -async def get_locator_pos(locator: WebElement): - location = await locator.location - size = await locator.size - assert location, size - - x, y, width, height = location.get("x"), location.get("y"), size.get("width"), size.get("height") - assert x and y and width and height - - x, y = x + width // 2, y + height // 2 - return x, y - async def main(): async with webdriver.Chrome(...) as driver: async_input = await AsyncInput(browser=driver) @@ -70,7 +56,7 @@ async def main(): # Example: Click Button # Find Button Coords locator = await driver.find_element(By.XPATH, "//button") - x, y = await get_locator_pos(locator) + x, y = await locator.mid_location() # Click Coords => Click Button await async_input.click("left", x, y) diff --git a/tests/test_async_playwright.py b/tests/test_async_playwright.py index b5d5a76..7caf069 100644 --- a/tests/test_async_playwright.py +++ b/tests/test_async_playwright.py @@ -82,10 +82,10 @@ async def test_locators_hover(async_page: Page, server: Server) -> None: x, y = await get_locator_pos(button) await async_page.async_input.move(x, y) # type: ignore[attr-defined] + await asyncio.sleep(0.5) assert await async_page.evaluate("document.querySelector('button:hover').id") == "button-12" -@pytest.mark.skip(reason="Scrolling is discouraged") @pytest.mark.asyncio async def test_scroll(async_page: Page, server: Server) -> None: await async_page.goto(server.PREFIX + "/offscreenbuttons.html") diff --git a/tests/test_selenium.py b/tests/test_selenium.py index 44f650a..38bf7e2 100644 --- a/tests/test_selenium.py +++ b/tests/test_selenium.py @@ -112,6 +112,7 @@ def test_locators_hover(selenium_driver: Chrome, server: Server) -> None: x, y = get_locator_pos(sync_locator) selenium_driver.sync_input.move(x, y) # type: ignore[attr-defined] + time.sleep(0.5) assert selenium_driver.execute_script("return document.querySelector('button:hover').id") == "button-12" diff --git a/tests/test_sync_driverless.py b/tests/test_sync_driverless.py index 07872f4..e34781b 100644 --- a/tests/test_sync_driverless.py +++ b/tests/test_sync_driverless.py @@ -113,6 +113,7 @@ def test_locators_hover(sync_driver: Chrome, server: Server) -> None: x, y = get_locator_pos(sync_locator) sync_driver.sync_input.move(x, y) # type: ignore[attr-defined] + time.sleep(0.5) assert sync_driver.execute_script("return document.querySelector('button:hover').id") == "button-12" diff --git a/tests/test_sync_playwright.py b/tests/test_sync_playwright.py index 1339830..3ab013c 100644 --- a/tests/test_sync_playwright.py +++ b/tests/test_sync_playwright.py @@ -78,10 +78,10 @@ def test_locators_hover(sync_page: Page, server: Server) -> None: x, y = get_locator_pos(button) sync_page.sync_input.move(x, y) # type: ignore[attr-defined] + time.sleep(0.5) assert sync_page.evaluate("document.querySelector('button:hover').id") == "button-12" -@pytest.mark.skip(reason="Scrolling is discouraged") def test_scroll(sync_page: Page, server: Server) -> None: sync_page.goto(server.PREFIX + "/offscreenbuttons.html") for i in range(11):