mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-08-29 10:09:43 +02:00
## Summary Adds end‑to‑end UI tests on the `Microsoft.PowerToys.UITest.Next` (winappcli) framework for three modules, grows the shared `.Next` test framework with the helpers those suites needed, and adds the CI plumbing that lets shell‑extension tests exercise the **real** Windows 11 modern context menu. Also ships two agent skills that document how to write and run these tests. Product runtime behavior is **unchanged** — the only product edits are test‑observability hooks in Peek and a unit‑test project exclude. Closes: https://github.com/microsoft/PowerToys/issues/40660 https://github.com/microsoft/PowerToys/issues/49424 https://github.com/microsoft/PowerToys/issues/40661 ## What's added ### New UI test suites - **Image Resizer** — `src/modules/imageresizer/tests/ImageResizer.UITests`: context‑menu enable/disable tracking, the resize dialog, custom presets, every fit mode, every unit, filename format, keep‑date, shrink‑only, replace‑in‑place, and orientation. - **Peek** — `src/modules/peek/Peek.UITests.Next`: file‑preview coverage across image/text/archive/ markdown types with per‑arch visual baselines. - **File Explorer add‑ons** — `src/modules/previewpane/PreviewPane.UITests`: Preview Pane handlers and thumbnail providers. ### `UITestAutomation.Next` framework - New helpers: `ExplorerShell` (Shell selection/view‑mode interop), `WaitHelper` (structured stable waits), `WindowControl` (foreground/context‑menu/process control), `VisualAssert` (image compare), `WindowHelper`. - Updates to `Session`, `UITestBase`, `SettingsConfigHelper`, `WinappCli`. - New `UITestAutomation.Next.UnitTests` project covering the new wait/settings/CLI helpers. ### CI — sign sparse MSIX so the modern menu registers - **`.pipelines/signSparsePackages.ps1`** — self‑signs each sparse context‑menu MSIX with a publisher‑matching test certificate and force‑trusts it (machine stores), so `AddPackageByUriAsync` succeeds on otherwise‑unsigned PR builds. Robust `signtool` discovery with a NuGet fallback; test‑only trust that asserts no security. - Wired into **`.pipelines/v2/templates/job-test-project.yml`** as a best‑effort step covering the run‑in‑place, machine‑install, and per‑user‑install locations. Signs nothing it can't (skips already‑signed packages) and never fails the job. ### Product changes (test observability only) - **Peek `FilePreview.xaml` / `.xaml.cs`** — a named `LoadingIndicator` and a hidden automation peer that exposes the current preview state as text, so tests can read load state deterministically. No runtime behavior change. - **`ImageResizer.UnitTests.csproj`** — exclude the sibling `ImageResizer.UITests\**` folder from the unit‑test compilation. ### Agent skills & docs - **New `ui-tests-local-vm` skill** — run `.Next` suites in persistent dockur/windows VMs: setup, agentic loop, image customization, troubleshooting, the shell‑extension **signing** reference, plus controller/guest scripts and VM templates. - **Updated `ui-tests-migration` skill** — WinAppDriver/Selenium → `.Next` porting guidance (CI stability, Explorer/shell‑extension test design, patterns & pitfalls). - **`doc/devdocs/development/ui-tests.md`** — updated for the `.Next` workflow. ## Testing - All three suites pass locally and in CI across **x64 Win10**, **x64 Win11**, and **arm64** (machine and per‑user install legs). ## Reviewer notes - No product runtime behavior changes; product edits are limited to the Peek test hooks above. - The CI signing step is a **test‑only** trust anchor (self‑signed, scoped to the agent) and is best‑effort, so it can only add modern‑menu coverage and never regress the job.
107 lines
3.4 KiB
PowerShell
107 lines
3.4 KiB
PowerShell
# Copyright (c) Microsoft Corporation
|
|
# The Microsoft Corporation licenses this file to you under the MIT license.
|
|
# See the LICENSE file in the project root for more information.
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Manages clean-baseline checkpoints for the Hyper-V UI-test guest.
|
|
|
|
.DESCRIPTION
|
|
Restoring a standard checkpoint returns the guest to the exact state it was captured in, including
|
|
the logged-on desktop, which makes it the fast equivalent of recreating the VM. Use it for every
|
|
clean-profile claim instead of trusting a long-lived, mutated guest.
|
|
|
|
.EXAMPLE
|
|
pwsh ./Reset-LocalVm.ps1 -List
|
|
|
|
.EXAMPLE
|
|
pwsh ./Reset-LocalVm.ps1 -Restore
|
|
|
|
.EXAMPLE
|
|
pwsh ./Reset-LocalVm.ps1 -CreateBaseline -CheckpointName 'webview2-installed'
|
|
#>
|
|
|
|
[CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'List')]
|
|
param(
|
|
[string]$ConfigPath = (Join-Path $PSScriptRoot 'vm.config.psd1'),
|
|
|
|
[Parameter(ParameterSetName = 'List')]
|
|
[switch]$List,
|
|
|
|
[Parameter(Mandatory, ParameterSetName = 'Restore')]
|
|
[switch]$Restore,
|
|
|
|
[Parameter(Mandatory, ParameterSetName = 'Create')]
|
|
[switch]$CreateBaseline,
|
|
|
|
[Parameter(ParameterSetName = 'Restore')]
|
|
[Parameter(ParameterSetName = 'Create')]
|
|
[string]$CheckpointName,
|
|
|
|
[Parameter(ParameterSetName = 'Restore')]
|
|
[switch]$StartAfterRestore
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
if (-not (Test-Path $ConfigPath -PathType Leaf)) {
|
|
throw "Configuration was not found: $ConfigPath"
|
|
}
|
|
$configuration = Import-PowerShellDataFile $ConfigPath
|
|
$effectiveCheckpoint = if ([string]::IsNullOrWhiteSpace($CheckpointName)) {
|
|
$configuration.BaselineCheckpointName
|
|
}
|
|
else {
|
|
$CheckpointName
|
|
}
|
|
|
|
try {
|
|
Import-Module Hyper-V -ErrorAction Stop
|
|
Get-VMHost -ErrorAction Stop | Out-Null
|
|
}
|
|
catch {
|
|
throw 'BLOCKED: Hyper-V is not accessible from this shell. Run from an elevated PowerShell 7 terminal, or add this account to the local "Hyper-V Administrators" group.'
|
|
}
|
|
|
|
$vm = Get-VM -Name $configuration.VmName -ErrorAction SilentlyContinue
|
|
if ($null -eq $vm) {
|
|
throw "Virtual machine '$($configuration.VmName)' does not exist."
|
|
}
|
|
|
|
if ($CreateBaseline) {
|
|
if ($PSCmdlet.ShouldProcess($vm.Name, "Create checkpoint '$effectiveCheckpoint'")) {
|
|
Get-VMCheckpoint -VMName $vm.Name -Name $effectiveCheckpoint -ErrorAction SilentlyContinue |
|
|
Remove-VMCheckpoint -Confirm:$false
|
|
Checkpoint-VM -Name $vm.Name -SnapshotName $effectiveCheckpoint
|
|
}
|
|
}
|
|
elseif ($Restore) {
|
|
$checkpoint = Get-VMCheckpoint -VMName $vm.Name -Name $effectiveCheckpoint -ErrorAction SilentlyContinue
|
|
if ($null -eq $checkpoint) {
|
|
throw "Checkpoint '$effectiveCheckpoint' does not exist for '$($vm.Name)'."
|
|
}
|
|
if ($PSCmdlet.ShouldProcess($vm.Name, "Restore checkpoint '$effectiveCheckpoint'")) {
|
|
if ($vm.State -eq 'Running') {
|
|
Stop-VM -Name $vm.Name -TurnOff -Force
|
|
}
|
|
Restore-VMCheckpoint -VMName $vm.Name -Name $effectiveCheckpoint -Confirm:$false
|
|
if ($StartAfterRestore) {
|
|
Start-VM -Name $vm.Name
|
|
}
|
|
}
|
|
}
|
|
|
|
$vm = Get-VM -Name $configuration.VmName
|
|
[pscustomobject]@{
|
|
VmName = $vm.Name
|
|
State = [string]$vm.State
|
|
BaselineCheckpointName = $configuration.BaselineCheckpointName
|
|
Checkpoints = @(Get-VMCheckpoint -VMName $vm.Name -ErrorAction SilentlyContinue | ForEach-Object {
|
|
[pscustomobject]@{
|
|
Name = $_.Name
|
|
CreationTime = $_.CreationTime
|
|
ParentCheckpointName = $_.ParentCheckpointName
|
|
}
|
|
})
|
|
} | ConvertTo-Json -Depth 4
|