Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions .github/skills/test-on-vm/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
name: test-on-vm
description: EXPERIMENTAL. Run locally built WinUI interaction tests on a Hyper-V VM through PowerShell Direct. Use when asked to run WinUI tests on a local VM.
---

# Run WinUI Tests on a Hyper-V VM

Run `tools\run-tests-on-vm.ps1` through `initrun.ps1`. It refreshes the local
test payload, deploys it to the VM, performs required machine setup, and runs
tests on the VM's interactive desktop.

This skill and script are experimental and may not be stable.

## Before You Run

Build the repository first. Follow the **build** skill:

```powershell
.\initrun.ps1 .\build.cmd /q
```

Also verify:

- The VM is running with an unlocked desktop and a logged-in user.
- The caller is a local admin or a member of **Hyper-V Administrators**.
- The command uses `initial_wait` of at least **180 seconds**.

If Hyper-V permissions are missing, **do not add the user to the group**. Tell
the user to open an administrator PowerShell window and run this command
themselves:

```powershell
Add-LocalGroupMember -Group 'Hyper-V Administrators' -Member (whoami)
```

Tell the user to sign out and back in afterward. Wait for them to confirm they
have completed these steps before retrying the test.

The first run prompts for VM credentials in a separate window and caches them
encrypted under `~\.winui-test`. Use `-ResetCredential` to replace them.

## Run Tests

```powershell
# Run a specific test
.\initrun.ps1 .\tools\run-tests-on-vm.ps1 -VMName <vm> <testname>

# Wildcard match
.\initrun.ps1 .\tools\run-tests-on-vm.ps1 -VMName <vm> *CommandBar*

# Force full copy instead of incremental
.\initrun.ps1 .\tools\run-tests-on-vm.ps1 -VMName <vm> -FullCopy <testname>

# Stop a stuck test run
.\initrun.ps1 .\tools\run-tests-on-vm.ps1 -VMName <vm> -Stop
```

## Payload Rules

By default, the script runs `test\CreateTestPayload.ps1` to refresh
`TestPayload\<flavor>` from the current build outputs, then deploys changed
files incrementally.

- `-FullCopy` still refreshes the local payload, then copies all of it to the VM.
- **Use `-SkipPayload` rarely.** It deploys the existing local payload without
refreshing it. Use it only when that payload is known to be current or when
intentionally testing stale binaries. Never use it merely to save time.

## Useful Options

| Option | Purpose |
|--------|---------|
| `-Platform` | `x86`, `x64`, or `arm64`; uses `$env:BUILDPLATFORM`, then defaults to `x64` |
| `-Configuration` | `chk` or `fre`; uses `$env:_BuildType`, then defaults to `chk` |
| `-FullCopy` | Copy the full refreshed payload instead of only changes |
| `-SkipPayload` | Rare: deploy the existing payload without refreshing it |
| `-SkipPrerun` | Skip `testmachine-prerun.cmd` |
| `-ForcePrerun` | Run `testmachine-prerun.cmd` again |
| `-Credential` | Supply a `PSCredential` instead of using the prompt/cache |
| `-ResetCredential` | Clear the cached credential for this VM |
| `-Stop` | Stop the active test and clean up |

## Troubleshooting

| Symptom | Cause | Fix |
|---------|-------|-----|
| `Could not launch app`, foreground-window errors, or an empty UIA tree | VM desktop is locked or not visible | Keep the VM desktop unlocked and active |
| `Failed to connect to VM` | VM not running or wrong credentials | Start the VM; use `-ResetCredential` to re-enter credentials |
| Permission error | Need Hyper-V Administrators membership | Have the user follow the permission steps above |
| Incomplete payload or prerun failure | Stale payload or partial deployment | Omit `-SkipPayload`; retry with `-FullCopy` if needed |

## Crash Dumps

The first prerun configures full crash dumps under `C:\dumps` on the VM, with
up to three dumps per process. Pull one back through PowerShell Direct:

```powershell
$vmName = "<vm>"
$credentialKey = $vmName -replace '[^a-zA-Z0-9]', '_'
$cred = Import-Clixml (Join-Path $env:USERPROFILE ".winui-test\vmcred-$credentialKey.xml")
$destination = Join-Path $env:TEMP "WinUIDumps"
New-Item -ItemType Directory -Path $destination -Force | Out-Null

$session = New-PSSession -VMName $vmName -Credential $cred
try {
Invoke-Command -Session $session { Get-ChildItem C:\dumps\*.dmp }
Copy-Item -FromSession $session -Path "C:\dumps\<dump>.dmp" -Destination $destination
}
finally {
Remove-PSSession $session
}
```

For a quick local analysis:

```powershell
cdb -z "$env:TEMP\WinUIDumps\<dump>.dmp" -c "!analyze -v; ~*k; q"
```
10 changes: 5 additions & 5 deletions tools/run-tests-on-vm.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# .\run-tests-on-vm.ps1 -VMName "MyVM" "Button*" -HostingMode WPF
# .\run-tests-on-vm.ps1 -VMName "MyVM" "MyTest" -SkipPayload
# .\run-tests-on-vm.ps1 -VMName "MyVM" "MyTest" -FullCopy
# .\run-tests-on-vm.ps1 -VMName "MyVM" -Stop # kill any running test
# .\run-tests-on-vm.ps1 -VMName "MyVM" -Stop
#
# First run will prompt for VM credentials and cache them (encrypted, per-user).
# Subsequent runs reuse the cached credential automatically.
Expand Down Expand Up @@ -37,7 +37,7 @@ param(
[switch]$SkipPayload,

# CreateTestPayload mode. Most tests use DevTestSuite.
[ValidateSet("Auto", "DevTestSuite", "All", "PGO")]
[ValidateSet("Auto", "DevTestSuite")]
[string]$Mode = "Auto",

# Force a full copy instead of incremental
Expand Down Expand Up @@ -153,7 +153,7 @@ function Connect-TestVM {
Write-Host "Error: PS Direct requires local admin or 'Hyper-V Administrators' membership." -ForegroundColor Red
Write-Host ""
Write-Host " One-time fix (run once from an admin prompt, then log out and back in):" -ForegroundColor Yellow
Write-Host " Add-LocalGroupMember -Group 'Hyper-V Administrators' -Member `$env:USERNAME" -ForegroundColor White
Write-Host " Add-LocalGroupMember -Group 'Hyper-V Administrators' -Member (whoami)" -ForegroundColor White
exit 1
}

Expand Down Expand Up @@ -659,7 +659,7 @@ echo %ERRORLEVEL% > "$exitFile"

# -- Resolve platform/config --------------------------------------------
if (-not $Platform) {
$Platform = if ($env:BUILDPLATFORM) { $env:BUILDPLATFORM } else { "x86" }
$Platform = if ($env:BUILDPLATFORM) { $env:BUILDPLATFORM } else { "x64" }
}
if (-not $Configuration) {
$Configuration = if ($env:_BuildType) { $env:_BuildType } else { "chk" }
Expand All @@ -668,7 +668,7 @@ if (-not $Configuration) {
$Flavor = "$Platform$Configuration"
$repoRoot = $env:reporoot
if (-not $repoRoot -or -not (Test-Path $repoRoot)) {
Write-Host "Error: reporoot env var is not set. Run via initrun.ps1 or from a WinUI dev prompt." -ForegroundColor Red
Write-Host "Error: reporoot env var is not set. Run from a WinUI dev prompt." -ForegroundColor Red
exit 1
}

Expand Down
Loading