Migrate PowerToys module UI tests from the legacy WinAppDriver/Selenium harness (Microsoft.PowerToys.UITest) to the new winappcli-based harness (Microsoft.PowerToys.UITest.Next). Use when asked to port/convert/rewrite/modernize a module's UI tests to the .Next framework, create a new [Module].UITests.Next project alongside existing legacy tests, or stand up brand-new winappcli UI tests for a module that has none by reading its human test sign-off markdown. Covers the API mapping (By/Element/Session/UITestBase, KeyboardHelper/MouseHelper/ClipboardHelper), project/csproj scaffolding, naming rules, common PowerToys test recipes (toggle a module, read an activation shortcut, fire a global hotkey, inspect the clipboard, discover overlay/editor windows), build/run validation, and CI-stability hardening for fewer CI iterations. Keywords: UI test, UITests, UITestAutomation.Next, winappcli, WinAppDriver, Selenium, migrate, port, modernize, .Next, MSTest, CI stability, flaky test, stabilize on CI.
npx skills add https://github.com/microsoft/PowerToys --skill ui-tests-migration
.Next)Convert a PowerToys module's UI tests from the legacy WinAppDriver / Selenium / Appium harness
(Microsoft.PowerToys.UITest, in src/common/UITestAutomation/) to the new winappcli harness
(Microsoft.PowerToys.UITest.Next, in src/common/UITestAutomation.Next/).
The new harness shells out to winapp.exe and parses its JSON — **no WinAppDriver server on :4723,
no Selenium/Appium NuGet packages, no WindowsElement/WindowsDriver.** The public *shape*
(UITestBase, Session, Find<T>, By, element wrappers like ToggleSwitch) is deliberately
similar, so most of the work is mechanical API mapping plus reworking a few patterns that don't
translate one-to-one (XPath selectors, stateful elements, instance mouse/keyboard helpers).
Use this skill when the task is to:
.Next (e.g. "migrate the ScreenRuler UI tests tothe new framework", "convert FancyZones.UITests to winappcli").
[Module].UITests.Next project that re-implements the legacy tests with the newharness, leaving the old project in place.
.Next UI tests for a module that has no UI tests at all, by reading themodule's human test sign-off markdown (e.g. ColorPickerUITest.md) and turning each manual
checklist item into an automated test.
This skill is the *how*: the framework differences, the API mapping, the project scaffolding, the
naming rules, the recurring PowerToys test recipes, and the build/validate loop. The *what* (which
module, which tests) comes from the calling prompt.
> Reference implementation — read these working examples before porting anything. They are
> the ground truth for "what good looks like" with each harness:
> - New (.Next): ColorPickerEndToEndTests.cs
> — full end-to-end scenario (navigate Settings → toggle module → read shortcut → fire hotkey →
> read overlay → click-capture → inspect editor), driven entirely through winappcli.
> - Legacy: TestSpacing.cs
> + TestHelper.cs
> — a UITestBase subclass plus a static helper that navigates, toggles, reads the shortcut, fires
> the hotkey, and validates the clipboard.
> - Worked Scenario-A port (validated 5/5, where the legacy suite scored 0/5 locally): the
> ScreenRuler suite ported from the legacy project above lives in
> ScreenRuler.UITests.Next/TestHelper.cs
> + 5 test classes. It is the canonical port reference — cross-window toolbar discovery via
> Session.FromProcess, a DPI-aware app.manifest, cursor centering, and patient hotkey
> activation are all there because real runs needed them (see
> references/patterns-and-pitfalls.md).
SKILL.md — the decision tree (which scenario), the naming rules, the high-levelworkflow, and the build/validate loop.
deltas you MUST internalize before writing code: winappcli engine, stateless elements, selector
grammar (no XPath/CssSelector), session scopes (window vs process), lifecycle/hygiene/module
pre-enablement, multi-window discovery, and what the new harness does NOT (yet) provide.
namespaces, By, Element actions/properties, Session, UITestBase, the static
Keyboard/Mouse/Clipboard helpers, and the element-wrapper catalog. Keep this open while editing.
rules, .slnx registration, and how to build & run a .Next project. Uses the
templates/ starter files.
playbooks: A) port existing legacy tests, and B) author tests from a human sign-off
markdown when none exist.
for the recurring PowerToys patterns (toggle a module + verify its process, read the activation
shortcut from a ShortcutControl, fire a global hotkey reliably, inspect the clipboard, discover
overlay/editor windows) and the gotchas that bite during migration.
Win32-window vs UIA-element mental model, five design principles that keep a port green on a slow
CI agent (authoritative-signal retries over fixed sleeps, invoke-vs-physical-click, screen-capture
cold-start, toggle-state guards, on-screen/DPI/clean-profile hygiene), and a **pre-flight
checklist** to apply BEFORE the first CI push so the first run *validates* instead of *discovers*.
Read this to spend one CI iteration instead of six.
flowchart TD
A[Module to migrate] --> B{Does a legacy<br/>UITests project exist?}
B -- Yes --> C["Scenario A: PORT<br/>Create [Module].UITests.Next<br/>Re-implement each legacy test"]
B -- No --> D{Is there a human test<br/>sign-off .md?}
D -- Yes --> E["Scenario B: GREENFIELD<br/>Create [Module].UITests<br/>Turn each checklist item into a test"]
D -- No --> F[Ask the user for the<br/>test spec / sign-off doc]
| Scenario | Trigger | New project name | Source of test cases |
|---|---|---|---|
| A — Port | A legacy [Module].UITests (or similar) project already exists and references UITestAutomation.csproj | [Module].UITests.Next — keep the .Next suffix so it lives alongside the legacy project | The existing legacy test methods (1:1 re-implementation) |
| B — Greenfield | The module has no UI tests at all | [Module].UITests — drop the .Next suffix; there's nothing to live alongside | The module's human sign-off markdown (manual checklist), e.g. ColorPickerUITest.md |
Place the new project under src/modules/[Module]/Tests/[Module].UITests.Next/ (or
…/Tests/[Module].UITests/ for Scenario B). If the module already keeps tests in a different
Tests/ layout, match the module's existing convention rather than forcing this one — see
references/project-setup.md.
> Keep it abstract. Every PowerToys module is unique and the legacy tests were written by
> different people in different styles. Treat the recipes in this skill as *adaptable patterns*, not
> a rigid script. Re-create the intent and assertions of each test; do not mechanically translate
> brittle, harness-specific scaffolding (Selenium Actions, XPath walks, manual driver attaches) when
> the new harness has a cleaner idiom.
Create a TODO list and work top-to-bottom. Each step links to the reference that drives it.
- [ ] 1. Identify the module + scenario (A port / B greenfield) — this SKILL.md "Pick your scenario"
- [ ] 2. Read the two reference examples (ColorPicker .Next + ScreenRuler legacy) end-to-end
- [ ] 3. Inventory the source:
• Scenario A → list every [TestMethod] + shared helper in the legacy project
• Scenario B → read the module's sign-off .md; list each manual checklist item
— references/porting-workflow.md
- [ ] 4. Internalize the deltas — references/framework-differences.md
- [ ] 5. Scaffold the new project (csproj from template, name per the table, register in .slnx)
— references/project-setup.md
- [ ] 6. Re-implement tests, mapping each API as you go — references/api-mapping.md
+ recipes from references/patterns-and-pitfalls.md
- [ ] 7. Apply the CI-stability checklist BEFORE building — references/ci-stability.md
(authoritative-signal retries not fixed sleeps, navigation via UIA invoke, Win32 window/overlay
detection, screen-capture cold-start handling, DPI manifest, single-module enable, first-run
suppression)
- [ ] 8. Build the new project to exit code 0 — this SKILL.md "Build & validate"
- [ ] 9. (If a live desktop is available) run the tests; otherwise report that they build and are
ready to run, and summarize coverage vs. the source
The .Next harness needs winapp.exe only at run time, not build time — the project has zero
managed dependency on the engine. So you can always compile-verify a migration even on an agent with
no winappcli installed.
# 0. FIRST build of a brand-new project: restore so the assets file exists, otherwise the build
# fails with NETSDK1004 "Assets file ... project.assets.json not found".
dotnet restore src\modules\<Module>\Tests\<Module>.UITests.Next\<Module>.UITests.Next.csproj -p:Platform=x64
# (Equivalently, run tools\build\build-essentials.cmd once at the start of the session.)
# 1. Build just the new test project (fast inner loop). Prefer the repo build script.
tools\build\build.cmd -Path src\modules\<Module>\Tests\<Module>.UITests.Next -Platform x64 -Configuration Debug
# Exit code 0 = success; non-zero = failure. On failure read the errors log next to the project:
# build.<Configuration>.<Platform>.errors.log
# 2. Run (needs a live desktop). A .Next project is a Microsoft.Testing.Platform Exe — run the
# produced exe directly with a TRX report; filter to one test/category for a tight loop.
$exe = "<repo>\x64\Debug\tests\<Module>.UITests.Next\net10.0-windows10.0.26100.0\<Module>.UITests.Next.exe"
& $exe --filter "TestCategory=<Cat>" --report-trx --report-trx-filename run.trx --results-directory <dir>
# --filter accepts "TestCategory=X" or "FullyQualifiedName~Y"; omit it to run everything.
# Exit 0 = all passed. Parse the .trx for per-test outcomes + failure messages.
Before the first push, walk its pre-flight checklist (authoritative-signal retries instead of fixed
sleeps, navigation via UIA invoke, Win32 window/overlay detection, screen-capture cold-start
handling, DPI manifest, single-module enable, first-run suppression). Most "passes local, fails CI"
loops come from skipping one of these; applying them proactively is how you spend one CI iteration
instead of six.
failures (DPI scaling, cursor position, hotkey-arming races) that only a live run reveals. Start
with one deterministic test (e.g. the activation/toggle test), get it green, then widen.
launches PowerToys via ProcessStartInfo { Verb = "runas" } (elevated), so a non-elevated test
host can't complete the launch and **every test fails at startup with a misleading Win32Exception
cascade** — a false 0/N that looks like "the tests are broken" but is purely the run method. (That's
why VS Test Explorer passes them: VS runs as admin.) Run from an elevated terminal: start
WinAppDriver.exe on 127.0.0.1:4723, then run the built DLL with vstest.console.exe (see
references/porting-workflow.md §A0 for the -Verb RunAs recipe).
A measurement failure on a scaled (non-100%) display is usually a pre-existing DPI issue (Pitfall
12), not something the port must reproduce — the ScreenRuler legacy suite scores 4/5 elevated
here (Bounds fails at 150% scale) while the .Next port scores 5/5. .Next tests themselves
need no elevation (the new harness launches the runner non-elevated).
not leave // TODO: port this stubs that break the build.
winapp.exe(winget install Microsoft.winappcli, or set WINAPP_CLI_PATH). The whole PowerToys runner is
launched by the harness (PowerToys.exe --open-settings) — you should see the Settings window
appear. If the environment has no desktop (headless agent), state that the project **builds clean
and is ready to run**, and list which source tests/checklist items each new [TestMethod] covers.
.csproj files under src/ MUST <Import Project="$(RepoRoot)src\Common.Dotnet.CsWinRT.props" />right after <Project Sdk=...> (CI audits this). The template already does.
[Module].UITests project in Scenario A. The .Next projectlives alongside it; removing the old one is a separate, explicit decision for the maintainers.
doesn't exist (e.g. an AutomationId or a hidden automation-peer TextBlock), flag it for the user
rather than silently editing the module. (The ColorPicker example's ColorHexAutomationPeer hook
is a documented, pre-existing exception — see its class remarks.)
Actions, no WindowsDriver/WindowsElement,no By.XPath/By.CssSelector, no :4723. Map them to the winappcli idioms in
references/api-mapping.md.
ProjectReference to UITestAutomation.csproj (the legacy harness) — referenceUITestAutomation.Next.csproj only.
pass/fail signal, implement what you can and leave a clearly-marked TestContext.WriteLine note
(or skip with an explanation) rather than asserting on something you can't actually read.
.Next harness is intentionallydependency-free (MSTest only). Use the Win32-based helpers it already ships.
Execute Python code in a safe sandboxed environment via [inference.sh](https://inference.sh). Pre-installed: NumPy, Pandas, Matplotlib, requests, BeautifulSoup, Selenium, Playwright, MoviePy, Pillow, OpenCV, trimesh, and 100+ more libraries. Use for: data processing, web scraping, image manipulation, video creation, 3D model processing, PDF generation, API calls, automation scripts. Triggers: python, execute code, run script, web scraping, data analysis, image processing, video editing, 3D models, automation, pandas, matplotlib
Execute Python code in a safe sandboxed environment via [inference.sh](https://inference.sh). Pre-installed: NumPy, Pandas, Matplotlib, requests, BeautifulSoup, Selenium, Playwright, MoviePy, Pillow, OpenCV, trimesh, and 100+ more libraries. Use for: data processing, web scraping, image manipulation, video creation, 3D model processing, PDF generation, API calls, automation scripts. Triggers: python, execute code, run script, web scraping, data analysis, image processing, video editing, 3D models, automation, pandas, matplotlib
Upgrade browser versions (Chrome or Firefox) in the Flutter Web Engine and/or Framework tests. Use when asked to roll or upgrade Chrome or Firefox to a newer version.
> Documentation reference for writing Python code using the browser-use open-source library. Use this skill whenever the user needs help with Agent, Browser, or Tools configuration, is writing code that imports from browser_use, asks about @sandbox deployment, supported LLM models, Actor API, custom tools, lifecycle hooks, MCP server setup, or monitoring/observability with Laminar or OpenLIT. Also trigger for questions about browser-use installation, prompting strategies, or sensitive data handling. Do NOT use this for Cloud API/SDK usage or pricing — use the cloud skill instead. Do NOT use this for directly automating a browser via CLI commands — use the browser-use skill instead.
Run agent-browser + Chrome inside Vercel Sandbox microVMs for browser automation from any Vercel-deployed app. Use when the user needs browser automation in a Vercel app (Next.js, SvelteKit, Nuxt, Remix, Astro, etc.), wants to run headless Chrome without binary size limits, needs persistent browser sessions across commands, or wants ephemeral isolated browser environments. Triggers include "Vercel Sandbox browser", "microVM Chrome", "agent-browser in sandbox", "browser automation on Vercel", or any task requiring Chrome in a Vercel Sandbox.
Use the browse CLI for Browserbase browser automation, Browserbase cloud APIs, Browserbase Functions, templates, web fetch/search, diagnostics, and Browse.sh skill discovery/installation. Use when the user asks to navigate pages, inspect browser state, run local or remote browser sessions, manage Browserbase resources, call Browserbase Functions, browse or scaffold Browserbase templates, fetch or search web content, diagnose browse setup, find or install a skill for a website task, discover site-specific Browse.sh skills, or install/refresh this browse skill.
Turn a website's observable HTTP traffic into a best-effort OpenAPI 3.1 spec by analyzing a `browser-trace` capture. Use when the user wants to discover/extract API endpoints from a browser session, build an OpenAPI doc from network traffic, or document a third-party site's XHR/fetch surface for client integration.
Use when the user asks to use d3k, run/dev/test/debug a web project with d3k, or reproduce a browser issue. Own the runtime: reuse or background-start d3k non-interactively, wait for readiness, use its project-stable managed Chrome profile, and inspect unified browser/server evidence.
Take microsoft/ui-tests-migration from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.