mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
[UI automation] workspaces ui automation (#39812)
<!-- 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 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] **Closes:** #xxx - [ ] **Communication:** I've discussed this with core contributors already. If 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  https://microsoft.visualstudio.com/Dart/_build/results?buildId=125637396&view=results --------- Signed-off-by: Shawn Yuan <shuai.yuan.zju@gmail.com> Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com> Co-authored-by: Jerry Xu <n.xu@outlook.com> Co-authored-by: Zhaopeng Wang <zhaopengwang@microsoft.com> Co-authored-by: Xiaofeng Wang (from Dev Box) <xiaofengwang@microsoft.com> Co-authored-by: Mengyuan <162882040+chenmy77@users.noreply.github.com> Co-authored-by: yaqingmi <miyaqing01@gmail.com> Co-authored-by: Clint Rutkas <clint@rutkas.com> Co-authored-by: Yaqing Mi (from Dev Box) <yaqingmi@microsoft.com> Co-authored-by: XiaofengWang <709586527@qq.com> Co-authored-by: zhaopeng wang <33367956+wang563681252@users.noreply.github.com> Co-authored-by: Laszlo Nemeth <57342539+donlaci@users.noreply.github.com> Co-authored-by: RokyZevon <12629919+RokyZevon@users.noreply.github.com> Co-authored-by: Yu Leng <42196638+moooyo@users.noreply.github.com> Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> Co-authored-by: Davide Giacometti <25966642+davidegiacometti@users.noreply.github.com> Co-authored-by: Gordon Lam <73506701+yeelam-gordon@users.noreply.github.com> Co-authored-by: ruslanlap <106077551+ruslanlap@users.noreply.github.com> Co-authored-by: Muhammad Danish <mdanishkhdev@gmail.com> Co-authored-by: Bennett Blodinger <benwa@users.noreply.github.com> Co-authored-by: Jaime Bernardo <jaime@janeasystems.com> Co-authored-by: Ionuț Manța <ionut@janeasystems.com> Co-authored-by: Hao Liu <liuhaobupt@163.com> Co-authored-by: OlegHarchevkin <40352094+OlegKharchevkin@users.noreply.github.com> Co-authored-by: dcog989 <89043002+dcog989@users.noreply.github.com> Co-authored-by: PesBandi <127593627+PesBandi@users.noreply.github.com> Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com> Co-authored-by: Typpi <20943337+Nick2bad4u@users.noreply.github.com> Co-authored-by: Mike Griese <migrie@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Abhyudit <64366765+bitmap4@users.noreply.github.com> Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com> Co-authored-by: Ved Nig <vednig12@outlook.com> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Aung Khaing Khant <aungkhaingkhant.dev@gmail.com> Co-authored-by: Aung Khaing Khant <aungkhaingkhant@advent-soft.com> Co-authored-by: Dustin L. Howett <duhowett@microsoft.com> Co-authored-by: leileizhang <leilzh@microsoft.com> Co-authored-by: Dustin L. Howett <dustin@howett.net> Co-authored-by: Shawn Yuan <128874481+shuaiyuanxx@users.noreply.github.com> Co-authored-by: Shawn Yuan <shuai.yuan.zju@gmail.com> Co-authored-by: cryolithic <cryolithic@gmail.com> Co-authored-by: Lemonyte <49930425+lemonyte@users.noreply.github.com> Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com> Co-authored-by: Corey Hayward <72159232+CoreyHayward@users.noreply.github.com> Co-authored-by: Jerry Xu <nxu@microsoft.com> Co-authored-by: Shawn Yuan <shuaiyuan@microsoft.com> Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com> Co-authored-by: Jeremy Sinclair <4016293+snickler@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<Page
|
||||
<Page
|
||||
x:Class="WorkspacesEditor.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -172,7 +172,7 @@
|
||||
VerticalContentAlignment="Stretch"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Visibility="{Binding IsWorkspacesViewEmpty, Mode=OneWay, Converter={StaticResource BooleanToInvertedVisibilityConverter}, UpdateSourceTrigger=PropertyChanged}">
|
||||
<ItemsControl ItemsSource="{Binding WorkspacesView, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
|
||||
<ItemsControl x:Name="WorkspacesItemsControl" ItemsSource="{Binding WorkspacesView, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel
|
||||
@@ -235,7 +235,10 @@
|
||||
Grid.Column="1"
|
||||
Margin="12,12,12,12"
|
||||
Orientation="Vertical">
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<StackPanel
|
||||
x:Name="WorkspaceActionGroup"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="MoreButton"
|
||||
HorizontalAlignment="Right"
|
||||
@@ -248,7 +251,8 @@
|
||||
</Button>
|
||||
<Popup
|
||||
AllowsTransparency="True"
|
||||
IsOpen="{Binding IsPopupVisible, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Closed="PopupClosed"
|
||||
IsOpen="{Binding IsPopupVisible, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Placement="Left"
|
||||
PlacementTarget="{Binding ElementName=MoreButton}"
|
||||
StaysOpen="False">
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
using System.Windows.Controls.Primitives;
|
||||
using ManagedCommon;
|
||||
using WorkspacesEditor.Models;
|
||||
using WorkspacesEditor.ViewModels;
|
||||
|
||||
@@ -42,17 +43,28 @@ namespace WorkspacesEditor
|
||||
e.Handled = true;
|
||||
Button button = sender as Button;
|
||||
Project selectedProject = button.DataContext as Project;
|
||||
selectedProject.IsPopupVisible = false;
|
||||
|
||||
_mainViewModel.DeleteProject(selectedProject);
|
||||
}
|
||||
|
||||
private void MoreButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_mainViewModel.CloseAllPopups();
|
||||
e.Handled = true;
|
||||
Button button = sender as Button;
|
||||
Project project = button.DataContext as Project;
|
||||
project.IsPopupVisible = true;
|
||||
}
|
||||
|
||||
private void PopupClosed(object sender, object e)
|
||||
{
|
||||
if (sender is Popup p && p.DataContext is Project proj)
|
||||
{
|
||||
proj.IsPopupVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
@@ -437,7 +437,11 @@ namespace WorkspacesEditor.ViewModels
|
||||
private void RunSnapshotTool(bool isExistingProjectLaunched)
|
||||
{
|
||||
Process process = new Process();
|
||||
process.StartInfo = new ProcessStartInfo(@".\PowerToys.WorkspacesSnapshotTool.exe");
|
||||
|
||||
var exeDir = Path.GetDirectoryName(Environment.ProcessPath);
|
||||
var snapshotUtilsPath = Path.Combine(exeDir, "PowerToys.WorkspacesSnapshotTool.exe");
|
||||
|
||||
process.StartInfo = new ProcessStartInfo(snapshotUtilsPath);
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
process.StartInfo.Arguments = isExistingProjectLaunched ? $"{(int)InvokePoint.LaunchAndEdit}" : string.Empty;
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
MouseLeave="AppBorder_MouseLeave">
|
||||
<Expander
|
||||
Margin="0,0,20,0"
|
||||
AutomationProperties.AutomationId="{Binding AppName}"
|
||||
AutomationProperties.Name="{Binding AppName}"
|
||||
FlowDirection="RightToLeft"
|
||||
IsEnabled="{Binding IsIncluded, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsExpanded="{Binding IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
|
||||
@@ -399,7 +401,11 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ItemsControl ItemTemplateSelector="{StaticResource AppListDataTemplateSelector}" ItemsSource="{Binding ApplicationsListed, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ItemsControl
|
||||
x:Name="CapturedAppList"
|
||||
AutomationProperties.Name="Captured Application List"
|
||||
ItemTemplateSelector="{StaticResource AppListDataTemplateSelector}"
|
||||
ItemsSource="{Binding ApplicationsListed, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -0,0 +1,605 @@
|
||||
// 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.
|
||||
|
||||
using System.Diagnostics;
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
[Ignore("not stable")]
|
||||
public class WorkspacesEditingPageTests : WorkspacesUiAutomationBase
|
||||
{
|
||||
public WorkspacesEditingPageTests()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.RemoveApp")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestRemoveAppFromWorkspace()
|
||||
{
|
||||
// Find app list
|
||||
var appList = Find<Custom>("AppList");
|
||||
var initialAppCount = appList.FindAll<Custom>(By.ClassName("AppItem")).Count;
|
||||
|
||||
if (initialAppCount == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to remove");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove first app
|
||||
var firstApp = appList.FindAll<Custom>(By.ClassName("AppItem"))[0];
|
||||
var appName = firstApp.GetAttribute("Name");
|
||||
|
||||
var removeButton = firstApp.Find<Button>("Remove");
|
||||
removeButton.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify app removed from list
|
||||
var finalAppCount = appList.FindAll<Custom>(By.ClassName("AppItem")).Count;
|
||||
Assert.AreEqual(initialAppCount - 1, finalAppCount, "App should be removed from list");
|
||||
|
||||
// Verify preview updated
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
Assert.AreEqual(finalAppCount, windowPreviews.Count, "Preview should show correct number of windows");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.RemoveAndAddBackApp")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestRemoveAndAddBackApp()
|
||||
{
|
||||
// Find app list
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
var appName = firstApp.GetAttribute("Name");
|
||||
|
||||
// Remove app
|
||||
var removeButton = firstApp.Find<Button>("Remove");
|
||||
removeButton.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify removed app shows in "removed apps" section
|
||||
Assert.IsTrue(Has<Button>("Add back"), "Should have 'Add back' button for removed apps");
|
||||
|
||||
// Add back the app
|
||||
var addBackButton = Find<Button>("Add back");
|
||||
addBackButton.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify app is back in the list
|
||||
var restoredApp = appList.Find<Custom>(By.Name(appName), timeoutMS: 2000);
|
||||
Assert.IsNotNull(restoredApp, "App should be restored to the list");
|
||||
|
||||
// Verify preview updated
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
var currentAppCount = appList.FindAll<Custom>(By.ClassName("AppItem")).Count;
|
||||
Assert.AreEqual(currentAppCount, windowPreviews.Count, "Preview should show all windows again");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.SetAppMinimized")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestSetAppMinimized()
|
||||
{
|
||||
// Find first app
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
|
||||
// Find and toggle minimized checkbox
|
||||
var minimizedCheckbox = firstApp.Find<CheckBox>("Minimized");
|
||||
bool wasMinimized = minimizedCheckbox.IsChecked;
|
||||
|
||||
minimizedCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify state changed
|
||||
Assert.AreNotEqual(wasMinimized, minimizedCheckbox.IsChecked, "Minimized state should toggle");
|
||||
|
||||
// Verify preview reflects the change
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
|
||||
// The first window preview should indicate minimized state
|
||||
if (minimizedCheckbox.IsChecked && windowPreviews.Count > 0)
|
||||
{
|
||||
var firstPreview = windowPreviews[0];
|
||||
var opacity = firstPreview.GetAttribute("Opacity");
|
||||
|
||||
// Minimized windows might have reduced opacity or other visual indicator
|
||||
Assert.IsNotNull(opacity, "Minimized window should have visual indication in preview");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.SetAppMaximized")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestSetAppMaximized()
|
||||
{
|
||||
// Find first app
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
|
||||
// Find and toggle maximized checkbox
|
||||
var maximizedCheckbox = firstApp.Find<CheckBox>("Maximized");
|
||||
bool wasMaximized = maximizedCheckbox.IsChecked;
|
||||
|
||||
maximizedCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify state changed
|
||||
Assert.AreNotEqual(wasMaximized, maximizedCheckbox.IsChecked, "Maximized state should toggle");
|
||||
|
||||
// Verify preview reflects the change
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
if (maximizedCheckbox.IsChecked)
|
||||
{
|
||||
// Maximized window should fill the preview area
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
if (windowPreviews.Count > 0)
|
||||
{
|
||||
var firstPreview = windowPreviews[0];
|
||||
|
||||
// Check if preview shows maximized state
|
||||
var width = firstPreview.GetAttribute("Width");
|
||||
var height = firstPreview.GetAttribute("Height");
|
||||
Assert.IsNotNull(width, "Maximized window should have width in preview");
|
||||
Assert.IsNotNull(height, "Maximized window should have height in preview");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.LaunchAsAdmin")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestSetLaunchAsAdmin()
|
||||
{
|
||||
// Find app that supports admin launch
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
bool foundAdminCapableApp = false;
|
||||
foreach (var app in apps)
|
||||
{
|
||||
try
|
||||
{
|
||||
var adminCheckbox = app.Find<CheckBox>("Launch as admin", timeoutMS: 1000);
|
||||
if (adminCheckbox != null && adminCheckbox.IsChecked)
|
||||
{
|
||||
foundAdminCapableApp = true;
|
||||
bool wasAdmin = adminCheckbox.IsChecked;
|
||||
|
||||
adminCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify state changed
|
||||
Assert.AreNotEqual(wasAdmin, adminCheckbox.IsChecked, "Admin launch state should toggle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// This app doesn't support admin launch
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundAdminCapableApp)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace support admin launch");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.AddCLIArgs")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestAddCommandLineArguments()
|
||||
{
|
||||
// Find first app
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
|
||||
// Find CLI args textbox
|
||||
var cliArgsTextBox = firstApp.Find<TextBox>("Command line arguments", timeoutMS: 2000);
|
||||
if (cliArgsTextBox == null)
|
||||
{
|
||||
Assert.Inconclusive("App does not support command line arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add test arguments
|
||||
string testArgs = "--test-arg value";
|
||||
cliArgsTextBox.SetText(testArgs);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify arguments were entered
|
||||
Assert.AreEqual(testArgs, cliArgsTextBox.Text, "Command line arguments should be set");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.ChangeAppPosition")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestManuallyChangeAppPosition()
|
||||
{
|
||||
// Find first app
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
|
||||
// Find position controls
|
||||
var xPositionBox = firstApp.Find<TextBox>("X position", timeoutMS: 2000);
|
||||
var yPositionBox = firstApp.Find<TextBox>("Y position", timeoutMS: 2000);
|
||||
|
||||
if (xPositionBox == null || yPositionBox == null)
|
||||
{
|
||||
// Try alternate approach with spinners
|
||||
var positionSpinners = firstApp.FindAll<Custom>(By.ClassName("SpinBox"));
|
||||
if (positionSpinners.Count >= 2)
|
||||
{
|
||||
xPositionBox = positionSpinners[0].Find<TextBox>(By.ClassName("TextBox"));
|
||||
yPositionBox = positionSpinners[1].Find<TextBox>(By.ClassName("TextBox"));
|
||||
}
|
||||
}
|
||||
|
||||
if (xPositionBox != null && yPositionBox != null)
|
||||
{
|
||||
// Change position
|
||||
xPositionBox.SetText("200");
|
||||
Thread.Sleep(500);
|
||||
|
||||
yPositionBox.SetText("150");
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify preview updated
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
Assert.IsTrue(windowPreviews.Count > 0, "Preview should show window at new position");
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Inconclusive("Could not find position controls");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.ChangeWorkspaceName")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestChangeWorkspaceName()
|
||||
{
|
||||
// Find workspace name textbox
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string originalName = nameTextBox.Text;
|
||||
|
||||
// Change name
|
||||
string newName = "Renamed_Workspace_" + DateTime.Now.Ticks;
|
||||
nameTextBox.SetText(newName);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Save changes
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify we're back at main list
|
||||
Assert.IsTrue(Has<Custom>("WorkspacesList"), "Should return to main list after saving");
|
||||
|
||||
// Verify workspace was renamed
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var renamedWorkspace = workspacesList.Find<Custom>(By.Name(newName), timeoutMS: 2000);
|
||||
Assert.IsNotNull(renamedWorkspace, "Workspace should be renamed in the list");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.SaveAndCancelWork")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestSaveAndCancelButtons()
|
||||
{
|
||||
// Make a change
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string originalName = nameTextBox.Text;
|
||||
string tempName = originalName + "_temp";
|
||||
|
||||
nameTextBox.SetText(tempName);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Test Cancel button
|
||||
var cancelButton = Find<Button>("Cancel");
|
||||
cancelButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify returned to main list without saving
|
||||
Assert.IsTrue(Has<Custom>("WorkspacesList"), "Should return to main list");
|
||||
|
||||
// Go back to editing
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspace = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
workspace.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify name wasn't changed
|
||||
nameTextBox = Find<TextBox>("Workspace name");
|
||||
Assert.AreEqual(originalName, nameTextBox.Text, "Name should not be changed after cancel");
|
||||
|
||||
// Now test Save button
|
||||
nameTextBox.SetText(tempName);
|
||||
Thread.Sleep(500);
|
||||
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify saved
|
||||
workspacesList = Find<Custom>("WorkspacesList");
|
||||
var savedWorkspace = workspacesList.Find<Custom>(By.Name(tempName), timeoutMS: 2000);
|
||||
Assert.IsNotNull(savedWorkspace, "Workspace should be saved with new name");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.NavigateWithoutSaving")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestNavigateToMainPageWithoutSaving()
|
||||
{
|
||||
// Make a change
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string originalName = nameTextBox.Text;
|
||||
|
||||
nameTextBox.SetText(originalName + "_unsaved");
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Click on "Workspaces" navigation/breadcrumb
|
||||
if (Has<NavigationViewItem>("Workspaces", timeoutMS: 1000))
|
||||
{
|
||||
var workspacesNav = Find<NavigationViewItem>("Workspaces");
|
||||
workspacesNav.Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
else if (Has<HyperlinkButton>("Workspaces", timeoutMS: 1000))
|
||||
{
|
||||
var workspacesBreadcrumb = Find<HyperlinkButton>("Workspaces");
|
||||
workspacesBreadcrumb.Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
// If there's a confirmation dialog, handle it
|
||||
if (Has<Button>("Discard", timeoutMS: 1000))
|
||||
{
|
||||
Find<Button>("Discard").Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Verify returned to main list
|
||||
Assert.IsTrue(Has<Custom>("WorkspacesList"), "Should return to main list");
|
||||
|
||||
// Verify changes weren't saved
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var unsavedWorkspace = workspacesList.Find<Custom>(By.Name(originalName + "_unsaved"), timeoutMS: 1000);
|
||||
Assert.IsNull(unsavedWorkspace, "Unsaved changes should not persist");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.CreateDesktopShortcut")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestCreateDesktopShortcut()
|
||||
{
|
||||
// Find desktop shortcut checkbox
|
||||
var shortcutCheckbox = Find<CheckBox>("Create desktop shortcut");
|
||||
|
||||
// Get desktop path
|
||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
|
||||
// Get workspace name to check for shortcut
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string workspaceName = nameTextBox.Text;
|
||||
string shortcutPath = Path.Combine(desktopPath, $"{workspaceName}.lnk");
|
||||
|
||||
// Clean up any existing shortcut
|
||||
if (File.Exists(shortcutPath))
|
||||
{
|
||||
File.Delete(shortcutPath);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Check the checkbox
|
||||
if (!shortcutCheckbox.IsChecked)
|
||||
{
|
||||
shortcutCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Save
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(2000); // Give time for shortcut creation
|
||||
|
||||
// Verify shortcut was created
|
||||
Assert.IsTrue(File.Exists(shortcutPath), "Desktop shortcut should be created");
|
||||
|
||||
// Clean up
|
||||
if (File.Exists(shortcutPath))
|
||||
{
|
||||
File.Delete(shortcutPath);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.DesktopShortcutState")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestDesktopShortcutCheckboxState()
|
||||
{
|
||||
// Get workspace name
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string workspaceName = nameTextBox.Text;
|
||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
string shortcutPath = Path.Combine(desktopPath, $"{workspaceName}.lnk");
|
||||
|
||||
// Find checkbox
|
||||
var shortcutCheckbox = Find<CheckBox>("Create desktop shortcut");
|
||||
|
||||
// Test 1: When shortcut exists
|
||||
if (!File.Exists(shortcutPath))
|
||||
{
|
||||
// Create shortcut first
|
||||
if (!shortcutCheckbox.IsChecked)
|
||||
{
|
||||
shortcutCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
Find<Button>("Save").Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Navigate back to editing
|
||||
NavigateToEditingPage();
|
||||
}
|
||||
|
||||
shortcutCheckbox = Find<CheckBox>("Create desktop shortcut");
|
||||
Assert.IsTrue(shortcutCheckbox.IsChecked, "Checkbox should be checked when shortcut exists");
|
||||
|
||||
// Test 2: Remove shortcut
|
||||
if (File.Exists(shortcutPath))
|
||||
{
|
||||
File.Delete(shortcutPath);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Re-navigate to refresh state
|
||||
Find<Button>("Cancel").Click();
|
||||
Thread.Sleep(1000);
|
||||
NavigateToEditingPage();
|
||||
|
||||
shortcutCheckbox = Find<CheckBox>("Create desktop shortcut");
|
||||
Assert.IsFalse(shortcutCheckbox.IsChecked, "Checkbox should be unchecked when shortcut doesn't exist");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.LaunchAndEdit")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestLaunchAndEditCapture()
|
||||
{
|
||||
// Find Launch and Edit button
|
||||
var launchEditButton = Find<Button>("Launch and Edit");
|
||||
launchEditButton.Click();
|
||||
Thread.Sleep(3000); // Wait for apps to launch
|
||||
|
||||
// Open a new application
|
||||
Process.Start("calc.exe");
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Click Capture
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Verify new app was added
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
bool foundCalculator = false;
|
||||
foreach (var app in apps)
|
||||
{
|
||||
var appName = app.GetAttribute("Name");
|
||||
if (appName.Contains("Calculator", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foundCalculator = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.IsTrue(foundCalculator, "Newly opened Calculator should be captured and added");
|
||||
|
||||
// Clean up
|
||||
foreach (var process in Process.GetProcessesByName("CalculatorApp"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
foreach (var process in Process.GetProcessesByName("Calculator"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
private void NavigateToEditingPage()
|
||||
{
|
||||
// Ensure we have at least one workspace
|
||||
if (!Has<Custom>("WorkspacesList", timeoutMS: 1000))
|
||||
{
|
||||
CreateTestWorkspace();
|
||||
}
|
||||
|
||||
// Click on first workspace to edit
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItems = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"));
|
||||
|
||||
if (workspaceItems.Count == 0)
|
||||
{
|
||||
CreateTestWorkspace();
|
||||
workspaceItems = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"));
|
||||
}
|
||||
|
||||
workspaceItems[0].Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
private void CreateTestWorkspace()
|
||||
{
|
||||
// Open a test app
|
||||
Process.Start("notepad.exe");
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Create workspace
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Capture
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Save with default name
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Close test app
|
||||
foreach (var process in Process.GetProcessesByName("notepad"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
public class WorkspacesEditorTests : UITestBase
|
||||
public class WorkspacesEditorTests : WorkspacesUiAutomationBase
|
||||
{
|
||||
public WorkspacesEditorTests()
|
||||
: base(PowerToysModule.Workspaces, WindowSize.Medium)
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -21,4 +21,217 @@ public class WorkspacesEditorTests : UITestBase
|
||||
{
|
||||
Assert.IsTrue(this.Has<Button>("Create Workspace"), "Should have create workspace button");
|
||||
}
|
||||
|
||||
/*
|
||||
[TestMethod("WorkspacesEditor.Editor.NewWorkspaceAppearsInList")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestNewWorkspaceAppearsInListAfterCapture()
|
||||
{
|
||||
// Open test application
|
||||
OpenNotepad();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Create workspace
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Capture
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Save workspace
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify workspace appears in list
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItems = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"));
|
||||
Assert.IsTrue(workspaceItems.Count > 0, "New workspace should appear in the list");
|
||||
|
||||
CloseNotepad();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.CancelCaptureDoesNotAddWorkspace")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestCancelCaptureDoesNotAddWorkspace()
|
||||
{
|
||||
// Count existing workspaces
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var initialCount = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem")).Count;
|
||||
|
||||
// Create workspace
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Cancel
|
||||
var cancelButton = Find<Button>("Cancel");
|
||||
cancelButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify count hasn't changed
|
||||
var finalCount = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem")).Count;
|
||||
Assert.AreEqual(initialCount, finalCount, "Workspace count should not change after canceling");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.SearchFiltersWorkspaces")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestSearchFiltersWorkspaces()
|
||||
{
|
||||
// Create test workspaces first
|
||||
CreateTestWorkspace("TestWorkspace1");
|
||||
CreateTestWorkspace("TestWorkspace2");
|
||||
CreateTestWorkspace("DifferentName");
|
||||
|
||||
// Find search box
|
||||
var searchBox = Find<TextBox>("Search");
|
||||
searchBox.SetText("TestWorkspace");
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify filtered results
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var visibleItems = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"));
|
||||
|
||||
// Should only show items matching "TestWorkspace"
|
||||
Assert.IsTrue(visibleItems.Count >= 2, "Should show at least 2 TestWorkspace items");
|
||||
|
||||
// Clear search
|
||||
searchBox.SetText(string.Empty);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.SortByWorks")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestSortByFunctionality()
|
||||
{
|
||||
// Find sort dropdown
|
||||
var sortDropdown = Find<ComboBox>("SortBy");
|
||||
sortDropdown.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Select different sort options
|
||||
var sortOptions = FindAll<Custom>(By.ClassName("ComboBoxItem"));
|
||||
if (sortOptions.Count > 1)
|
||||
{
|
||||
sortOptions[1].Click(); // Select second option
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify list is updated (we can't easily verify sort order in UI tests)
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
Assert.IsNotNull(workspacesList, "Workspaces list should still be visible after sorting");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.SortByPersists")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestSortByPersistsAfterRestart()
|
||||
{
|
||||
// Set sort option
|
||||
var sortDropdown = Find<ComboBox>("SortBy");
|
||||
sortDropdown.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
var sortOptions = FindAll<Custom>(By.ClassName("ComboBoxItem"));
|
||||
string selectedOption = string.Empty;
|
||||
if (sortOptions.Count > 1)
|
||||
{
|
||||
sortOptions[1].Click(); // Select second option
|
||||
selectedOption = sortDropdown.Text;
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
// Restart editor
|
||||
RestartScopeExe();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Verify sort option persisted
|
||||
sortDropdown = Find<ComboBox>("SortBy");
|
||||
Assert.AreEqual(selectedOption, sortDropdown.Text, "Sort option should persist after restart");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.RemoveWorkspace")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestRemoveWorkspace()
|
||||
{
|
||||
// Create a test workspace
|
||||
CreateTestWorkspace("WorkspaceToRemove");
|
||||
|
||||
// Find the workspace in the list
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.Find<Custom>(By.Name("WorkspaceToRemove"));
|
||||
|
||||
// Click remove button
|
||||
var removeButton = workspaceItem.Find<Button>("Remove");
|
||||
removeButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Confirm removal if dialog appears
|
||||
if (Has<Button>("Yes"))
|
||||
{
|
||||
Find<Button>("Yes").Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
// Verify workspace is removed
|
||||
Assert.IsFalse(Has(By.Name("WorkspaceToRemove")), "Workspace should be removed from list");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.EditOpensEditingPage")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestEditOpensEditingPage()
|
||||
{
|
||||
// Create a test workspace if none exist
|
||||
if (!Has<Custom>("WorkspacesList"))
|
||||
{
|
||||
CreateTestWorkspace("TestWorkspace");
|
||||
}
|
||||
|
||||
// Find first workspace
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
|
||||
// Click edit button
|
||||
var editButton = workspaceItem.Find<Button>("Edit");
|
||||
editButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify editing page opened
|
||||
Assert.IsTrue(Has<Button>("Save"), "Should have Save button on editing page");
|
||||
Assert.IsTrue(Has<Button>("Cancel"), "Should have Cancel button on editing page");
|
||||
|
||||
// Go back
|
||||
Find<Button>("Cancel").Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.ClickWorkspaceOpensEditingPage")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestClickWorkspaceOpensEditingPage()
|
||||
{
|
||||
// Create a test workspace if none exist
|
||||
if (!Has<Custom>("WorkspacesList"))
|
||||
{
|
||||
CreateTestWorkspace("TestWorkspace");
|
||||
}
|
||||
|
||||
// Find first workspace
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
|
||||
// Click on the workspace item itself
|
||||
workspaceItem.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify editing page opened
|
||||
Assert.IsTrue(Has<Button>("Save"), "Should have Save button on editing page");
|
||||
Assert.IsTrue(Has<Button>("Cancel"), "Should have Cancel button on editing page");
|
||||
|
||||
// Go back
|
||||
Find<Button>("Cancel").Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\UITestAutomation\UITestAutomation.csproj" />
|
||||
<ProjectReference Include="..\WorkspacesEditor\WorkspacesEditor.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
// 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.
|
||||
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
[Ignore("NOT STABLE")]
|
||||
public class WorkspacesLauncherTest : WorkspacesUiAutomationBase
|
||||
{
|
||||
public WorkspacesLauncherTest()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Launcher.LaunchFromEditor")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestLaunchWorkspaceFromEditor()
|
||||
{
|
||||
ClearWorkspaces();
|
||||
var uuid = Guid.NewGuid().ToString("N").Substring(0, 8);
|
||||
CreateTestWorkspace(uuid);
|
||||
|
||||
CloseNotepad();
|
||||
|
||||
var launchButton = Find<Button>(By.Name("Launch"));
|
||||
launchButton.Click();
|
||||
|
||||
Task.Delay(2000).Wait();
|
||||
|
||||
var processes = System.Diagnostics.Process.GetProcessesByName("notepad");
|
||||
|
||||
Assert.IsTrue(processes?.Length > 0);
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Launcher.CancelLaunch")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestCancelLaunch()
|
||||
{
|
||||
// Create workspace with multiple apps
|
||||
CreateWorkspaceWithApps();
|
||||
|
||||
// Launch workspace
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
var launchButton = workspaceItem.Find<Button>("Launch");
|
||||
launchButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Cancel launch
|
||||
if (Has<Button>("Cancel launch"))
|
||||
{
|
||||
Find<Button>("Cancel launch").Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify launcher closed
|
||||
Assert.IsFalse(Has<Window>("Workspaces Launcher"), "Launcher window should close after cancel");
|
||||
}
|
||||
|
||||
// Close any apps that may have launched
|
||||
CloseTestApplications();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Launcher.DismissKeepsLaunching")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestDismissKeepsAppsLaunching()
|
||||
{
|
||||
// Create workspace with apps
|
||||
CreateWorkspaceWithApps();
|
||||
|
||||
// Launch workspace
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
var launchButton = workspaceItem.Find<Button>("Launch");
|
||||
launchButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Dismiss launcher
|
||||
if (Has<Button>("Dismiss"))
|
||||
{
|
||||
Find<Button>("Dismiss").Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify launcher closed but apps continue launching
|
||||
Assert.IsFalse(Has<Window>("Workspaces Launcher"), "Launcher window should close after dismiss");
|
||||
|
||||
// Wait for apps to finish launching
|
||||
Thread.Sleep(3000);
|
||||
|
||||
// Verify apps launched (notepad should be open)
|
||||
Assert.IsTrue(WindowHelper.IsWindowOpen("Notepad"), "Apps should continue launching after dismiss");
|
||||
}
|
||||
|
||||
// Close launched apps
|
||||
CloseTestApplications();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
// 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.
|
||||
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
public class WorkspacesSettingsTests : UITestBase
|
||||
{
|
||||
public WorkspacesSettingsTests()
|
||||
: base(PowerToysModule.PowerToysSettings, WindowSize.Medium)
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.LaunchFromSettings")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
public void TestLaunchEditorFromSettingsPage()
|
||||
{
|
||||
GoToSettingsPageAndEnable();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.ActivationShortcut")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
public void TestActivationShortcutCustomization()
|
||||
{
|
||||
GoToSettingsPageAndEnable();
|
||||
|
||||
// Find the activation shortcut control
|
||||
var shortcutButton = Find<Button>("Activation shortcut");
|
||||
Assert.IsNotNull(shortcutButton, "Activation shortcut control should exist");
|
||||
|
||||
// Test customizing the shortcut
|
||||
shortcutButton.Click();
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Send new key combination (Win+Ctrl+W)
|
||||
SendKeys(Key.Win, Key.Ctrl, Key.W);
|
||||
|
||||
var saveButton = Find<Button>("Save");
|
||||
|
||||
Assert.IsNotNull(saveButton, "Save button should exist after editing shortcut");
|
||||
|
||||
saveButton.Click();
|
||||
|
||||
var helpText = shortcutButton.HelpText;
|
||||
Assert.AreEqual("Win + Ctrl + W", helpText, "Activation shortcut should be updated to Win + Ctrl + W");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.EnableToggle")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
public void TestEnableDisableModule()
|
||||
{
|
||||
GoToSettingsPageAndEnable();
|
||||
|
||||
// Find the enable toggle
|
||||
var enableToggle = Find<ToggleSwitch>("Enable Workspaces");
|
||||
Assert.IsNotNull(enableToggle, "Enable Workspaces toggle should exist");
|
||||
|
||||
Assert.IsTrue(enableToggle.IsOn, "Enable Workspaces toggle should be in the 'on' state");
|
||||
|
||||
// Toggle the state
|
||||
enableToggle.Click();
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
// Verify state changed
|
||||
Assert.IsFalse(enableToggle.IsOn, "Toggle state should change");
|
||||
|
||||
// Verify related controls are enabled/disabled accordingly
|
||||
var launchButton = Find<Button>("Launch editor");
|
||||
Assert.IsFalse(launchButton.Enabled, "Launch editor button should be disabled when module is disabled");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.LaunchByActivationShortcut")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
[Ignore("Wait until settings & runner can be connected in framework")]
|
||||
public void TestLaunchEditorByActivationShortcut()
|
||||
{
|
||||
// Ensure module is enabled
|
||||
var enableToggle = Find<ToggleSwitch>("Enable Workspaces");
|
||||
if (!enableToggle.IsOn)
|
||||
{
|
||||
enableToggle.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Close settings window to test shortcut
|
||||
ExitScopeExe();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Default shortcut is Win+Ctrl+`
|
||||
SendKeys(Key.Win, Key.Ctrl, Key.W);
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Verify editor opened
|
||||
Assert.IsTrue(WindowHelper.IsWindowOpen("Workspaces Editor"), "Workspaces Editor should open with activation shortcut");
|
||||
|
||||
// Reopen settings for next tests
|
||||
RestartScopeExe();
|
||||
NavigateToWorkspacesSettings();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.DisableModuleNoLaunch")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
[Ignore("Wait until settings & runner can be connected in framework")]
|
||||
public void TestDisabledModuleDoesNotLaunchByShortcut()
|
||||
{
|
||||
// Disable the module
|
||||
var enableToggle = Find<ToggleSwitch>("Enable Workspaces");
|
||||
if (enableToggle.IsOn)
|
||||
{
|
||||
enableToggle.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Close settings to test shortcut
|
||||
ExitScopeExe();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Try to launch with shortcut
|
||||
SendKeys(Key.Win, Key.Ctrl, Key.W);
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Verify editor did not open
|
||||
Assert.IsFalse(WindowHelper.IsWindowOpen("Workspaces Editor"), "Workspaces Editor should not open when module is disabled");
|
||||
|
||||
// Reopen settings and re-enable the module
|
||||
RestartScopeExe();
|
||||
NavigateToWorkspacesSettings();
|
||||
|
||||
enableToggle = Find<ToggleSwitch>("Enable Workspaces");
|
||||
if (!enableToggle.IsOn)
|
||||
{
|
||||
enableToggle.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.QuickAccessLaunch")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
[Ignore("Wait until tray icon supported is in framework")]
|
||||
public void TestLaunchFromQuickAccess()
|
||||
{
|
||||
// This test verifies the "quick access" mention in settings
|
||||
// Look for any quick access related UI elements
|
||||
var quickAccessInfo = FindAll(By.LinkText("quick access"));
|
||||
|
||||
if (quickAccessInfo.Count > 0)
|
||||
{
|
||||
Assert.IsTrue(quickAccessInfo.Count > 0, "Quick access information should be present in settings");
|
||||
}
|
||||
|
||||
// Note: Actual system tray/quick access interaction would require
|
||||
// more complex automation that might be platform-specific
|
||||
}
|
||||
|
||||
private void NavigateToWorkspacesSettings()
|
||||
{
|
||||
// Find and click Workspaces in the navigation
|
||||
var workspacesNavItem = Find<NavigationViewItem>("Workspaces");
|
||||
workspacesNavItem.Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
private void GoToSettingsPageAndEnable()
|
||||
{
|
||||
if (this.FindAll<NavigationViewItem>("Workspaces").Count == 0)
|
||||
{
|
||||
this.Find<NavigationViewItem>("Windowing & Layouts").Click();
|
||||
}
|
||||
|
||||
this.Find<NavigationViewItem>("Workspaces").Click();
|
||||
|
||||
var enableButton = this.Find<ToggleSwitch>("Enable Workspaces");
|
||||
Assert.IsNotNull(enableButton, "Enable Workspaces toggle should exist");
|
||||
|
||||
if (!enableButton.IsOn)
|
||||
{
|
||||
enableButton.Click();
|
||||
Task.Delay(500).Wait(); // Wait for the toggle animation and state change
|
||||
}
|
||||
|
||||
// Verify it's now enabled
|
||||
Assert.IsTrue(enableButton.IsOn, "Enable Workspaces toggle should be in the 'on' state");
|
||||
}
|
||||
|
||||
private void AttachWorkspacesEditor()
|
||||
{
|
||||
Task.Delay(200).Wait();
|
||||
this.Session.Attach(PowerToysModule.Workspaces);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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.
|
||||
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using WorkspacesEditor.Utils;
|
||||
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
public class WorkspacesSnapshotTests : WorkspacesUiAutomationBase
|
||||
{
|
||||
public WorkspacesSnapshotTests()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSnapshot.CancelCapture")]
|
||||
[TestCategory("Workspaces Snapshot UI")]
|
||||
public void TestCaptureCancel()
|
||||
{
|
||||
AttachWorkspacesEditor();
|
||||
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
AttachSnapshotWindow();
|
||||
|
||||
var cancelButton = Find<Button>("Cancel");
|
||||
|
||||
Assert.IsNotNull(cancelButton, "Capture button should exist");
|
||||
|
||||
cancelButton.Click();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSnapshot.CapturePackagedApps")]
|
||||
[TestCategory("Workspaces Snapshot UI")]
|
||||
public void TestCapturePackagedApplications()
|
||||
{
|
||||
OpenCalculator();
|
||||
|
||||
// OpenWindowsSettings();
|
||||
Task.Delay(2000).Wait();
|
||||
|
||||
AttachWorkspacesEditor();
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
AttachSnapshotWindow();
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Task.Delay(3000).Wait();
|
||||
|
||||
// Verify captured windows by reading the temporary workspaces file as the ground truth.
|
||||
var editorIO = new WorkspacesEditorIO();
|
||||
var workspace = editorIO.ParseTempProject();
|
||||
|
||||
Assert.IsNotNull(workspace, "Workspace data should be deserialized.");
|
||||
Assert.IsNotNull(workspace.Applications, "Workspace should contain a list of apps.");
|
||||
|
||||
bool isCalculatorFound = workspace.Applications.Any(app => app.AppPath.Contains("Calculator", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// bool isSettingsFound = workspace.Applications.Any(app => app.AppPath.Contains("Settings", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.IsTrue(isCalculatorFound, "Calculator should be captured in the workspace data.");
|
||||
|
||||
// Assert.IsTrue(isSettingsFound, "Settings should be captured in the workspace data.");
|
||||
|
||||
// Cancel to clean up
|
||||
AttachWorkspacesEditor();
|
||||
Find<Button>("Cancel").Click();
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Close test applications
|
||||
CloseCalculator();
|
||||
|
||||
// CloseWindowsSettings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
// 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.
|
||||
|
||||
using System.Diagnostics;
|
||||
using Microsoft.PowerToys.UITest;
|
||||
|
||||
namespace WorkspacesEditorUITest
|
||||
{
|
||||
public class WorkspacesUiAutomationBase : UITestBase
|
||||
{
|
||||
public WorkspacesUiAutomationBase()
|
||||
: base(PowerToysModule.Workspaces, WindowSize.Medium)
|
||||
{
|
||||
}
|
||||
|
||||
protected void CreateTestWorkspace(string name)
|
||||
{
|
||||
// Open notepad for capture
|
||||
OpenNotepad();
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Create workspace
|
||||
AttachWorkspacesEditor();
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
// Capture
|
||||
AttachSnapshotWindow();
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Task.Delay(5000).Wait();
|
||||
|
||||
// Set name
|
||||
var nameTextBox = Find<TextBox>("EditNameTextBox");
|
||||
nameTextBox.SetText(name);
|
||||
|
||||
// Save
|
||||
Find<Button>("Save Workspace").Click();
|
||||
|
||||
// Close notepad
|
||||
CloseNotepad();
|
||||
}
|
||||
|
||||
// DO NOT USE UNTIL FRAMEWORK AVAILABLE, CAN'T FIND BUTTON FOR SECOND LOOP
|
||||
protected void ClearWorkspaces()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var root = Find<Element>(By.AccessibilityId("WorkspacesItemsControl"));
|
||||
var buttons = root.FindAll<Button>(By.AccessibilityId("MoreButton"));
|
||||
|
||||
Debug.WriteLine($"Found {buttons.Count} button");
|
||||
|
||||
var button = buttons[^1];
|
||||
|
||||
button.Click();
|
||||
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
var remove = Find<Button>(By.Name("Remove"));
|
||||
remove.Click();
|
||||
|
||||
Task.Delay(500).Wait();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void CreateWorkspaceWithApps()
|
||||
{
|
||||
// Open multiple test applications
|
||||
OpenTestApplications();
|
||||
Thread.Sleep(3000);
|
||||
|
||||
// Create workspace
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Capture
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Save
|
||||
Find<Button>("Save").Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Close test applications
|
||||
CloseTestApplications();
|
||||
}
|
||||
|
||||
protected void OpenTestApplications()
|
||||
{
|
||||
OpenNotepad();
|
||||
|
||||
// Could add more applications here
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
protected void CloseTestApplications()
|
||||
{
|
||||
CloseNotepad();
|
||||
}
|
||||
|
||||
protected void CloseWorkspacesEditor()
|
||||
{
|
||||
// Find and close the Workspaces Editor window
|
||||
if (WindowHelper.IsWindowOpen("Workspaces Editor"))
|
||||
{
|
||||
var editorWindow = Find<Window>("Workspaces Editor");
|
||||
editorWindow.Close();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ResetShortcutToDefault(Custom shortcutControl)
|
||||
{
|
||||
// Right-click on the shortcut control to open context menu
|
||||
shortcutControl.Click(rightClick: true);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Look for a "Reset to default" or similar option in the context menu
|
||||
try
|
||||
{
|
||||
// Try to find various possible menu item texts for reset option
|
||||
var resetOption = Find("Reset to default");
|
||||
resetOption?.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// Try alternative text
|
||||
var resetOption = Find("Reset");
|
||||
resetOption?.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// Try another alternative
|
||||
var resetOption = Find("Default");
|
||||
resetOption?.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If context menu doesn't have reset option, try keyboard shortcut
|
||||
// ESC to close any open menus first
|
||||
SendKeys(Key.Esc);
|
||||
Thread.Sleep(200);
|
||||
|
||||
// Click on the control and try to clear it with standard shortcuts
|
||||
shortcutControl.Click();
|
||||
Thread.Sleep(200);
|
||||
|
||||
// Try Ctrl+A to select all, then Delete to clear
|
||||
SendKeys(Key.Ctrl, Key.A);
|
||||
Thread.Sleep(100);
|
||||
SendKeys(Key.Delete);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void OpenNotepad()
|
||||
{
|
||||
var process = System.Diagnostics.Process.Start("notepad.exe");
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
|
||||
protected void CloseNotepad()
|
||||
{
|
||||
var processes = System.Diagnostics.Process.GetProcessesByName("notepad");
|
||||
foreach (var process in processes)
|
||||
{
|
||||
try
|
||||
{
|
||||
process.Kill();
|
||||
process.WaitForExit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachPowertoySetting()
|
||||
{
|
||||
Task.Delay(200).Wait();
|
||||
this.Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
}
|
||||
|
||||
protected void AttachWorkspacesEditor()
|
||||
{
|
||||
Task.Delay(200).Wait();
|
||||
this.Session.Attach(PowerToysModule.Workspaces);
|
||||
}
|
||||
|
||||
protected void AttachSnapshotWindow()
|
||||
{
|
||||
Task.Delay(5000).Wait();
|
||||
this.Session.Attach("Snapshot Creator");
|
||||
}
|
||||
|
||||
protected void OpenCalculator()
|
||||
{
|
||||
Process.Start("calc.exe");
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
|
||||
protected void CloseCalculator()
|
||||
{
|
||||
foreach (var process in Process.GetProcessesByName("CalculatorApp"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
foreach (var process in Process.GetProcessesByName("Calculator"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
|
||||
protected void OpenWindowsSettings()
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "ms-settings:",
|
||||
UseShellExecute = true,
|
||||
});
|
||||
Task.Delay(500).Wait();
|
||||
}
|
||||
|
||||
protected void CloseWindowsSettings()
|
||||
{
|
||||
foreach (var process in Process.GetProcessesByName("SystemSettings"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user