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 winappdriverwinappdriver
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
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
Install + enable
Per wad (opens in new window):
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):
| Capability | Purpose |
|---|---|
app | Application identifier (UWP family name) or full executable path (wadauth (opens in new window)) |
appArguments | Launch arguments string (wadauth (opens in new window)) |
appWorkingDir | Working directory for classic Win32 apps (wadauth (opens in new window)) |
appTopLevelWindow | Hexadecimal handle of an existing window to attach to (wadauth (opens in new window)) |
platformName | Target platform - set to Windows |
platformVersion | Platform 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-pattern | Why it fails | Fix |
|---|---|---|
Locating by FindElementByName for localised apps | Element name changes per language | Use AccessibilityId (UIA AutomationId) - stable across locales (wadauth (opens in new window)) |
Hard-coded screen coordinates via MouseAction | DPI / window-state / multi-monitor break | Resolve element via accessibility tree; the driver computes hit-test centre |
| Running tests with Developer Mode disabled | Session creation fails with cryptic error | Enable Developer Mode (Install + enable) (wad (opens in new window)) |
| Custom IP / port without admin privileges | Service refuses to bind to non-default address | Run admin shell or stay on default 127.0.0.1:4723 (wad (opens in new window)) |
| One mega-session that drives multiple apps | UIA tree gets stale between app switches | One session per app; close + recreate on app change |
Forgetting session.Quit() | Orphaned WinAppDriver child processes accumulate | try/finally around session lifecycle |
| Driving Edge / Chrome via WinAppDriver | Browser apps need a real WebDriver (Selenium / Playwright) | Use a browser driver, not WinAppDriver |
| Pixel-image matching for primary assertions | Brittle to font / theme / DPI changes | Accessibility tree first; image matching only for canvas-rendered content (per desktop-test-strategy-reference) |
Limitations
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/hubCustom 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 method | UIA attribute |
|---|---|
FindElementByAccessibilityId | AutomationId |
FindElementByClassName | ClassName |
FindElementById | RuntimeId (decimal) |
FindElementByName | Name |
FindElementByTagName | LocalizedControlType |
FindElementByXPath | any 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=600000Tests 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.