diff --git a/src/common/UITestAutomation/Element/By.cs b/src/common/UITestAutomation/Element/By.cs
index 2e4814accde5..b2d8ecf6c449 100644
--- a/src/common/UITestAutomation/Element/By.cs
+++ b/src/common/UITestAutomation/Element/By.cs
@@ -11,17 +11,40 @@ namespace Microsoft.PowerToys.UITest
///
public class By
{
- private readonly OpenQA.Selenium.By by;
+ private readonly OpenQA.Selenium.By? by;
+ private readonly bool isAccessibilityId;
+ private readonly string? accessibilityId;
private By(OpenQA.Selenium.By by)
{
+ isAccessibilityId = false;
this.by = by;
}
+ private By(string accessibilityId)
+ {
+ isAccessibilityId = true;
+ this.accessibilityId = accessibilityId;
+ }
+
public override string ToString()
{
// override ToString to return detailed debugging content provided by OpenQA.Selenium.By
- return this.by.ToString();
+ return this.GetAccessibilityId();
+ }
+
+ public bool GetIsAccessibilityId() => this.isAccessibilityId;
+
+ public string GetAccessibilityId()
+ {
+ if (this.isAccessibilityId)
+ {
+ return this.accessibilityId!;
+ }
+ else
+ {
+ return this.by!.ToString();
+ }
}
///
@@ -45,6 +68,13 @@ public override string ToString()
/// A By object.
public static By Id(string id) => new By(OpenQA.Selenium.By.Id(id));
+ ///
+ /// Creates a By object using the ID attribute.
+ ///
+ /// The ID attribute to search for.
+ /// A By object.
+ public static By AccessibilityId(string accessibilityId) => new By(accessibilityId);
+
///
/// Creates a By object using the XPath expression.
///
@@ -77,6 +107,6 @@ public override string ToString()
/// Converts the By object to an OpenQA.Selenium.By object.
///
/// An OpenQA.Selenium.By object.
- internal OpenQA.Selenium.By ToSeleniumBy() => by;
+ internal OpenQA.Selenium.By ToSeleniumBy() => by!;
}
}
diff --git a/src/common/UITestAutomation/Element/Element.cs b/src/common/UITestAutomation/Element/Element.cs
index 70bdc690c08e..7ca0cf53a5b5 100644
--- a/src/common/UITestAutomation/Element/Element.cs
+++ b/src/common/UITestAutomation/Element/Element.cs
@@ -7,6 +7,7 @@
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using ABI.Windows.Foundation;
+using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
@@ -192,7 +193,10 @@ public void Drag(Element element)
/// The Key to Send.
public void SendKeys(string key)
{
- windowsElement?.SendKeys(key);
+ PerformAction((actions, windowElement) =>
+ {
+ windowElement.SendKeys(key);
+ });
}
///
@@ -241,26 +245,6 @@ public T Find(string name, int timeoutMS = 3000)
return this.Find(By.Name(name), timeoutMS);
}
- ///
- /// Shortcut for this.FindAllByAccessibilityId(accessibilityId, timeoutMS)
- ///
- /// The class of the element, should be Element or its derived class.
- /// The accessibilityId of the element.
- /// The timeout in milliseconds (default is 3000).
- /// The found element.
- public T FindByAccessibilityId(string accessibilityId, int timeoutMS = 3000)
- where T : Element, new()
- {
- Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: accessibilityId = {accessibilityId}, timeoutMS = {timeoutMS}");
-
- // leverage findAll to filter out mismatched elements
- var collection = this.FindAllByAccessibilityId(accessibilityId, timeoutMS);
-
- Assert.IsTrue(collection.Count > 0, $"Element not found using selector: {accessibilityId}");
-
- return collection[0];
- }
-
///
/// Finds an element by the selector.
/// Shortcut for this.Find(by, timeoutMS)
@@ -299,31 +283,16 @@ public ReadOnlyCollection FindAll(By by, int timeoutMS = 3000)
var foundElements = FindHelper.FindAll(
() =>
{
- var elements = this.windowsElement.FindElements(by.ToSeleniumBy());
- return elements;
- },
- this.driver,
- timeoutMS);
-
- return foundElements ?? new ReadOnlyCollection([]);
- }
-
- ///
- /// Finds all elements by accessibilityId.
- ///
- /// The class of the elements, should be Element or its derived class.
- /// The accessibilityId to find the elements.
- /// The timeout in milliseconds (default is 3000).
- /// A read-only collection of the found elements.
- public ReadOnlyCollection FindAllByAccessibilityId(string accessibilityId, int timeoutMS = 3000)
- where T : Element, new()
- {
- Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method FindAll<{typeof(T).Name}> with parameters: accessibilityId = {accessibilityId}, timeoutMS = {timeoutMS}");
- var foundElements = FindHelper.FindAll(
- () =>
- {
- var elements = this.windowsElement.FindElementsByAccessibilityId(accessibilityId);
- return elements;
+ if (by.GetIsAccessibilityId())
+ {
+ var elements = this.windowsElement.FindElementsByAccessibilityId(by.GetAccessibilityId());
+ return elements;
+ }
+ else
+ {
+ var elements = this.windowsElement.FindElements(by.ToSeleniumBy());
+ return elements;
+ }
},
this.driver,
timeoutMS);
diff --git a/src/common/UITestAutomation/Session.cs b/src/common/UITestAutomation/Session.cs
index f4b5535ae10d..9e5101fc759e 100644
--- a/src/common/UITestAutomation/Session.cs
+++ b/src/common/UITestAutomation/Session.cs
@@ -8,6 +8,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
+using OpenQA.Selenium.Interactions;
namespace Microsoft.PowerToys.UITest
{
@@ -62,26 +63,6 @@ public T Find(string name, int timeoutMS = 3000)
return this.Find(By.Name(name), timeoutMS);
}
- ///
- /// Shortcut for this.FindAllByAccessibilityId(accessibilityId, timeoutMS)
- ///
- /// The class of the element, should be Element or its derived class.
- /// The accessibilityId of the element.
- /// The timeout in milliseconds (default is 3000).
- /// The found element.
- public T FindByAccessibilityId(string accessibilityId, int timeoutMS = 3000)
- where T : Element, new()
- {
- Assert.IsNotNull(this.WindowsDriver, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: accessibilityId = {accessibilityId}, timeoutMS = {timeoutMS}");
-
- // leverage findAll to filter out mismatched elements
- var collection = this.FindAllByAccessibilityId(accessibilityId, timeoutMS);
-
- Assert.IsTrue(collection.Count > 0, $"Element not found using selector: {accessibilityId}");
-
- return collection[0];
- }
-
///
/// Shortcut for this.Find(by, timeoutMS)
///
@@ -118,31 +99,16 @@ public ReadOnlyCollection FindAll(By by, int timeoutMS = 3000)
var foundElements = FindHelper.FindAll(
() =>
{
- var elements = this.WindowsDriver.FindElements(by.ToSeleniumBy());
- return elements;
- },
- this.WindowsDriver,
- timeoutMS);
-
- return foundElements ?? new ReadOnlyCollection([]);
- }
-
- ///
- /// Finds all elements by accessibilityId.
- ///
- /// The class of the elements, should be Element or its derived class.
- /// The accessibilityId to find the elements.
- /// The timeout in milliseconds (default is 3000).
- /// A read-only collection of the found elements.
- public ReadOnlyCollection FindAllByAccessibilityId(string accessibilityId, int timeoutMS = 3000)
- where T : Element, new()
- {
- Assert.IsNotNull(this.WindowsDriver, $"WindowsElement is null in method FindAll<{typeof(T).Name}> with parameters: accessibilityId = {accessibilityId}, timeoutMS = {timeoutMS}");
- var foundElements = FindHelper.FindAll(
- () =>
- {
- var elements = this.WindowsDriver.FindElementsByAccessibilityId(accessibilityId);
- return elements;
+ if (by.GetIsAccessibilityId())
+ {
+ var elements = this.WindowsDriver.FindElementsByAccessibilityId(by.GetAccessibilityId());
+ return elements;
+ }
+ else
+ {
+ var elements = this.WindowsDriver.FindElements(by.ToSeleniumBy());
+ return elements;
+ }
},
this.WindowsDriver,
timeoutMS);
@@ -188,6 +154,39 @@ public ReadOnlyCollection FindAll(string name, int timeoutMS = 3000)
return this.FindAll(By.Name(name), timeoutMS);
}
+ ///
+ /// Keyboard Action key.
+ ///
+ /// The Keys1 to click.
+ /// The Keys2 to click.
+ /// The Keys3 to click.
+ /// The Keys4 to click.
+ public void KeyboardAction(string key1, string key2 = "", string key3 = "", string key4 = "")
+ {
+ PerformAction((actions, windowElement) =>
+ {
+ if (string.IsNullOrEmpty(key2))
+ {
+ actions.SendKeys(key1);
+ }
+ else if (string.IsNullOrEmpty(key3))
+ {
+ actions.SendKeys(key1).SendKeys(key2);
+ }
+ else if (string.IsNullOrEmpty(key4))
+ {
+ actions.SendKeys(key1).SendKeys(key2).SendKeys(key3);
+ }
+ else
+ {
+ actions.SendKeys(key1).SendKeys(key2).SendKeys(key3).SendKeys(key4);
+ }
+
+ actions.Release();
+ actions.Build().Perform();
+ });
+ }
+
///
/// Attaches to an existing PowerToys module.
///
@@ -232,5 +231,28 @@ public Session Attach(string windowName)
return this;
}
+
+ ///
+ /// Simulates a manual operation on the element.
+ ///
+ /// The action to perform on the element.
+ /// The number of milliseconds to wait before the action. Default value is 500 ms
+ /// The number of milliseconds to wait after the action. Default value is 500 ms
+ protected void PerformAction(Action> action, int msPreAction = 500, int msPostAction = 500)
+ {
+ if (msPreAction > 0)
+ {
+ Task.Delay(msPreAction).Wait();
+ }
+
+ var windowsDriver = this.WindowsDriver;
+ Actions actions = new Actions(this.WindowsDriver);
+ action(actions, windowsDriver);
+
+ if (msPostAction > 0)
+ {
+ Task.Delay(msPostAction).Wait();
+ }
+ }
}
}
diff --git a/src/common/UITestAutomation/UITestBase.cs b/src/common/UITestAutomation/UITestBase.cs
index d9887708289e..1fb37468ff2a 100644
--- a/src/common/UITestAutomation/UITestBase.cs
+++ b/src/common/UITestAutomation/UITestBase.cs
@@ -52,9 +52,10 @@ public void TestInit()
///
/// UnInitializes the test.
///
+ [TestCleanup]
public void TestClean()
{
- this.sessionHelper.Cleanup();
+ // this.sessionHelper.Cleanup();
}
///
diff --git a/src/modules/fancyzones/UITests-FancyZonesEditor/DefaultLayoutsTest.cs b/src/modules/fancyzones/UITests-FancyZonesEditor/DefaultLayoutsTest.cs
index 4f95b4712e7a..06c06d53e289 100644
--- a/src/modules/fancyzones/UITests-FancyZonesEditor/DefaultLayoutsTest.cs
+++ b/src/modules/fancyzones/UITests-FancyZonesEditor/DefaultLayoutsTest.cs
@@ -64,27 +64,21 @@ public DefaultLayoutsTest()
FancyZonesEditorHelper.Files.ParamsIOHelper.WriteData(editorParameters.Serialize(parameters));
}
- [TestCleanup]
- public void TestCleanup()
- {
- this.TestClean();
- }
-
[TestMethod]
public void ClickMonitor()
{
- Assert.IsNotNull(Session.FindByAccessibilityId("Monitors").Find("Monitor 1"));
- Assert.IsNotNull(Session.FindByAccessibilityId("Monitors").Find("Monitor 2"));
+ Assert.IsNotNull(Session.Find("Monitor 1"));
+ Assert.IsNotNull(Session.Find("Monitor 2"));
// verify that the monitor 1 is selected initially
- Assert.IsTrue(Session.FindByAccessibilityId("Monitors").Find("Monitor 1").Selected);
- Assert.IsFalse(Session.FindByAccessibilityId("Monitors").Find("Monitor 2").Selected);
+ Assert.IsTrue(Session.Find("Monitor 1").Selected);
+ Assert.IsFalse(Session.Find("Monitor 2").Selected);
- Session.FindByAccessibilityId("Monitors").Find("Monitor 2").Click();
+ Session.Find("Monitor 2").Click();
// verify that the monitor 2 is selected after click
- Assert.IsFalse(Session.FindByAccessibilityId("Monitors").Find("Monitor 1").Selected);
- Assert.IsTrue(Session.FindByAccessibilityId("Monitors").Find("Monitor 2").Selected);
+ Assert.IsFalse(Session.Find("Monitor 1").Selected);
+ Assert.IsTrue(Session.Find("Monitor 2").Selected);
}
}
}
diff --git a/src/modules/fancyzones/UITests-FancyZonesEditor/DeleteLayoutTests.cs b/src/modules/fancyzones/UITests-FancyZonesEditor/DeleteLayoutTests.cs
new file mode 100644
index 000000000000..4d24dc4045c4
--- /dev/null
+++ b/src/modules/fancyzones/UITests-FancyZonesEditor/DeleteLayoutTests.cs
@@ -0,0 +1,356 @@
+// 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.Collections.Generic;
+using FancyZonesEditor.Models;
+using FancyZonesEditorCommon.Data;
+using Microsoft.FancyZonesEditor.UnitTests.Utils;
+using Microsoft.PowerToys.UITest;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using ModernWpf.Controls;
+using OpenQA.Selenium;
+using static FancyZonesEditorCommon.Data.CustomLayouts;
+using static FancyZonesEditorCommon.Data.DefaultLayouts;
+using static FancyZonesEditorCommon.Data.EditorParameters;
+using static FancyZonesEditorCommon.Data.LayoutHotkeys;
+using static Microsoft.FancyZonesEditor.UnitTests.Utils.FancyZonesEditorHelper;
+
+namespace Microsoft.FancyZonesEditor.UITests
+{
+ [TestClass]
+ public class DeleteLayoutTests : UITestBase
+ {
+ public DeleteLayoutTests()
+ : base(PowerToysModule.FancyZone)
+ {
+ }
+
+ private static readonly CustomLayoutListWrapper CustomLayouts = new CustomLayoutListWrapper
+ {
+ CustomLayouts = new List
+ {
+ new CustomLayoutWrapper
+ {
+ Uuid = "{0D6D2F58-9184-4804-81E4-4E4CC3476DC1}",
+ Type = CustomLayout.Grid.TypeToString(),
+ Name = "Custom layout 1",
+ Info = new CustomLayouts().ToJsonElement(new CustomLayouts.GridInfoWrapper
+ {
+ Rows = 2,
+ Columns = 3,
+ RowsPercentage = new List { 2967, 7033 },
+ ColumnsPercentage = new List { 2410, 6040, 1550 },
+ CellChildMap = new int[][] { [0, 1, 1], [0, 2, 3] },
+ SensitivityRadius = 30,
+ Spacing = 26,
+ ShowSpacing = false,
+ }),
+ },
+ new CustomLayoutWrapper
+ {
+ Uuid = "{E7807D0D-6223-4883-B15B-1F3883944C09}",
+ Type = CustomLayout.Canvas.TypeToString(),
+ Name = "Custom layout 2",
+ Info = new CustomLayouts().ToJsonElement(new CanvasInfoWrapper
+ {
+ RefHeight = 952,
+ RefWidth = 1500,
+ SensitivityRadius = 10,
+ Zones = new List
+ {
+ new CanvasInfoWrapper.CanvasZoneWrapper
+ {
+ X = 0,
+ Y = 0,
+ Width = 900,
+ Height = 522,
+ },
+ new CanvasInfoWrapper.CanvasZoneWrapper
+ {
+ X = 900,
+ Y = 0,
+ Width = 600,
+ Height = 750,
+ },
+ new CanvasInfoWrapper.CanvasZoneWrapper
+ {
+ X = 0,
+ Y = 522,
+ Width = 1500,
+ Height = 430,
+ },
+ },
+ }),
+ },
+ },
+ };
+
+ private static readonly DefaultLayouts.DefaultLayoutsListWrapper DefaultLayoutsList = new DefaultLayouts.DefaultLayoutsListWrapper
+ {
+ DefaultLayouts = new List
+ {
+ new DefaultLayoutWrapper
+ {
+ MonitorConfiguration = MonitorConfigurationType.Horizontal.TypeToString(),
+ Layout = new DefaultLayoutWrapper.LayoutWrapper
+ {
+ Type = LayoutType.Custom.TypeToString(),
+ Uuid = CustomLayouts.CustomLayouts[1].Uuid,
+ },
+ },
+ },
+ };
+
+ private static readonly LayoutHotkeys.LayoutHotkeysWrapper Hotkeys = new LayoutHotkeys.LayoutHotkeysWrapper
+ {
+ LayoutHotkeys = new List
+ {
+ new LayoutHotkeyWrapper
+ {
+ LayoutId = CustomLayouts.CustomLayouts[1].Uuid,
+ Key = 0,
+ },
+ },
+ };
+
+ private static readonly ParamsWrapper Parameters = new ParamsWrapper
+ {
+ ProcessId = 1,
+ SpanZonesAcrossMonitors = false,
+ Monitors = new List
+ {
+ new NativeMonitorDataWrapper
+ {
+ Monitor = "monitor-1",
+ MonitorInstanceId = "instance-id-1",
+ MonitorSerialNumber = "serial-number-1",
+ MonitorNumber = 1,
+ VirtualDesktop = "{FF34D993-73F3-4B8C-AA03-73730A01D6A8}",
+ Dpi = 192,
+ LeftCoordinate = 0,
+ TopCoordinate = 0,
+ WorkAreaHeight = 1040,
+ WorkAreaWidth = 1920,
+ MonitorHeight = 1080,
+ MonitorWidth = 1920,
+ IsSelected = true,
+ },
+ },
+ };
+
+ [TestInitialize]
+ public void TestInitialize()
+ {
+ EditorParameters editorParameters = new EditorParameters();
+ FancyZonesEditorHelper.Files.ParamsIOHelper.WriteData(editorParameters.Serialize(Parameters));
+
+ CustomLayouts customLayouts = new CustomLayouts();
+ FancyZonesEditorHelper.Files.CustomLayoutsIOHelper.WriteData(customLayouts.Serialize(CustomLayouts));
+
+ LayoutTemplates layoutTemplates = new LayoutTemplates();
+ LayoutTemplates.TemplateLayoutsListWrapper templateLayoutsListWrapper = new LayoutTemplates.TemplateLayoutsListWrapper
+ {
+ LayoutTemplates = new List
+ {
+ new LayoutTemplates.TemplateLayoutWrapper
+ {
+ Type = LayoutType.Blank.TypeToString(),
+ },
+ new LayoutTemplates.TemplateLayoutWrapper
+ {
+ Type = LayoutType.Focus.TypeToString(),
+ ZoneCount = 10,
+ },
+ new LayoutTemplates.TemplateLayoutWrapper
+ {
+ Type = LayoutType.Rows.TypeToString(),
+ ZoneCount = 2,
+ ShowSpacing = true,
+ Spacing = 10,
+ SensitivityRadius = 10,
+ },
+ new LayoutTemplates.TemplateLayoutWrapper
+ {
+ Type = LayoutType.Columns.TypeToString(),
+ ZoneCount = 2,
+ ShowSpacing = true,
+ Spacing = 20,
+ SensitivityRadius = 20,
+ },
+ new LayoutTemplates.TemplateLayoutWrapper
+ {
+ Type = LayoutType.Grid.TypeToString(),
+ ZoneCount = 4,
+ ShowSpacing = false,
+ Spacing = 10,
+ SensitivityRadius = 30,
+ },
+ new LayoutTemplates.TemplateLayoutWrapper
+ {
+ Type = LayoutType.PriorityGrid.TypeToString(),
+ ZoneCount = 3,
+ ShowSpacing = true,
+ Spacing = 1,
+ SensitivityRadius = 40,
+ },
+ },
+ };
+ FancyZonesEditorHelper.Files.LayoutTemplatesIOHelper.WriteData(layoutTemplates.Serialize(templateLayoutsListWrapper));
+
+ DefaultLayouts defaultLayouts = new DefaultLayouts();
+ FancyZonesEditorHelper.Files.DefaultLayoutsIOHelper.WriteData(defaultLayouts.Serialize(DefaultLayoutsList));
+
+ LayoutHotkeys layoutHotkeys = new LayoutHotkeys();
+ FancyZonesEditorHelper.Files.LayoutHotkeysIOHelper.WriteData(layoutHotkeys.Serialize(Hotkeys));
+
+ AppliedLayouts appliedLayouts = new AppliedLayouts();
+ AppliedLayouts.AppliedLayoutsListWrapper appliedLayoutsWrapper = new AppliedLayouts.AppliedLayoutsListWrapper
+ {
+ AppliedLayouts = new List { },
+ };
+ FancyZonesEditorHelper.Files.AppliedLayoutsIOHelper.WriteData(appliedLayouts.Serialize(appliedLayoutsWrapper));
+
+ this.RestartScopeExe();
+ Session.Find(CustomLayouts.CustomLayouts[0].Name).Click();
+ }
+
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ FancyZonesEditorHelper.Files.Restore();
+ }
+
+ [TestMethod]
+ public void DeleteNotAppliedLayout()
+ {
+ var deletedLayout = CustomLayouts.CustomLayouts[1].Name;
+ Session.Find(deletedLayout).Find