Skip to content

[Settings] Add navigation smoke test using winapp CLI (no WinAppDriver)#48414

Closed
crutkas wants to merge 2 commits into
microsoft:mainfrom
crutkas:user/crutkas/uitest-settings-navigation-smoke-winapp
Closed

[Settings] Add navigation smoke test using winapp CLI (no WinAppDriver)#48414
crutkas wants to merge 2 commits into
microsoft:mainfrom
crutkas:user/crutkas/uitest-settings-navigation-smoke-winapp

Conversation

@crutkas

@crutkas crutkas commented Jun 9, 2026

Copy link
Copy Markdown
Member

Why this exists

ShellViewModel.HandleNavigationFailure and ShellViewModel.GetPageDisplayName (the helpers introduced/expanded in #48409 / #48410) cover the pure-logic half of the navigation-failure regression. They cannot reach the original FailFast path: NavigationFailedEventArgs is a sealed WinRT projection that can't be constructed from MSTest, so any regression that re-introduces "page constructor throws → unhandled in Frame_NavigationFailedRoFailFast" sails right past the unit tests.

This PR adds the runtime counterpart: a smoke test that drives a real Settings shell and asserts the process is still alive after clicking every NavigationViewItem.

Framework

This test deliberately does not use Appium.WebDriver / WinAppDriver — the existing src\settings-ui\UITest-Settings project's stack. Instead it drives the running Settings shell through the Windows App Development CLI (winapp), which exposes a UI Automation surface (winapp ui invoke|wait-for|screenshot|inspect|search|get-property|click|set-value|...) against any running app — WinUI 3, WPF, WinForms, Win32, Electron. No daemon, no driver process, no Appium server.

winapp is currently in public preview; this PR introduces it as an opt-in test dependency in a brand-new project so it does not affect the existing Appium-based tests or anything else. If the maintainers would rather keep WinAppDriver as the only sanctioned UI test path, this PR can be closed without touching anything else in the repo.

Project layout

New project: src/settings-ui/WinAppCli.UITest-Settings/

  • WinAppCli.UITest-Settings.csproj — plain MSTest. No Appium.WebDriver reference. Mirrors the existing UI test csproj conventions (<RunVSTest>false</RunVSTest>, <OutputPath>$(RepoRoot)$(Platform)\$(Configuration)\tests\WinAppCli.UITests-Settings\</OutputPath>).
  • WinAppCli.cs — thin wrapper around Process.Start("winapp", "ui …") with Invoke, WaitFor, Screenshot, and IsAvailable. Returns a record with exit code + stdout/stderr + a DescribeFailure() helper for clean assertion messages.
  • SettingsHost.cs — owns the PowerToys.Settings.exe process for the class. Locates the exe in either an installed PowerToys path or alongside the test assembly (dev build), and waits for MainWindowHandle before returning.
  • NavigationSmokeTests.cs — one [TestMethod] (parameterized via [DynamicData]) that produces a discrete test result per nav item. Each row clicks one item via winapp ui invoke <AutomationId> -a <pid> (parent groups are expanded on first encounter), and then asserts PowerToys.Settings.exe has not exited.

Splitting the helper into one file each keeps the test source itself small — the alternative reference shape (one long PowerShell script that pipes winapp ui … calls together) doesn't fit cleanly into how PowerToys discovers and runs its existing MSTest UI test projects.

Why one [TestMethod] per nav item, parameterized via [DynamicData]

  • Gives a discrete pass/fail per nav item in TestExplorer / pipeline reports — if MeasureToolNavItem regresses, the report says so by name.
  • Keeps source minimal: the navigation table is a static array; the test body is a dozen lines.
  • The class-level [ClassInitialize] / [ClassCleanup] launches Settings exactly once and tears it down at the end — every row exercises navigation against the same process so the "did the process die" check is meaningful.

AutomationId-based selectors

Every selector is the AutomationId already attached in ShellPage.xaml (e.g. DashboardNavItem, FancyZonesNavItem, SystemToolsNavItem). This keeps the test localization-independent — display strings change with the user's MUI language but AutomationIds do not.

Parent group items (SystemToolsNavItem, WindowingAndLayoutsNavItem, InputOutputNavItem, FileManagementNavItem, AdvancedNavItem) have SelectsOnInvoked="False" and only expand on click. winapp ui invoke tries InvokePattern, TogglePattern, SelectionItemPattern, then ExpandCollapsePattern in order, so the same Invoke call works for both navigation-y leaves and expand-y groups.

Pipeline notes

  • Project sits in the new /settings-ui/Tests/ slnx folder alongside Settings.UI.UnitTests.csproj.
  • <RunVSTest>false</RunVSTest> matches every other UI test project in the repo — the test doesn't run in a regular MSBuild and only fires in the UI test pipeline.
  • The UI test pipeline (per doc/devdocs/development/ui-tests.md) selects projects via the uiTestModules parameter — this csproj's assembly name is WinAppCli.UITests-Settings, which is what would go in that list to opt in.
  • Running this test class requires winapp on PATH. The pipeline can install it with winget install Microsoft.winappcli or the setup-WinAppCli action. [ClassInitialize] calls WinAppCli.IsAvailable() and fails the whole class with a useful error message (rather than producing 30 opaque per-test failures) if the CLI is missing.

How this was validated locally

  • The C# in all three files compiles clean (0 Warning(s), 0 Error(s)) against net10.0-windows MSTest. The PowerToys-side restore is currently failing on my dev box for every csproj under src/settings-ui/UITest-Settings and friends because the local NuGet cache wants runtime packs at a version the cached feed no longer has — that's a pre-existing local-env issue, not something this PR introduces. Pipeline restore uses a different feed and is expected to be fine.
  • winapp 0.3.2 was installed via winget and the ui subcommand surface (invoke, wait-for, screenshot, inspect, search, get-property, click, set-value, etc.) was verified to match what this PR depends on.

Risk

  • New test project; no production code changes.
  • Does not touch the existing UITest-Settings (WinAppDriver) project — both can coexist.
  • If winapp is unavailable, the class fails fast with a clear message; it cannot quietly skip and report green.

Replaces

This supersedes a draft I closed at #48411, which used WinAppDriver/Appium for the same coverage. Same test goal; new transport.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Adds a brand-new test project (src/settings-ui/WinAppCli.UITest-Settings/) that drives the Settings shell through the Windows App Development CLI's UI Automation surface (winapp ui invoke / wait-for / etc.). One TestMethod row per NavigationViewItem covers every shell entry; assertion is that PowerToys.Settings.exe stays alive after each click.

This is the runtime counterpart to the unit tests on ShellViewModel.HandleNavigationFailure (microsoft#48410). The unit tests cannot reach the FailFast path because NavigationFailedEventArgs is a sealed WinRT type; this smoke test is what would catch a regression that re-introduces 'throw from Frame_NavigationFailed' or any module page whose constructor throws.

Deliberately does NOT use Appium.WebDriver / WinAppDriver - exists as a standalone project alongside the existing UITest-Settings project. Supersedes the closed microsoft#48411 which used the older stack.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/settings-ui/WinAppCli.UITest-Settings/NavigationSmokeTests.cs Fixed
Comment thread src/settings-ui/WinAppCli.UITest-Settings/NavigationSmokeTests.cs Fixed
Comment thread src/settings-ui/WinAppCli.UITest-Settings/NavigationSmokeTests.cs Fixed
Comment thread src/settings-ui/WinAppCli.UITest-Settings/NavigationSmokeTests.cs Fixed
Comment thread src/settings-ui/WinAppCli.UITest-Settings/WinAppCli.cs Fixed
Comment thread src/settings-ui/WinAppCli.UITest-Settings/WinAppCli.cs Fixed
Comment thread src/settings-ui/WinAppCli.UITest-Settings/WinAppCli.cs Fixed
Comment thread src/settings-ui/WinAppCli.UITest-Settings/WinAppCli.cs Fixed
Comment thread src/settings-ui/WinAppCli.UITest-Settings/WinAppCli.cs Fixed
@github-actions

This comment has been minimized.

- Add 'winapp' and 'winappcli' to .github/actions/spell-check/expect.txt (the project and CLI name; preserves alphabetical order alongside the existing 'winappsdk' entry).

- Reword the comment above the post-invoke Thread.Sleep in NavigationSmokeTests.cs so it no longer matches the line_forbidden.patterns rule about consecutive articles.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@crutkas

crutkas commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

Pushed a follow-up commit (12c3a78) addressing the spelling check:

  • Added winapp and winappcli to .github/actions/spell-check/expect.txt (alphabetical, next to the existing winappsdk entry — these are the project name and CLI command name, similar to how winappsdk is already on the list).
  • Reworded the comment above the post-invoke Thread.Sleep in NavigationSmokeTests.cs so it no longer matches the line_forbidden.patterns rule about consecutive articles. Same intent, different phrasing.

PowerToys CI (Build x64 / Build arm64) failures look unrelated to this PR.
The failing task is Verify Nuget package versions for PowerToys.slnx (log 87). The errors are NU1102 against projects that this PR does not touch — Awake.ModuleServices.csproj, PowerOCR.csproj, QoiPreviewHandler.csproj, etc. — for runtime packs like Microsoft.NETCore.App.Runtime.win-x64 = 10.0.9 where the feed only has 11.0.0-preview.1.26104.118. That looks like a PowerToysPublicDependencies feed-version mismatch rather than something introduced by this branch (I see the same failures when restoring those projects locally on a clean clone of main). Happy to retry once the feed catches up, but a heads-up so the failing checks here aren't read as something this PR needs to fix.

@crutkas crutkas marked this pull request as draft June 10, 2026 15:03
@crutkas

crutkas commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

Pushed a follow-up commit (12c3a78) addressing the spelling check:

  • Added winapp and winappcli to .github/actions/spell-check/expect.txt (alphabetical, next to the existing winappsdk entry — these are the project name and CLI command name, similar to how winappsdk is already on the list).
  • Reworded the comment above the post-invoke Thread.Sleep in NavigationSmokeTests.cs so it no longer matches the line_forbidden.patterns rule about consecutive articles. Same intent, different phrasing.

PowerToys CI (Build x64 / Build arm64) failures look unrelated to this PR.
The failing task is Verify Nuget package versions for PowerToys.slnx (log 87). The errors are NU1102 against projects that this PR does not touch — Awake.ModuleServices.csproj, PowerOCR.csproj, QoiPreviewHandler.csproj, etc. — for runtime packs like Microsoft.NETCore.App.Runtime.win-x64 = 10.0.9 where the feed only has 11.0.0-preview.1.26104.118. That looks like a PowerToysPublicDependencies feed-version mismatch rather than something introduced by this branch (I see the same failures when restoring those projects locally on a clean clone of main). Happy to retry once the feed catches up, but a heads-up so the failing checks here aren't read as something this PR needs to fix.

@crutkas

crutkas commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

closing out as this work was absorbed into #48467

@crutkas crutkas closed this Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants