# Add winappcli-based UI test harness (no WinAppDriver / Selenium)
## Summary
Introduces a new UI test harness — `Microsoft.PowerToys.UITest.Next` —
that drives PowerToys
modules through Microsoft's
[winappcli](https://github.com/microsoft/WinAppCli) (UI Automation
CLI) instead of WinAppDriver + Selenium. Engine is a single executable
shelled out from
C#; no third-party NuGet packages, no driver process, no Appium server.
Adds two real consumers:
a full ColorPicker end-to-end scenario and a Settings shell navigation
smoke test.
This is opt-in and additive — the existing `UITestAutomation` library
and the
WinAppDriver-based test projects are untouched. Both can coexist while
we evaluate the new
harness.
Inspired in part by
[#48414](https://github.com/microsoft/PowerToys/pull/48414), which lands
the same architectural bet (winappcli, AutomationId selectors, no
WinAppDriver) at a smaller
scope. This PR generalizes it into a reusable library.
## Why
WinAppDriver + Selenium is a legacy pre-agentic solution that is no
longer actively maintained. It's unreliable, heavyweight, and slow. To
achieve 100% UI test coverage, we should leverage modern, reliable
solutions, and WinApp CLI is a strong candidate.
## What's in this PR
### Harness library —
[`src/common/UITestAutomation.Next/`](src/common/UITestAutomation.Next/)
| File | Purpose |
|---|---|
| [`WinappCli.cs`](src/common/UITestAutomation.Next/WinappCli.cs) |
Process wrapper around `winapp.exe`. `Invoke` / `InvokeAssertSuccess` /
`InvokeJson` / `IsAvailable` / `TryResolveExecutable`. `Result` carries
the args and emits `DescribeFailure()` like `winapp ui invoke X -w 12345
-> exit 1; stderr: ...` |
| [`Session.cs`](src/common/UITestAutomation.Next/Session.cs) | Test
session, scoped by either HWND (`-w`) or process (`-a`) via
`TargetScope`. `Find<T>` / `FindAll<T>` / `Inspect` / `Screenshot` /
`SendKeys`. `Session.FromProcess(...)` factory for the
single-window-per-process case |
|
[`SessionHelper.cs`](src/common/UITestAutomation.Next/SessionHelper.cs)
| Owns the launch + window-readiness flow. Static `EnsureRunning(scope,
timeout)` returns whether the call had to launch (so cleanup only kills
what we started). Uses `UseShellExecute=true` so child handles don't
keep MSTest hanging |
| [`UITestBase.cs`](src/common/UITestAutomation.Next/UITestBase.cs) |
MSTest base class. Pre-flights `WinappCli.IsAvailable()` once per
process and fails fast with the install hint if `winapp.exe` isn't on
PATH |
| [`Element/*.cs`](src/common/UITestAutomation.Next/Element/) |
`Element`, `Button`, `ToggleSwitch`, `TextBox`, `NavigationViewItem`,
`Window`. `Click` / `MouseClick` / `Focus` / `GetProperty` / `GetValue`
/ `HelpText` / `WaitForProperty` / `WaitForGone` plus coords
(`X`/`Y`/`Width`/`Height`) |
| [`By.cs`](src/common/UITestAutomation.Next/By.cs) | `By.Name` /
`By.AccessibilityId` / `By.Id` / `By.Slug` |
| [`Windows.cs`](src/common/UITestAutomation.Next/Windows.cs) |
`WindowsFinder.ListAll` / `ListByApp` / `WaitForWindowByApp` /
`WaitForWindowByProcess`. Notes the winappcli bug where unfiltered
`list-windows` drops untitled windows |
|
[`WindowControl.cs`](src/common/UITestAutomation.Next/WindowControl.cs)
| Tolerant Win32 helpers — `TryCloseByApp` / `TryFocusByApp` /
`SafeCloseAndFocus` / `TryKillProcess` — for `finally` blocks |
|
[`KeyboardHelper.cs`](src/common/UITestAutomation.Next/KeyboardHelper.cs)
| Hybrid `keybd_event` + `SendKeys.SendWait` chord sender — required for
global PowerToys hotkeys |
| [`MouseHelper.cs`](src/common/UITestAutomation.Next/MouseHelper.cs) |
`MoveTo` / `LeftClick` / `RightClick` / `LeftClickAt` Win32 wrappers |
|
[`ClipboardHelper.cs`](src/common/UITestAutomation.Next/ClipboardHelper.cs)
| STA-thread `Clipboard` access with `WaitForText` |
|
[`ModuleConfigData.cs`](src/common/UITestAutomation.Next/ModuleConfigData.cs)
| `PowerToysModule` enum + path/process-name resolution |
### Tests
**[`src/modules/colorPicker/ColorPicker.UITests/`](src/modules/colorPicker/ColorPicker.UITests/)**
— replaces the previous empty `UITest-ColorPicker` stub. One test,
[`ColorPickerEndToEndTests.NavigateReadShortcutActivateAndCapture`](src/modules/colorPicker/ColorPicker.UITests/ColorPickerEndToEndTests.cs),
drives the full E2E:
1. Navigate to the Color Picker page via the dashboard utilities stack
2. Toggle the module OFF, verify `PowerToys.ColorPickerUI` exits; toggle
ON, verify it respawns
3. Read the activation shortcut from the page's `ShortcutControl`
(`EditButton.HelpText`)
4. Clear clipboard, park cursor, send the chord
5. Wait for the picker overlay window
6. Read the displayed HEX from a hidden XAML automation peer (see below)
7. Left-click to capture; assert the clipboard value matches the peer's
HEX
8. Wait for the editor window and assert the captured color appears in
its tree
**[`src/settings-ui/Settings.UITests/`](src/settings-ui/Settings.UITests/)**
— `SettingsNavigationSmokeTests.NavigationItem_NavigatesWithoutCrashing`
is one `[TestMethod]` parameterized with `[DynamicData]`, producing 31
discrete results — one per `NavigationViewItem` in
[`ShellPage.xaml`](src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml).
For each item: navigate, settle 250ms, assert `PowerToys.Settings` is
still alive. Catches FailFast regressions in
`ShellViewModel.Frame_NavigationFailed` that pure-logic unit tests can't
reach (the failure path needs a `NavigationFailedEventArgs` which is a
sealed WinRT projection).
### Product change
**[`src/modules/colorPicker/ColorPickerUI/Views/MainView.xaml`](src/modules/colorPicker/ColorPickerUI/Views/MainView.xaml)**
— adds a hidden `TextBlock` automation peer:
```xml
<TextBlock
x:Name="ColorHexAutomationPeer"
AutomationProperties.AutomationId="ColorHexAutomationPeer"
IsHitTestVisible="False"
Opacity="0"
Text="{Binding ColorText}" />
```
The visible `ColorTextBlock` has `AutomationProperties.Name="{Binding
ColorName}"`, which masks the HEX value in the UIA tree (you see "White"
instead of `#FFFFFF`). This zero-impact peer mirrors `ColorText` so
tests can read the actually-displayed HEX. `Opacity=0` +
`IsHitTestVisible=False` keep it out of the visual layout and out of
accessibility focus.
### Project wiring
- [`PowerToys.slnx`](PowerToys.slnx) — registers `UITestAutomation.Next`
under `/common/`, `ColorPicker.UITests` under
`/modules/colorpicker/Tests/`, and `Settings.UITests` under
`/settings-ui/Tests/`. Original `UITest-ColorPicker` stub csproj
removed.
-
[`.github/actions/spell-check/expect.txt`](.github/actions/spell-check/expect.txt)
— adds `winapp` / `winappcli`.
### Not in this PR
- No pipeline changes. `winapp.exe` is expected to be pre-staged on the
test agent image. If it's missing, `UITestBase` fails the first test
with the install hint (`winget install Microsoft.winappcli`) rather than
producing 30 opaque per-test errors.
- No changes to the legacy `UITestAutomation` library or any of the
existing `*.UITests` projects.
## Validation
- All three projects build clean on `x64|Debug` (empty
`build.<config>.<plat>.errors.log`):
- `src/common/UITestAutomation.Next/`
- `src/modules/colorPicker/ColorPicker.UITests/`
- `src/settings-ui/Settings.UITests/`
- Both tests run in Test Explorer / `dotnet test` via
Microsoft.Testing.Platform (already enabled repo-wide in
`Directory.Build.props`).
- Local runs: ColorPicker E2E green; Settings smoke green across all 31
nav items.
- `winapp 0.3.2` from `winget install Microsoft.winappcli`.
## Notes for reviewers
- **`UseShellExecute = true`** in `SessionHelper.EnsureRunning` is
intentional — `false` makes child processes inherit the test host's
stdin/stdout/stderr handles, which keeps MTP/Test Explorer marking the
run as "in progress" until the spawned PowerToys exits.
- **Process-scope (`-a`) targeting** in the Settings smoke test handles
single-instance handoff: the EXE you launch may exit with code 0
immediately after signalling an existing owner, so the alive check uses
`Process.GetProcessesByName` rather than the launcher PID.
- **AutomationId-only selectors** in the Settings smoke list keep the
test localization-independent. Parent groups have
`SelectsOnInvoked="False"` and only expand on click — `Element.Click`
tries `InvokePattern → TogglePattern → SelectionItemPattern →
ExpandCollapsePattern` so the same call works for both leaves and
groups.
- **Untitled-window discovery**: filtered `winapp ui list-windows -a
<name>` returns windows that the unfiltered call drops (e.g. ColorPicker
editor). `WindowsFinder.ListByApp` uses the filtered form. Reported
upstream.
## Before Merge
- Add the `winappcli` install step to the UI-test pipeline.
Step-by-step guide for diagnosing old update installer accumulation,
covering log files to check, UpdateState.json interpretation, and common
root causes.
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
We are missing msix setup event log from
Microsoft-Windows-AppXDeploymentServer-Operational from bug report.
This PR includes it back for any installation with Powertoys or
CommandPalette
Attach the sample one capture after I setup PowerToys for
Microsoft-Windows-AppXDeploymentServer-Operational events
[EventViewer-AppXDeploymentServerEventLog.zip](https://github.com/user-attachments/files/20791324/EventViewer-AppXDeploymentServerEventLog.zip)
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Remove all VideoConferenceMute related code and files
* Clean up vcm driver registry keys
* Also remove the Webcam report tool
* Also clean out video conference on the installer
* Fix spellcheck
* Remove comment about video conf
* Update gpo files revision
* Revert removing the VCM policies
* Deprecate VCM GPO policy
* Change deprecation message to show first supported version
* Tweak supported strings in the adml