Verisoft Wiki

Desktop Driver (Windows Native App Automation)

Overview

VerisoftDesktopDriver and DesktopBasePage provide automation for Windows native (desktop) applications via appium-wincore-driver. This is the desktop analog of the mobile/web drivers in the framework — page objects extend DesktopBasePage instead of WebBasePage / MobileBasePage.

You can find a detailed documentation for the driver in here

You’ll also find a general description in here

Requirements:

Page Object HierarchyPage Object Hierarchy

BasePage
├── WebBasePage
├── WebBasePageJS
├── MobileBasePage
└── DesktopBasePage   ← Windows native apps

Supported Functions

UI Automation Patterns (element-based)

Method Description
windowsInvoke(element) Invokes InvokePattern (buttons, menu items, hyperlinks)
windowsExpand(element) Expands a collapsible element (tree nodes, combo boxes, expanders)
windowsCollapse(element) Collapses an expanded element
windowsToggle(element) Toggles a checkable element (checkboxes, toggle buttons)
windowsSelect(element) Selects an item via SelectionItemPattern
windowsAddToSelection(element) Adds an item to a multi-select list selection
windowsRemoveFromSelection(element) Removes an item from a multi-select list selection
windowsScrollIntoView(element) Scrolls the element into view via ScrollItemPattern
windowsSetFocus(element) Moves keyboard focus to the element
windowsGetValue(element) Returns element value via ValuePattern (null if unsupported)
windowsSetValue(element, text) Sets element value via ValuePattern
windowsGetSelectedItem(element) Returns currently selected child item (null if none)
windowsGetAllSelectedItems(element) Returns all selected child items of a multi-select container
windowsIsMultipleSelection(element) Returns whether the container supports multiple selection
windowsSelectFromCombobox(element, value) Opens the combo box, selects the item whose name exactly matches value, and closes the list again

Window Management

Method Description
windowsMaximizeWindow(element) Maximizes the window containing the element via WindowPattern
windowsMinimizeWindow(element) Minimizes the window
windowsRestoreWindow(element) Restores window to previous size
windowsCloseWindow(element) Closes the window via WindowPattern
windowsSwitchToWindowByTitle(title) Switches session root to first window whose title contains the string
windowsSwitchToWindowByTitle(title, exact) Switches to window whose title matches (exact=true) or contains (exact=false) the string
windowsWaitForWindowByTitle(title) Waits up to 5s for a window (contains match), then switches
windowsWaitForWindowByTitle(title, exact) Waits up to 5s for a window (exact/contains), then switches
windowsWaitForWindowByTitle(title, timeOut) Waits up to timeOut seconds (contains match); throws RuntimeException if not found
windowsWaitForWindowByTitle(title, exact, timeOut) Waits up to timeOut seconds (exact/contains); throws RuntimeException if not found
windowsGetWindowElement() Returns the root window element of the current session
windowsGetWindows() Returns list of maps for all open top-level windows: handle, title, className

App Lifecycle

Method Description
windowsLaunchApp() Re-launches the AUT using original session capabilities
windowsCloseApp() Closes the AUT

Pointer Input

Method Description
windowsClick(element) Left-clicks centered on the element
windowsClick(element, button) Clicks element with specified button: "left" (default), "right", "middle", "back", "forward"
windowsClick(x, y) Left-clicks at absolute screen coordinates
windowsClick(WindowsClickOptions) Full options builder — element or coordinates, button, modifier keys, repeat count, hold duration
windowsHover(element) Moves pointer to center of element
windowsHover(WindowsHoverOptions) Full options builder — start/end element or coordinates, modifier keys, duration
windowsScroll(element, deltaX, deltaY) Scrolls mouse wheel over an element
windowsScroll(x, y, deltaX, deltaY) Scrolls mouse wheel at absolute coordinates
windowsScroll(WindowsScrollOptions) Full options builder — element or coordinates, delta, modifier keys
windowsClickAndDrag(WindowsClickAndDragOptions) Drags from one element/position to another
windowsKeys(CharSequence... keys) Sends keys through the windows: keys command (native input by Windows virtual-key code). It takes the same arguments as WebElement.sendKeys: text plus Selenium Keys constants. A chord such as Keys.chord(Keys.CONTROL, "a") holds the modifier. Keys go to the focused window, not to an element, so focus the target first. Throws IllegalArgumentException if a Keys constant has no virtual-key mapping.
windowsKeys(WindowsKeysOptions) Full builder: pause(ms), type(text), pressKey(Keys / text / vkCode), keyDown(...), keyUp(...), forceUnicode(bool)

Options builders (WindowsClickOptions, WindowsHoverOptions, WindowsScrollOptions, WindowsClickAndDragOptions, WindowsKeysOptions) are static factory + fluent builders on VerisoftDesktopDriver, e.g.:

getDesktopDriver().windowsClick(
    WindowsClickOptions.onElement(myButton)
        .button("right")
        .modifierKeys(ModifierKey.CTRL, ModifierKey.SHIFT)
        .times(2)
        .durationMs(300));

WindowsClickOptions also supports interClickDelayMs(ms) (default 100), the delay between clicks when times > 1. WindowsClickAndDragOptions supports button(...) and durationMs(ms) (default 500)

driver.windowsKeys("username", Keys.TAB, "password", Keys.ENTER);
driver.windowsKeys(Keys.chord(Keys.CONTROL, "a"));

driver.windowsKeys(WindowsKeysOptions.create()
        .keyDown(Keys.CONTROL).pressKey("a").pressKey("c").keyUp(Keys.CONTROL));

driver.windowsKeys(WindowsKeysOptions.create()
        .type("search term").pause(200).pressKey(Keys.ENTER));

Supported modifier keys (ModifierKey enum): SHIFT, CTRL, ALT, WIN.

Scrolling (mouse wheel)

Method Description
scrollByDirection(direction) Scrolls the app window one step (3 wheel notches) with a W3C wheel action, centred on the window
scrollInsideContainer(container, direction) Scrolls a container element one step, centred on the container
scrollInToViewElement(By, direction) Scrolls until the target is on screen. Stops after 10 attempts, or earlier when the page stops changing
scrollInToViewElement(By, direction, maxScrolls) Same, with your own attempt limit
scrollInToViewElement(container, By, direction, maxScrolls) Scrolls inside a container. Stops when the container’s first visible child stops moving

The direction works the same way as in the swipe methods: DOWN moves the content down, which reveals what is above it. UP reveals what is below.
If the target never comes on screen, the method throws ElementNotInteractableException.
The scrollInToViewElement variants work only in the native context.

Clipboard

Method Description
windowsGetClipboard() Returns current plain-text clipboard content (null if empty)
windowsGetClipboard(contentType) Returns clipboard content as base64 string; contentType = "plaintext" or "image"
windowsSetClipboard(content) Writes plain-text content to clipboard
windowsSetClipboard(data, contentType) Writes raw bytes to clipboard (e.g. PNG image bytes) with given content type

Browser Address Bar (best-effort)

Method Description
windowsGetUrl() Reads a browser's address bar via CTRL+L → CTRL+C → clipboard read
windowsSetUrl(url) Sets a browser's address bar via CTRL+L → type → ENTER

Caveat: These go through keyboard shortcuts, not a native extension command — there is no reliable way to detect "is this actually a browser window." Only meaningful when the focused top-level window is a browser exposing a standard address bar bound to CTRL+L.

System / Environment

Method Description
executePowerShell(script) Executes a PowerShell script via appium-desktop-driver's powerShell extension; returns output as String
windowsGetDeviceTime() Returns current device/system time as ISO-8601 string
windowsGetDpiScale() Returns OS display scale factor (1.0 @ 100%, 1.5 @ 150%, etc.) — use to convert logical UIAutomation coords to physical pixel coords for windowsClick(x, y) and similar
windowsGetMonitors() Returns list of maps describing connected monitors: left, top, right, bottom, width, height, isPrimary

File System

Method Description
windowsDeleteFile(remotePath) Deletes a file on the remote machine. Requires MODIFY_FS_FEATURE flag enabled on Appium server
windowsDeleteFolder(remotePath) Deletes a folder on the remote machine. Requires MODIFY_FS_FEATURE flag enabled on Appium server

Screen Recording

Method Description
windowsStartRecordingScreen() Starts screen recording via FFmpeg. Requires ffmpegExecutablePath capability or FFmpeg on system PATH
windowsStopRecordingScreen() Stops recording, returns video as base64-encoded MP4 string

Vision-Based Element Finding

Method Description
windowsFindByVision(prompt, model) Finds a screen location using LLM-based vision matching. Returns VisionMatch(x, y, label, annotatedImageBase64)
windowsFindByVision(prompt, model, includeAnnotatedImage) Same, but when the flag is true it also returns a base64 PNG of the match, annotated, for debugging

model is the vision LLM id (for example claude-sonnet-4-6). See the appium-wincore-driver API.md for the supported prefixes and the API-key environment variables.

Standard Selenium (partially supported)

Area Support
switchTo().window(handle), switchTo().activeElement() Supported
manage().timeouts(), manage().window() Supported
waitForElement(locator) Supported — uses configured selenium.wait.timeout, tuned for native control render latency
waitForFocus(element) (DesktopBasePage) Waits until the element has keyboard focus (UI Automation HasKeyboardFocus). Uses selenium.wait.timeout

Context Switching (WebView Support)

VerisoftDesktopDriver implements SupportsContextSwitching, so context(name), getContext(), and getContextHandles() are supported. This matters for apps that embed a web renderer (Electron, CEF-based apps, etc.) — the driver can enumerate and switch into a WEBVIEW_* context the same way VerisoftMobileDriver does for hybrid mobile apps. WEBVIEW_* contexts require the webviewEnabled capability.

Once switched into a WEBVIEW_* context, appium-wincore-driver transparently proxies most standard WebDriver commands to a real chromedriver/edgedriver session attached via CDP. Concretely, the following are supported while a WEBVIEW_* context is active (and will fail/throw in the default native context, since appium-desktop-driver has no native handler for them):

windows:-prefixed extension commands and executePowerShell() always target the native UIA layer regardless of the active context.

Unsupported Operations

Calling any of these throws UnsupportedOperationException, regardless of active context — appium-wincore-driver has no implementation for them at all, native or WEBVIEW_*:

Touch/gesture (mobile-specific)

swipe* helpers fail in the native context, because appium-wincore-driver synthesizes no touch input. They work in a WEBVIEW_* context, where the call is proxied to chromedriver/edgedriver. On native UI, use windowsClick, windowsHover, windowsScroll, windowsClickAndDrag, scrollByDirection, scrollInsideContainer or scrollInToViewElement instead

Notes


Example

package co.verisoft.examples.drivers;

import co.verisoft.fw.selenium.drivers.VerisoftDesktopDriver;
import co.verisoft.fw.selenium.drivers.factory.DriverCapabilities;
import co.verisoft.fw.selenium.drivers.factory.DriverUrl;
import co.verisoft.fw.selenium.junit.extensions.DriverInjectionExtension;
import co.verisoft.fw.selenium.junit.extensions.ScreenShotExtension;
import co.verisoft.fw.selenium.junit.extensions.SeleniumLogExtesion;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * Self-contained example of a VerisoftDesktopDriver test.
 * Everything a dev needs is in this one file, split into three parts
 * that normally live in three separate files in a real project:
 *
 *   1. CapabilitiesConfig  - a Spring @Configuration bean per named capability set
 *                            (normally: src/main/java/.../dependencyinjection/DesktopCapabilitiesConfig.java)
 *   2. BaseTest            - registers the JUnit extensions that make driver
 *                            injection, screenshots-on-failure and log capture work
 *                            (normally: src/test/java/.../DriverBaseTest.java, extended by every UI test class)
 *   3. ExampleTest         - the actual test, extends BaseTest and asks for a
 *                            VerisoftDesktopDriver via @DriverCapabilities/@DriverUrl
 *
 * Requires an Appium server running on localhost:4723 with appium-wincore-driver installed.
 */
class VerisoftDesktopDriverExampleTest {

    @Configuration
    static class CapabilitiesConfig {

        @Bean("windows-notepad")
        public DesiredCapabilities windowsNotepad() {
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability("platformName", "Windows");
            caps.setCapability("appium:automationName", "Wincore");
            caps.setCapability("appium:app", "C:/Windows/System32/notepad.exe");
            caps.setCapability("ms:waitForAppLaunch", 5);
            return caps;
        }
    }

    @ExtendWith({DriverInjectionExtension.class, ScreenShotExtension.class, SeleniumLogExtesion.class})
    static class BaseTest {
        // Body stays empty here: the extensions above handle driver injection,
        // screenshots and log capture on their own. This is the place to add
        // shared @BeforeAll / @AfterAll hooks common to all UI tests, if needed.
    }

    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = CapabilitiesConfig.class)
    static class ExampleTest extends BaseTest {

        @Test
        void shouldTypeTextIntoNotepad(
                @DriverCapabilities("windows-notepad")
                @DriverUrl("http://127.0.0.1:4723")
                VerisoftDesktopDriver driver) {

            WebElement editArea = driver.findElement(By.xpath("//Document"));
            editArea.sendKeys("hello world");

            assertEquals("hello world", editArea.getText());
        }
    }
}