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.
Install with skills.sh (any agent)
npx skills add testland/qa --skill appium-windows-driverappium-windows-driver
Overview
Per the appium-windows-driver repository (opens in new window):
"Appium Windows Driver is a test automation tool for Windows devices and acts as a proxy to Microsoft's WinAppDriver server."
It is the Appium-ecosystem wrapper in front of Microsoft's WinAppDriver.exe (awd (opens in new window)). The Node.js driver itself is actively maintained (see awd (opens in new window) for the current release), while the underlying WinAppDriver service is described on the Appium ecosystem driver page (opens in new window) as "has not been maintained since 2022", which is why the wrapper now includes a built-in installer (appium driver run windows install-wad) to pin a known-good WinAppDriver version.
Sibling differentiation: winappdriver drives the same UIA surface directly via the Microsoft service - pick that skill if the project does not already use Appium or wants no Node.js dependency on the test host. Pick appium-windows-driver when the project already runs Appium for iOS / Android / Mac2 (per desktop-test-strategy-reference for the Mac2 sibling) and Windows is the next platform to add.
When to use
How to use
Install
Per awd (opens in new window):
npm install -g appium
appium driver install windowsThen install the underlying WinAppDriver server via the driver- provided helper (awd (opens in new window)):
appium driver run windows install-wad
# Or pin a version:
appium driver run windows install-wad 1.2.1The helper downloads the pinned WinAppDriver installer to C:\Program Files (x86)\Windows Application Driver\ - the standard Microsoft install path described in winappdriver.
Launch the Appium server:
appium --port 4723Standard Appium 2.x defaults - listens on 127.0.0.1:4723. Sessions to this port forward Windows-specific calls to the WinAppDriver service, which Appium spawns automatically when the first session is created.
Declare session capabilities
Per awd (opens in new window):
| Capability | Required | Notes |
|---|---|---|
platformName | yes | "Must be set to windows (case-insensitive)" (awd (opens in new window)) |
appium:automationName | yes | "Must be set to windows (case-insensitive)" (awd (opens in new window)) |
appium:app | yes (unless attaching) | UWP app ID or full executable path (awd (opens in new window)) |
appium:appTopLevelWindow | conditional | "The hexadecimal handle of an existing application top level window" (awd (opens in new window)) |
appium:appArguments | optional | Argument string passed to the launched app (awd (opens in new window)) |
appium:prerun | optional | PowerShell script run before session start (awd (opens in new window)) |
appium:postrun | optional | PowerShell script run after session end (awd (opens in new window)) |
Example capability JSON:
{
"platformName": "windows",
"appium:automationName": "windows",
"appium:app": "C:\\Windows\\System32\\notepad.exe",
"appium:appArguments": "MyTestFile.txt"
}Worked example
Drive one element end to end - launch Notepad, type into its editor, read the value back, and quit the session (Python client):
from appium import webdriver
from appium.options.windows import WindowsOptions
from selenium.webdriver.common.by import By
options = WindowsOptions()
options.platform_name = 'windows'
options.automation_name = 'windows'
options.app = r'C:\Windows\System32\notepad.exe'
driver = webdriver.Remote('http://127.0.0.1:4723', options=options)
editor = driver.find_element(By.NAME, 'Text editor')
editor.send_keys('Hello from Appium Windows')
assert 'Hello from Appium Windows' in editor.text
driver.quit()Locators (AccessibilityId, Name, ClassName, etc.) carry the same UIA semantics as in winappdriver - the driver proxies them through to WinAppDriver unchanged.
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Omitting appium: prefix on driver capabilities | Appium 2.x requires the vendor prefix on non-W3C-standard caps | Always prefix (appium:automationName, appium:app, etc.) (awd (opens in new window)) |
Targeting automationName: WinAppDriver (legacy) | Appium 2.x driver expects windows, case-insensitive | Use windows per awd (opens in new window) |
| Hand-installing a random WinAppDriver MSI | Version mismatch with the Node driver's proxy code | appium driver run windows install-wad [version] (awd (opens in new window)) |
| Running PowerShell hooks that block forever | Session creation hangs on the prerun script | Hooks must be short + non-interactive (awd (opens in new window)) |
Hard-coded appTopLevelWindow checked into the repo | Hex window handle is per-launch, not stable | Discover at runtime via windows: launchApp or fresh-launch via appium:app |
| Mixing the Mac2 driver's capability shape on Windows | appium:bundleId (Mac2) isn't valid for Windows | Per-platform capability blocks; share only the W3C-standard caps |
Using windows: scroll with positive deltaY to scroll down | Wheel-delta sign mirrors Windows convention | Negative deltaY scrolls down (see gestures reference) |
Limitations
References
Appium Windows driver - gestures, hooks, and CI
View source (opens in new window)Appium Windows driver - gestures, hooks, and CI
Deep reference for appium-windows-driver SKILL.md. Consult when adding Windows-specific gestures, multi-window flows, PowerShell session hooks, or wiring the driver into CI on a Windows runner.
Windows-specific gestures
Per awd (opens in new window), the driver adds Windows-namespaced extensions on top of the W3C WebDriver baseline:
| Command | Purpose |
|---|---|
windows: scroll | "Mouse wheel gesture" with deltaX / deltaY parameters (awd (opens in new window)) |
windows: clickAndDrag | "Drag-and-drop operations" (awd (opens in new window)) |
windows: keys | "Customized keyboard input with virtual key codes" (awd (opens in new window)) |
windows: launchApp | Open another app window within the same session (awd (opens in new window)) |
Scroll a list inside the app under test (negative deltaY scrolls down):
driver.execute_script('windows: scroll', {
'elementId': list_element.id,
'deltaY': -300, # negative scrolls down
})Drag a file across panels:
driver.execute_script('windows: clickAndDrag', {
'startElementId': source.id,
'endElementId': target.id,
})Multi-window sessions
Per awd (opens in new window), "It is possible to switch between app windows using WebDriver Windows API" and windows: launchApp "creates new app windows within the same session". This is the cross-app workflow path (e.g., test a deep-link flow that crosses from a desktop app into the Settings app):
settings_handle = driver.execute_script('windows: launchApp', {
'app': 'ms-settings:',
})
driver.switch_to.window(settings_handle)Pre/post-run PowerShell hooks
Per awd (opens in new window), appium:prerun and appium:postrun accept PowerShell scripts that the driver executes around session lifecycle. This is the canonical place to:
{
"platformName": "windows",
"appium:automationName": "windows",
"appium:app": "MyApp",
"appium:prerun": {
"script": "Copy-Item .\\fixtures\\config.json $env:APPDATA\\MyApp\\config.json -Force"
},
"appium:postrun": {
"script": "Remove-Item $env:APPDATA\\MyApp\\config.json -Force"
}
}Run and parse results
# Pytest example
pytest tests/windows --junitxml=reports/windows-junit.xmlJUnit XML output feeds junit-xml-analysis (in the qa-test-reporting plugin) for the cross-runner aggregation pipeline.
CI integration
# .github/workflows/appium-windows.yml
jobs:
test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with: { node-version: '22' }
- run: npm install -g appium
- run: appium driver install windows
- run: appium driver run windows install-wad
- name: Enable Developer Mode
run: |
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" `
/t REG_DWORD /f /v AllowDevelopmentWithoutDevLicense /d 1
- name: Start Appium
run: |
Start-Process -FilePath "appium" -ArgumentList "--port 4723" -PassThru
Start-Sleep -Seconds 5
- uses: actions/setup-python@v5
with: { python-version: '3.12' }
- run: pip install Appium-Python-Client pytest
- run: pytest tests/windows --junitxml=reports/windows-junit.xml
- uses: actions/upload-artifact@v4
if: always()
with: { name: junit, path: reports/ }Same hosted-vs-self-hosted runner caveats as winappdriver - UIA requires an interactive desktop session, so Session-0 Windows containers won't work without extra display setup.
Related skills
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.
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.
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.