Testland
Browse all skills & agents

winappdriver

Authors and runs Windows UI tests against WinAppDriver, Microsoft's W3C-WebDriver service for UWP / WPF / WinForms / Win32 apps: installing + launching `WinAppDriver.exe` on `127.0.0.1:4723`, declaring `app` / `platformName` / `appArguments` / `appTopLevelWindow` capabilities, finding elements by `AccessibilityId` / `Name` / `ClassName`, and Windows-runner CI. Use when driving a native Windows app from a Selenium-style client (C#, Java, Python, Ruby, JS); for the actively-maintained Appium 2.x wrapper over the same server use appium-windows-driver, for a C#-only FlaUI client use flaui-tests, and to choose among Windows desktop drivers first use desktop-test-strategy-reference.

Install with skills.sh (any agent)

npx skills add testland/qa --skill winappdriver
View source

winappdriver

Overview

Per the WinAppDriver repository (opens in new window):

"Windows Application Driver (WinAppDriver) is a service to support Selenium-like UI Test Automation on Windows Applications."

WinAppDriver exposes Microsoft UI Automation (UIA) - the Windows accessibility tree described in desktop-test-strategy-reference - behind a W3C-WebDriver-compatible HTTP endpoint. Per wad (opens in new window), it supports four application classes on Windows 10: "Universal Windows Platform (UWP)", "Windows Forms (WinForms)", "Windows Presentation Foundation (WPF)", and "Classic Windows (Win32) apps".

The driver is a Microsoft-maintained service, distinct from the Appium ecosystem's wrapper around it - see appium-windows-driver for the Appium proxy that sits in front of WinAppDriver.exe and adds gestures, multi-window helpers, and PowerShell hooks. Pick this skill when you want to talk to WinAppDriver.exe directly from a Selenium client; pick appium-windows-driver when you want the Appium feature surface.

When to use

  • Native Windows desktop app under test - UWP, WPF, WinForms, or Win32 (wad (opens in new window)).
  • Selenium-style client already in the project (C# WindowsDriver<T>, Java WindowsDriver, Python webdriver-windows).
  • Tests must drive system-installed apps (Notepad, Calculator, Settings) - app capability accepts an executable path or UWP application family name (wadauth (opens in new window)).
  • Direct-to-WinAppDriver.exe is required (no Appium installation permitted on the test host).

For Qt-on-Windows out-of-process tests, this is the recommended driver per desktop-test-strategy-reference; the Qt application must publish a usable QAccessible tree.

How to use

  1. Install WinAppDriver and enable Developer Mode on a Windows 10/11 machine (Install + enable).
  2. Launch WinAppDriver.exe on the default 127.0.0.1:4723 endpoint (Launch the service).
  3. Declare app / platformName / appArguments / appTopLevelWindow capabilities for the app under test (Declare session capabilities).
  4. Author a Selenium-style test that resolves an element by AccessibilityId (UIA AutomationId) and drives it end to end (Worked example). The full locator-strategy table, Inspect.exe discovery, and attach-to-running-window path live in references/locators-and-ci.md.
  5. Run on a Windows CI runner and parse TRX / JUnit results (feeds junit-xml-analysis) - full workflow in references/locators-and-ci.md.

Install + enable

Per wad (opens in new window):

  1. Windows 10 machine with the application under test installed.
  2. Enable Developer Mode - Settings → Update & Security → For developers → Developer mode (wad (opens in new window)).
  3. Administrator privileges are required to run on a custom IP / port (wad (opens in new window)); default 127.0.0.1:4723 runs as a normal user.

Download the latest WinAppDriver installer from the releases page (opens in new window) (latest stable per wad (opens in new window): v1.2.1, published 2020-11-05) and run it on the test machine. The installer drops WinAppDriver.exe under C:\Program Files (x86)\Windows Application Driver\.

Launch the service

Per wad (opens in new window), launch on the default endpoint:

:: Default - 127.0.0.1:4723
"C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe"

The service prints Press ENTER to exit. and listens for incoming W3C-WebDriver session requests. Custom IP / port / URL-prefix bindings (which require an admin shell) are in references/locators-and-ci.md.

Declare session capabilities

Per the WinAppDriver authoring guide (opens in new window):

CapabilityPurpose
appApplication identifier (UWP family name) or full executable path (wadauth (opens in new window))
appArgumentsLaunch arguments string (wadauth (opens in new window))
appWorkingDirWorking directory for classic Win32 apps (wadauth (opens in new window))
appTopLevelWindowHexadecimal handle of an existing window to attach to (wadauth (opens in new window))
platformNameTarget platform - set to Windows
platformVersionPlatform version string

Per wadauth (opens in new window), the UWP Application Id appears in the generated AppX\vs.appxrecipe file under the RegisteredUserModeAppID node (example shape: c24c8163-548e-4b84-a466-530178fc0580_scyf5npe3hv32!App).

Worked example

Drive one element end to end - launch Notepad, locate its editor by AccessibilityId, type into it, and close the session (C# client). The canonical example from wadauth (opens in new window):

using System;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;

var capabilities = new AppiumOptions();
capabilities.AddAdditionalCapability("app", @"C:\Windows\System32\notepad.exe");
capabilities.AddAdditionalCapability("appArguments", @"MyTestFile.txt");
capabilities.AddAdditionalCapability("appWorkingDir", @"C:\MyTestFolder\");
capabilities.AddAdditionalCapability("platformName", "Windows");

var session = new WindowsDriver<WindowsElement>(
    new Uri("http://127.0.0.1:4723"),
    capabilities);

// Locate by AccessibilityId (the AutomationId attribute)
var editor = session.FindElementByAccessibilityId("15");
editor.SendKeys("Hello from WinAppDriver");

session.Quit();

The AccessibilityId locator maps to the UIA AutomationId property - the stable locator per the desktop-test-strategy-reference locator table. The full method-to-attribute mapping and the other locator strategies are in references/locators-and-ci.md.

Anti-patterns

Anti-patternWhy it failsFix
Locating by FindElementByName for localised appsElement name changes per languageUse AccessibilityId (UIA AutomationId) - stable across locales (wadauth (opens in new window))
Hard-coded screen coordinates via MouseActionDPI / window-state / multi-monitor breakResolve element via accessibility tree; the driver computes hit-test centre
Running tests with Developer Mode disabledSession creation fails with cryptic errorEnable Developer Mode (Install + enable) (wad (opens in new window))
Custom IP / port without admin privilegesService refuses to bind to non-default addressRun admin shell or stay on default 127.0.0.1:4723 (wad (opens in new window))
One mega-session that drives multiple appsUIA tree gets stale between app switchesOne session per app; close + recreate on app change
Forgetting session.Quit()Orphaned WinAppDriver child processes accumulatetry/finally around session lifecycle
Driving Edge / Chrome via WinAppDriverBrowser apps need a real WebDriver (Selenium / Playwright)Use a browser driver, not WinAppDriver
Pixel-image matching for primary assertionsBrittle to font / theme / DPI changesAccessibility tree first; image matching only for canvas-rendered content (per desktop-test-strategy-reference)

Limitations

  • Windows-only. The service runs only on Windows 10/11. No cross-OS test sharing without re-authoring against XCTest / AT-SPI.
  • No first-party Linux / macOS analogue. Per the desktop-test-strategy-reference matrix, each OS has its own driver.
  • No headless mode. UIA requires an interactive desktop session; CI on windows-latest works because GitHub-hosted runners are interactive, but Windows containers under Session 0 do not.
  • GPU / DirectComposition surfaces (some WPF + WinUI 3 surfaces using DirectX-rendered controls) may not expose themselves to UIA - visible as opaque rectangles in Inspect.exe.
  • App must publish UIA. Custom-painted Win32 windows that don't implement IRawElementProviderSimple are uncovered by WinAppDriver. Add UIA support or fall back to image matching for those specific surfaces.

References

WinAppDriver - locators, attach, and CI

View source (opens in new window)

WinAppDriver - locators, attach, and CI

Deep reference for winappdriver SKILL.md. Consult for the full element-locator table, custom service bindings, attaching to an already-running window, and CI wiring on a Windows runner.

Custom service bindings

Per wad (opens in new window), beyond the default 127.0.0.1:4723:

:: Custom port (admin shell)
WinAppDriver.exe 4727

:: Bind to LAN IP (admin shell)
WinAppDriver.exe 10.0.0.10 4725

:: Bind to URL prefix (admin shell)
WinAppDriver.exe 10.0.0.10 4723/wd/hub

Custom IP / port bindings require Administrator privileges (wad (opens in new window)); the default 127.0.0.1:4723 runs as a normal user.

Element-locator strategies

Per wadauth (opens in new window):

C# / Java methodUIA attribute
FindElementByAccessibilityIdAutomationId
FindElementByClassNameClassName
FindElementByIdRuntimeId (decimal)
FindElementByNameName
FindElementByTagNameLocalizedControlType
FindElementByXPathany attribute (XPath over the UIA tree)

To discover the right id during authoring, use Inspect.exe (ships with the Windows SDK) or Accessibility Insights for Windows - both walk the same UIA tree the driver sees.

Attaching to an already-running window

For tests where the app is launched externally:

var capabilities = new AppiumOptions();
// Hex window handle from Inspect.exe / Spy++
capabilities.AddAdditionalCapability("appTopLevelWindow", "0xB822E2");
capabilities.AddAdditionalCapability("platformName", "Windows");
var session = new WindowsDriver<WindowsElement>(
    new Uri("http://127.0.0.1:4723"),
    capabilities);

Per wadauth (opens in new window), the appTopLevelWindow capability takes a hex window handle. This is the path for testing apps that don't support fresh-launch (apps with single-instance locks, or apps requiring authenticated login flows that run outside the test).

Run

:: Build + test (NUnit example)
dotnet test --logger "trx;LogFileName=results.trx"

:: With session retry on flaky launches
dotnet test --filter "Category=Smoke" -- RunConfiguration.TestSessionTimeout=600000

Tests assume WinAppDriver.exe is running on 127.0.0.1:4723. A Setup fixture per test class should start the driver if it isn't already, then dispose at TearDown.

Parsing results

The C# Selenium client emits standard NUnit / MSTest / xUnit results (TRX, XML, or JUnit depending on logger choice). Pair with junit-xml-analysis (in the qa-test-reporting plugin) for the cross-runner aggregation pipeline.

CI integration

Windows-only runner required - WinAppDriver does not run on Linux or macOS:

# .github/workflows/winappdriver.yml
jobs:
  test:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v5
      - name: Install WinAppDriver
        # Choco installs to default path + adds shortcut
        run: choco install winappdriver -y
      - name: Enable Developer Mode (Win 10/11 runners)
        run: |
          reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" `
            /t REG_DWORD /f /v AllowDevelopmentWithoutDevLicense /d 1
      - name: Start WinAppDriver
        run: |
          Start-Process -FilePath "C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe" `
            -PassThru
          Start-Sleep -Seconds 3   # Let the service bind to 4723
      - uses: actions/setup-dotnet@v4
        with: { dotnet-version: '8.0.x' }
      - name: Test
        run: dotnet test --logger "trx;LogFileName=results.trx"
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: trx-results
          path: '**/results.trx'

WinAppDriver runs interactive - GitHub-hosted windows-latest runners have an interactive session by default, but headless self- hosted Windows containers need additional setup (the service refuses to start under Session 0).

Related skills

appium-windows-driver

Authors and runs Appium 2.x tests against the Windows driver, the actively-maintained Node.js proxy in front of Microsoft's WinAppDriver: `appium driver install windows`, capabilities (`platformName: windows`, `appium:automationName: windows`, `appium:app`, `appium:appTopLevelWindow`, `appium:appArguments`), Windows gestures (`windows: scroll` / `clickAndDrag` / `keys`), PowerShell prerun/postrun hooks, and CI. Use when the stack already uses Appium for iOS / Android / Mac2 and Windows fits the existing client + capability model; to drive WinAppDriver directly from a Selenium-style client use winappdriver, and for a C#-only FlaUI client use flaui-tests.

at-spi-linux

Authors Linux desktop UI tests via AT-SPI - the DBus-based Assistive Technology Service Provider Interface implemented by `at-spi2-core` (registry daemon + `libatspi` C library + ATK GTK bridge). Covers enabling toolkit accessibility (`gsettings set org.gnome.desktop.interface toolkit-accessibility true`), driving GTK + Qt apps through Python `dogtail` (object-oriented + procedural APIs), inspecting the tree with Accerciser, scripting via `pyatspi`, and CI integration on headless Linux runners with `Xvfb` + `dbus-launch`. Use for Linux-side desktop tests of GTK applications, Qt apps with QAccessible enabled, and Electron apps on Linux.

desktop-test-strategy-reference

Pure-reference catalog of desktop GUI test strategies across Windows, macOS, and Linux. Defines the three accessibility-tree backends (Microsoft UI Automation on Windows, Apple Accessibility / XCTest on macOS, AT-SPI on Linux), the wrapper-tools that drive each backend (WinAppDriver, Appium-Windows, XCUIApplication, AT-SPI clients), the cross-toolkit Electron + Qt paths, and a per-OS decision matrix with accessibility-first locator strategy. Deep operational detail (per-OS asynchronous-wait hierarchies, parallel-test policy, foreground-lock / UAC / TCC / AT-SPI elevation hazards, and the high-DPI / per-monitor test matrix) lives in references/. Use when choosing how to test or automate a desktop GUI application (desktop app testing, GUI automation, automate desktop UI) on Windows, macOS, or Linux - the strategic reference before picking a desktop test stack, ahead of the per-tool implementation skills.

electron-playwright

Authors Playwright `_electron` tests for packaged Electron desktop apps - launches the app via `electron.launch({ args })`, returns an `ElectronApplication` handle, drives renderer windows as Playwright `Page` objects, and probes the main process via `electronApp.evaluate(({ app, BrowserWindow }) => …)`. Distinct from ordinary browser page automation: this wraps the `_electron` API for launching packaged Electron apps and probing main + renderer processes. Use for end-to-end tests of Electron apps where main-process state, IPC, and renderer DOM must all be asserted from one suite.

electron-spectron

Legacy reference for Spectron - Electron's original ChromeDriver-based testing framework, officially deprecated 2022-02-01 at v19.0.0. Documents what Spectron was, the architectural reason it became unmaintainable, the migration path to Playwright `_electron`, and the residual support contract for projects still on Spectron. Use only when auditing a legacy suite or planning a migration off Spectron - for new work use Playwright's `_electron` API.

flaui-tests

Authors and runs FlaUI-based Windows UI tests - the .NET-native wrapper around Microsoft UI Automation (UIA2 + UIA3). Covers the `FlaUI.Core` / `FlaUI.UIA2` / `FlaUI.UIA3` NuGet packages, `Application.Launch` / `Application.Attach` lifecycles, `ConditionFactory` + `FindFirstDescendant` locator patterns, `Retry` waits, and xUnit / NUnit / MSTest harness integration. Use when the test stack is C# / .NET-first and the team wants idiomatic in-process UIA calls rather than the HTTP/JSON wire protocol of `winappdriver` or the Appium proxy layer of `appium-windows-driver`.

qt-test-framework

Authors and runs Qt Test - the first-party C++ unit + GUI test framework that ships with Qt 6 (via the `QtTest` module header). Covers the `QTEST_MAIN` / `QTEST_APPLESS_MAIN` / `QTEST_GUILESS_MAIN` entry-point macros, the `QObject` private-slot test pattern, `QVERIFY` / `QCOMPARE` / `QFETCH` assertions, GUI event simulation (`QTest::mouseClick`, `QTest::keyClick`, `QTest::touchEvent`), `QSignalSpy` for signal introspection, `QBENCHMARK` for performance regression, and the `-o file,junitxml` CI output. Use for in-process testing of Qt widgets, QObject signal/slot chains, and Qt Quick / QML application logic; for out-of-process Qt-app driving, use an OS-native accessibility driver instead.

xctest-mac-desktop

Authors and runs XCTest UI + unit tests for macOS desktop apps - the Apple-first-party test framework that ships with Xcode. Covers the `XCTestCase` subclass + `test*` method-naming convention, `XCUIApplication` / `XCUIElement` / `XCUIElementQuery` for UI tests, accessibility-identifier-based locators (the stable replacement for label-based queries), `XCTAssert*` macros, `measureBlock:` for performance regressions, and `xcodebuild test` for CI execution. Use when the macOS app is built with Xcode and the test target is in-tree alongside the app - for cross-OS sharing see Appium Mac2 driver as a separate path.