[UI Tests] Enhance UI Test Automation and Pipeline Support for CmdPal Module (#40871)

<!-- 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
This pull request introduces enhancements to UI test automation,
improvements to pipeline configuration, and project structure updates.
The goal is to improve flexibility, maintainability, and efficiency in
PowerToys’ CI/CD processes.

### UI Test Enhancements:
Delayed Text Input Support
- UI tests now support character-by-character text input with
configurable delays.
- This serves as a workaround for a known CmdPal bug where input is
swallowed too quickly. The delay mitigates the issue until it is fixed
in CmdPal.
 
Centralized Environment Management
- Introduced a new class to centralize environment variable access for
UI test configuration.

CmdPal Launch Handling in Pipelines

- Adjusted test logic to handle CmdPal module startup specifically in CI
pipelines



### Pipeline Configuration Updates:
Build Artifact Customization

- Included test-related folders in pipeline build outputs for better
traceability.

Support for Build ID Targeting

- Added support for specifying PowerToys build IDs in test pipelines,
with conditional logic for specific or latest build selection.
<img width="264" height="44" alt="image"
src="https://github.com/user-attachments/assets/0d68a51e-e41a-4868-a1c3-f4233c56b0ee"
/>


### Project Structure Updates:
Added Peek.UITests back to the solution which removed by
https://github.com/microsoft/PowerToys/pull/40754

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **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
This commit is contained in:
leileizhang
2025-07-31 13:55:23 +08:00
committed by GitHub
parent d26ef36e31
commit 9a998b2056
14 changed files with 466 additions and 139 deletions

View File

@@ -123,7 +123,7 @@ jobs:
displayName: Stage UI Test Build Outputs
inputs:
sourceFolder: '$(Build.SourcesDirectory)'
contents: '$(BuildPlatform)/$(BuildConfiguration)/**/*'
contents: '**/$(BuildPlatform)/$(BuildConfiguration)/tests/**/*'
targetFolder: '$(JobOutputDirectory)\$(BuildPlatform)\$(BuildConfiguration)'
- publish: $(JobOutputDirectory)

View File

@@ -11,12 +11,14 @@ parameters:
- name: useLatestWebView2
type: boolean
default: false
- name: useLatestOfficialBuild
type: boolean
default: true
- name: useCurrentBranchBuild
type: boolean
default: false
- name: buildSource
type: string
default: "latestMainOfficialBuild"
displayName: "Build Source"
- name: specificBuildId
type: string
default: "xxxx"
displayName: "Build ID (for specific builds)"
- name: uiTestModules
type: object
default: []
@@ -43,6 +45,7 @@ jobs:
BuildConfiguration: ${{ parameters.configuration }}
SrcPath: $(Build.Repository.LocalPath)
TestArtifactsName: build-${{ variables.BuildPlatform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }}
isBuildNow: ${{ eq(parameters.buildSource, 'buildNow') }}
pool:
${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}:
${{ if ne(parameters.platform, 'ARM64') }}:
@@ -113,16 +116,17 @@ jobs:
& '$(build.sourcesdirectory)\.pipelines\InstallWinAppDriver.ps1'
displayName: Download and install WinAppDriver
- ${{ if eq(parameters.useLatestOfficialBuild, true) }}:
- ${{ if not(variables.isBuildNow) }}:
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'specific'
project: 'Dart'
definition: '76541'
buildVersionToDownload: 'latestFromBranch'
${{ if eq(parameters.useCurrentBranchBuild, true) }}:
branchName: '$(Build.SourceBranch)'
${{ if eq(parameters.buildSource, 'specificBuildId') }}:
buildVersionToDownload: 'specific'
buildId: '${{ parameters.specificBuildId }}'
${{ else }}:
buildVersionToDownload: 'latestFromBranch'
branchName: 'refs/heads/main'
artifactName: 'build-$(BuildPlatform)-Release'
targetPath: '$(Build.ArtifactStagingDirectory)'
@@ -133,7 +137,7 @@ jobs:
patterns: |
**/PowerToysSetup*.exe
- ${{ if eq(parameters.useLatestOfficialBuild, true) }}:
- ${{ if not(variables.isBuildNow) }}:
- ${{ if eq(parameters.installMode, 'peruser') }}:
- pwsh: |-
& "$(build.sourcesdirectory)\.pipelines\installPowerToys.ps1" -InstallMode "PerUser"
@@ -169,7 +173,7 @@ jobs:
!**\UITests-FancyZones\**\UITests-FancyZonesEditor.dll
env:
platform: '$(TestPlatform)'
useInstallerForTest: ${{ parameters.useLatestOfficialBuild }}
useInstallerForTest: ${{ not(variables.isBuildNow) }}
- ${{ if ne(length(parameters.uiTestModules), 0) }}:
- ${{ each module in parameters.uiTestModules }}:
@@ -191,4 +195,4 @@ jobs:
!**\UITests-FancyZones\**\UITests-FancyZonesEditor.dll
env:
platform: '$(TestPlatform)'
useInstallerForTest: ${{ parameters.useLatestOfficialBuild }}
useInstallerForTest: ${{ not(variables.isBuildNow) }}

View File

@@ -3,6 +3,8 @@ variables:
value: false
- name: EnablePipelineCache
value: true
- name: isBuildNow
value: ${{ eq(parameters.buildSource, 'buildNow') }}
parameters:
- name: buildPlatforms
@@ -19,22 +21,25 @@ parameters:
- name: useLatestWebView2
type: boolean
default: false
- name: useLatestOfficialBuild
type: boolean
default: true
- name: testBothInstallModes
type: boolean
default: true
- name: useCurrentBranchBuild
type: boolean
default: false
- name: buildSource
type: string
default: "latestMainOfficialBuild"
displayName: "Build Source"
values:
- latestMainOfficialBuild
- buildNow
- specificBuildId
- name: specificBuildId
type: string
default: 'xxxx'
displayName: "Build ID (only used when Build Source = specificBuildId)"
- name: uiTestModules
type: object
default: []
stages:
- ${{ each platform in parameters.buildPlatforms }}:
- ${{ if eq(parameters.useLatestOfficialBuild, false) }}:
- ${{ if variables.isBuildNow }}:
- stage: Build_${{ platform }}
displayName: Build ${{ platform }}
dependsOn: []
@@ -58,7 +63,7 @@ stages:
useVSPreview: ${{ parameters.useVSPreview }}
timeoutInMinutes: 90
- ${{ if eq(parameters.useLatestOfficialBuild, true) }}:
- ${{ if not(variables.isBuildNow) }}:
- stage: BuildUITests_${{ platform }}
displayName: Build UI Tests Only
dependsOn: []
@@ -79,7 +84,7 @@ stages:
- ${{ if eq(platform, 'x64') }}:
- stage: Test_x64Win10
displayName: Test x64Win10
${{ if eq(parameters.useLatestOfficialBuild, true) }}:
${{ if not(variables.isBuildNow) }}:
dependsOn:
- BuildUITests_${{ platform }}
${{ else }}:
@@ -91,19 +96,19 @@ stages:
platform: x64Win10
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
uiTestModules: ${{ parameters.uiTestModules }}
# Additional per-user installation test (when both modes are enabled)
- ${{ if and(eq(parameters.useLatestOfficialBuild, true), eq(parameters.testBothInstallModes, true)) }}:
# Additional per-user installation test
- ${{ if not(variables.isBuildNow) }}:
- template: job-test-project.yml
parameters:
platform: x64Win10
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
uiTestModules: ${{ parameters.uiTestModules }}
installMode: 'peruser'
jobSuffix: '_PerUser'
@@ -111,7 +116,7 @@ stages:
- ${{ if eq(platform, 'x64') }}:
- stage: Test_x64Win11
displayName: Test x64Win11
${{ if eq(parameters.useLatestOfficialBuild, true) }}:
${{ if not(variables.isBuildNow) }}:
dependsOn:
- BuildUITests_${{ platform }}
${{ else }}:
@@ -123,19 +128,19 @@ stages:
platform: x64Win11
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
uiTestModules: ${{ parameters.uiTestModules }}
# Additional per-user installation test (when both modes are enabled)
- ${{ if and(eq(parameters.useLatestOfficialBuild, true), eq(parameters.testBothInstallModes, true)) }}:
# Additional per-user installation test
- ${{ if not(variables.isBuildNow) }}:
- template: job-test-project.yml
parameters:
platform: x64Win11
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
uiTestModules: ${{ parameters.uiTestModules }}
installMode: 'peruser'
jobSuffix: '_PerUser'
@@ -143,7 +148,7 @@ stages:
- ${{ if ne(platform, 'x64') }}:
- stage: Test_${{ platform }}
displayName: Test ${{ platform }}
${{ if eq(parameters.useLatestOfficialBuild, true) }}:
${{ if not(variables.isBuildNow) }}:
dependsOn:
- BuildUITests_${{ platform }}
${{ else }}:
@@ -155,19 +160,19 @@ stages:
platform: ${{ platform }}
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
uiTestModules: ${{ parameters.uiTestModules }}
# Additional per-user installation test (when both modes are enabled)
- ${{ if and(eq(parameters.useLatestOfficialBuild, true), eq(parameters.testBothInstallModes, true)) }}:
# Additional per-user installation test
- ${{ if not(variables.isBuildNow) }}:
- template: job-test-project.yml
parameters:
platform: ${{ platform }}
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
uiTestModules: ${{ parameters.uiTestModules }}
installMode: 'peruser'
jobSuffix: '_PerUser'
jobSuffix: '_PerUser'