diff --git a/src/common/UITestAutomation/Element/By.cs b/src/common/UITestAutomation/Element/By.cs
index 5ccaf1eb06..b2d8ecf6c4 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();
+ }
}
///
@@ -31,6 +54,13 @@ namespace Microsoft.PowerToys.UITest
/// A By object.
public static By Name(string name) => new By(OpenQA.Selenium.By.Name(name));
+ ///
+ /// Creates a By object using the className attribute.
+ ///
+ /// The className attribute to search for.
+ /// A By object.
+ public static By ClassName(string className) => new By(OpenQA.Selenium.By.ClassName(className));
+
///
/// Creates a By object using the ID attribute.
///
@@ -38,6 +68,13 @@ namespace Microsoft.PowerToys.UITest
/// 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.
///
@@ -70,6 +107,6 @@ namespace Microsoft.PowerToys.UITest
/// 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 59c799e401..7ca0cf53a5 100644
--- a/src/common/UITestAutomation/Element/Element.cs
+++ b/src/common/UITestAutomation/Element/Element.cs
@@ -3,8 +3,13 @@
// See the LICENSE file in the project root for more information.
using System.Collections.ObjectModel;
+using System.Drawing;
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;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
@@ -63,6 +68,14 @@ namespace Microsoft.PowerToys.UITest
get { return this.windowsElement?.Selected ?? false; }
}
+ ///
+ /// Gets the Rect of the UI element.
+ ///
+ public Rectangle? Rect
+ {
+ get { return this.windowsElement?.Rect; }
+ }
+
///
/// Gets the AutomationID of the UI element.
///
@@ -138,6 +151,54 @@ namespace Microsoft.PowerToys.UITest
});
}
+ ///
+ /// Drag element move offset.
+ ///
+ /// The offsetX to move.
+ /// The offsetY to move.
+ public void Drag(int offsetX, int offsetY)
+ {
+ PerformAction((actions, windowElement) =>
+ {
+ actions.MoveToElement(windowElement).MoveByOffset(10, 10).ClickAndHold(windowElement).MoveByOffset(offsetX, offsetY).Release();
+ actions.Build().Perform();
+ });
+ }
+
+ ///
+ /// Drag element move to other element.
+ ///
+ /// Move to this element.
+ public void Drag(Element element)
+ {
+ PerformAction((actions, windowElement) =>
+ {
+ actions.MoveToElement(windowElement).ClickAndHold();
+ Assert.IsNotNull(element.windowsElement, "element is null");
+ int dx = (element.windowsElement.Rect.X - windowElement.Rect.X) / 10;
+ int dy = (element.windowsElement.Rect.Y - windowElement.Rect.Y) / 10;
+ for (int i = 0; i < 10; i++)
+ {
+ actions.MoveByOffset(dx, dy);
+ }
+
+ actions.Release();
+ actions.Build().Perform();
+ });
+ }
+
+ ///
+ /// Send Key of the element.
+ ///
+ /// The Key to Send.
+ public void SendKeys(string key)
+ {
+ PerformAction((actions, windowElement) =>
+ {
+ windowElement.SendKeys(key);
+ });
+ }
+
///
/// Gets the attribute value of the UI element.
///
@@ -222,8 +283,16 @@ namespace Microsoft.PowerToys.UITest
var foundElements = FindHelper.FindAll(
() =>
{
- var elements = this.windowsElement.FindElements(by.ToSeleniumBy());
- 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/FindHelper.cs b/src/common/UITestAutomation/FindHelper.cs
index 5f25dfcb15..465f1206a1 100644
--- a/src/common/UITestAutomation/FindHelper.cs
+++ b/src/common/UITestAutomation/FindHelper.cs
@@ -17,6 +17,19 @@ namespace Microsoft.PowerToys.UITest
///
internal static class FindHelper
{
+ public static ReadOnlyCollection? FindAll(Func> findElementsFunc, WindowsDriver? driver, int timeoutMS)
+ where T : Element, new()
+ {
+ var items = findElementsFunc();
+ var res = items.Select(item =>
+ {
+ var element = item as WindowsElement;
+ return NewElement(element, driver, timeoutMS);
+ }).Where(item => item.IsMatchingTarget()).ToList();
+
+ return new ReadOnlyCollection(res);
+ }
+
public static ReadOnlyCollection? FindAll(Func> findElementsFunc, WindowsDriver? driver, int timeoutMS)
where T : Element, new()
{
diff --git a/src/common/UITestAutomation/Session.cs b/src/common/UITestAutomation/Session.cs
index ef0a6fff3f..9e5101fc75 100644
--- a/src/common/UITestAutomation/Session.cs
+++ b/src/common/UITestAutomation/Session.cs
@@ -8,6 +8,7 @@ using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
+using OpenQA.Selenium.Interactions;
namespace Microsoft.PowerToys.UITest
{
@@ -98,8 +99,16 @@ namespace Microsoft.PowerToys.UITest
var foundElements = FindHelper.FindAll(
() =>
{
- var elements = this.WindowsDriver.FindElements(by.ToSeleniumBy());
- 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);
@@ -145,6 +154,39 @@ namespace Microsoft.PowerToys.UITest
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.
///
@@ -189,5 +231,28 @@ namespace Microsoft.PowerToys.UITest
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/SessionHelper.cs b/src/common/UITestAutomation/SessionHelper.cs
index 7bb1f6e7a6..324f41e5e3 100644
--- a/src/common/UITestAutomation/SessionHelper.cs
+++ b/src/common/UITestAutomation/SessionHelper.cs
@@ -2,6 +2,7 @@
// 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;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
@@ -19,15 +20,19 @@ namespace Microsoft.PowerToys.UITest
// Default session path is PowerToys settings dashboard
private readonly string sessionPath = ModuleConfigData.Instance.GetModulePath(PowerToysModule.PowerToysSettings);
+ private string? locationPath;
+
private WindowsDriver Root { get; set; }
private WindowsDriver? Driver { get; set; }
private Process? appDriver;
+ [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "")]
public SessionHelper(PowerToysModule scope)
{
this.sessionPath = ModuleConfigData.Instance.GetModulePath(scope);
+ this.locationPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var winAppDriverProcessInfo = new ProcessStartInfo
{
@@ -49,17 +54,12 @@ namespace Microsoft.PowerToys.UITest
/// Initializes the test environment.
///
/// The PowerToys module to start.
- [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "")]
public SessionHelper Init()
{
- string? path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
- this.StartExe(path + this.sessionPath);
+ this.StartExe(locationPath + this.sessionPath);
Assert.IsNotNull(this.Driver, $"Failed to initialize the test environment. Driver is null.");
- // Set default timeout to 5 seconds
- this.Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
-
return this;
}
@@ -68,9 +68,11 @@ namespace Microsoft.PowerToys.UITest
///
public void Cleanup()
{
+ ExitScopeExe();
try
{
appDriver?.Kill();
+ appDriver?.WaitForExit(); // Optional: Wait for the process to exit
}
catch (Exception ex)
{
@@ -87,7 +89,53 @@ namespace Microsoft.PowerToys.UITest
{
var opts = new AppiumOptions();
opts.AddAdditionalCapability("app", appPath);
+ Console.WriteLine($"appPath: {appPath}");
this.Driver = new WindowsDriver(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), opts);
+
+ // Set default timeout to 5 seconds
+ this.Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
+ }
+
+ ///
+ /// Exit a exe.
+ ///
+ /// The path to the application executable.
+ public void ExitExe(string path)
+ {
+ // Exit Exe
+ string exeName = Path.GetFileNameWithoutExtension(path);
+
+ // PowerToys.FancyZonesEditor
+ Process[] processes = Process.GetProcessesByName(exeName);
+ foreach (Process process in processes)
+ {
+ try
+ {
+ process.Kill();
+ process.WaitForExit(); // Optional: Wait for the process to exit
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail($"Failed to terminate process {process.ProcessName} (ID: {process.Id}): {ex.Message}");
+ }
+ }
+ }
+
+ ///
+ /// Exit now exe.
+ ///
+ public void ExitScopeExe()
+ {
+ ExitExe(sessionPath);
+ }
+
+ ///
+ /// Restarts now exe and takes control of it.
+ ///
+ public void RestartScopeExe()
+ {
+ ExitExe(sessionPath);
+ StartExe(locationPath + sessionPath);
}
public WindowsDriver GetRoot() => this.Root;
diff --git a/src/common/UITestAutomation/UITestBase.cs b/src/common/UITestAutomation/UITestBase.cs
index 1d6502ac54..40de0dc991 100644
--- a/src/common/UITestAutomation/UITestBase.cs
+++ b/src/common/UITestAutomation/UITestBase.cs
@@ -6,6 +6,7 @@ using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
+using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
@@ -31,11 +32,6 @@ namespace Microsoft.PowerToys.UITest
this.Session = new Session(this.sessionHelper.GetRoot(), this.sessionHelper.GetDriver());
}
- ~UITestBase()
- {
- this.sessionHelper.Cleanup();
- }
-
///
/// Initializes the test.
///
@@ -53,6 +49,15 @@ namespace Microsoft.PowerToys.UITest
}
}
+ ///
+ /// UnInitializes the test.
+ ///
+ [TestCleanup]
+ public void TestClean()
+ {
+ this.sessionHelper.Cleanup();
+ }
+
///
/// Finds an element by selector.
/// Shortcut for this.Session.Find(by, timeoutMS)
@@ -153,5 +158,24 @@ namespace Microsoft.PowerToys.UITest
{
return this.Session.FindAll(By.Name(name), timeoutMS);
}
+
+ ///
+ /// Restart scope exe.
+ ///
+ public void RestartScopeExe()
+ {
+ this.sessionHelper.RestartScopeExe();
+ this.Session = new Session(this.sessionHelper.GetRoot(), this.sessionHelper.GetDriver());
+ return;
+ }
+
+ ///
+ /// Restart scope exe.
+ ///
+ public void ExitScopeExe()
+ {
+ this.sessionHelper.ExitScopeExe();
+ return;
+ }
}
}
diff --git a/src/modules/fancyzones/FancyZonesEditorCommon/Data/CustomLayoutEnumExtension.cs b/src/modules/fancyzones/FancyZonesEditorCommon/Data/CustomLayoutEnumExtension.cs
new file mode 100644
index 0000000000..4f158b3aca
--- /dev/null
+++ b/src/modules/fancyzones/FancyZonesEditorCommon/Data/CustomLayoutEnumExtension.cs
@@ -0,0 +1,44 @@
+// 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.
+
+namespace FancyZonesEditorCommon.Data
+{
+ public enum CustomLayout
+ {
+ Canvas,
+ Grid,
+ }
+
+ public static class CustomLayoutEnumExtension
+ {
+ private const string CanvasJsonTag = "canvas";
+ private const string GridJsonTag = "grid";
+
+ public static string TypeToString(this CustomLayout value)
+ {
+ switch (value)
+ {
+ case CustomLayout.Canvas:
+ return CanvasJsonTag;
+ case CustomLayout.Grid:
+ return GridJsonTag;
+ }
+
+ return CanvasJsonTag;
+ }
+
+ public static CustomLayout TypeFromString(string value)
+ {
+ switch (value)
+ {
+ case CanvasJsonTag:
+ return CustomLayout.Canvas;
+ case GridJsonTag:
+ return CustomLayout.Grid;
+ }
+
+ return CustomLayout.Canvas;
+ }
+ }
+}
diff --git a/src/modules/fancyzones/UITests-FancyZonesEditor/ApplyLayoutTests.cs b/src/modules/fancyzones/UITests-FancyZonesEditor/ApplyLayoutTests.cs
new file mode 100644
index 0000000000..2ae581ebe1
--- /dev/null
+++ b/src/modules/fancyzones/UITests-FancyZonesEditor/ApplyLayoutTests.cs
@@ -0,0 +1,308 @@
+// 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 System.Globalization;
+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 Microsoft.FancyZonesEditor.UnitTests.Utils.FancyZonesEditorHelper;
+
+namespace Microsoft.FancyZonesEditor.UITests
+{
+ [TestClass]
+ public class ApplyLayoutTests : UITestBase
+ {
+ public ApplyLayoutTests()
+ : base(PowerToysModule.FancyZone)
+ {
+ }
+
+ private static readonly EditorParameters.ParamsWrapper Parameters = new EditorParameters.ParamsWrapper
+ {
+ ProcessId = 1,
+ SpanZonesAcrossMonitors = false,
+ Monitors = new List
+ {
+ new EditorParameters.NativeMonitorDataWrapper
+ {
+ Monitor = "monitor-1",
+ MonitorInstanceId = "instance-id-1",
+ MonitorSerialNumber = "serial-number-1",
+ MonitorNumber = 1,
+ VirtualDesktop = "{FF34D993-73F3-4B8C-AA03-73730A01D6A8}",
+ Dpi = 96,
+ LeftCoordinate = 0,
+ TopCoordinate = 0,
+ WorkAreaHeight = 1040,
+ WorkAreaWidth = 1920,
+ MonitorHeight = 1080,
+ MonitorWidth = 1920,
+ IsSelected = true,
+ },
+ new EditorParameters.NativeMonitorDataWrapper
+ {
+ Monitor = "monitor-2",
+ MonitorInstanceId = "instance-id-2",
+ MonitorSerialNumber = "serial-number-2",
+ MonitorNumber = 2,
+ VirtualDesktop = "{FF34D993-73F3-4B8C-AA03-73730A01D6A8}",
+ Dpi = 96,
+ LeftCoordinate = 1920,
+ TopCoordinate = 0,
+ WorkAreaHeight = 1040,
+ WorkAreaWidth = 1920,
+ MonitorHeight = 1080,
+ MonitorWidth = 1920,
+ IsSelected = false,
+ },
+ },
+ };
+
+ private static readonly CustomLayouts.CustomLayoutListWrapper CustomLayoutsList = new CustomLayouts.CustomLayoutListWrapper
+ {
+ CustomLayouts = new List
+ {
+ new CustomLayouts.CustomLayoutWrapper
+ {
+ Uuid = "{E7807D0D-6223-4883-B15B-1F3883944C09}",
+ Type = CustomLayout.Canvas.TypeToString(),
+ Name = "Custom layout",
+ Info = new CustomLayouts().ToJsonElement(new CustomLayouts.CanvasInfoWrapper
+ {
+ RefHeight = 952,
+ RefWidth = 1500,
+ SensitivityRadius = 10,
+ Zones = new List { },
+ }),
+ },
+ },
+ };
+
+ private static readonly LayoutTemplates.TemplateLayoutsListWrapper TemplateLayoutsList = 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,
+ },
+ },
+ };
+
+ [TestInitialize]
+ public void TestInitialize()
+ {
+ EditorParameters editorParameters = new EditorParameters();
+ FancyZonesEditorHelper.Files.ParamsIOHelper.WriteData(editorParameters.Serialize(Parameters));
+
+ LayoutTemplates layoutTemplates = new LayoutTemplates();
+ FancyZonesEditorHelper.Files.LayoutTemplatesIOHelper.WriteData(layoutTemplates.Serialize(TemplateLayoutsList));
+
+ CustomLayouts customLayouts = new CustomLayouts();
+ FancyZonesEditorHelper.Files.CustomLayoutsIOHelper.WriteData(customLayouts.Serialize(CustomLayoutsList));
+
+ DefaultLayouts defaultLayouts = new DefaultLayouts();
+ DefaultLayouts.DefaultLayoutsListWrapper defaultLayoutsListWrapper = new DefaultLayouts.DefaultLayoutsListWrapper
+ {
+ DefaultLayouts = new List
+ {
+ new DefaultLayouts.DefaultLayoutWrapper
+ {
+ MonitorConfiguration = MonitorConfigurationType.Horizontal.TypeToString(),
+ Layout = new DefaultLayouts.DefaultLayoutWrapper.LayoutWrapper
+ {
+ Type = LayoutType.Focus.TypeToString(),
+ ZoneCount = 4,
+ ShowSpacing = true,
+ Spacing = 5,
+ SensitivityRadius = 20,
+ },
+ },
+ new DefaultLayouts.DefaultLayoutWrapper
+ {
+ MonitorConfiguration = MonitorConfigurationType.Vertical.TypeToString(),
+ Layout = new DefaultLayouts.DefaultLayoutWrapper.LayoutWrapper
+ {
+ Type = LayoutType.Custom.TypeToString(),
+ Uuid = "{0D6D2F58-9184-4804-81E4-4E4CC3476DC1}",
+ ZoneCount = 0,
+ ShowSpacing = false,
+ Spacing = 0,
+ SensitivityRadius = 0,
+ },
+ },
+ },
+ };
+ FancyZonesEditorHelper.Files.DefaultLayoutsIOHelper.WriteData(defaultLayouts.Serialize(defaultLayoutsListWrapper));
+
+ LayoutHotkeys layoutHotkeys = new LayoutHotkeys();
+ LayoutHotkeys.LayoutHotkeysWrapper layoutHotkeysWrapper = new LayoutHotkeys.LayoutHotkeysWrapper
+ {
+ LayoutHotkeys = new List { },
+ };
+ FancyZonesEditorHelper.Files.LayoutHotkeysIOHelper.WriteData(layoutHotkeys.Serialize(layoutHotkeysWrapper));
+
+ AppliedLayouts appliedLayouts = new AppliedLayouts();
+ AppliedLayouts.AppliedLayoutsListWrapper appliedLayoutsWrapper = new AppliedLayouts.AppliedLayoutsListWrapper
+ {
+ AppliedLayouts = new List { },
+ };
+ FancyZonesEditorHelper.Files.AppliedLayoutsIOHelper.WriteData(appliedLayouts.Serialize(appliedLayoutsWrapper));
+
+ this.RestartScopeExe();
+ }
+
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ FancyZonesEditorHelper.Files.Restore();
+ }
+
+ [TestMethod]
+ public void ApplyCustomLayout()
+ {
+ var layout = CustomLayoutsList.CustomLayouts[0];
+ Assert.IsFalse(Session.Find(layout.Name).Selected);
+ Session.Find(layout.Name).Click();
+
+ Assert.IsTrue(Session.Find(layout.Name).Selected);
+
+ AppliedLayouts appliedLayouts = new AppliedLayouts();
+ var data = appliedLayouts.Read(appliedLayouts.File);
+ Assert.AreEqual(Parameters.Monitors.Count, data.AppliedLayouts.Count);
+ Assert.AreEqual(layout.Uuid, data.AppliedLayouts[0].AppliedLayout.Uuid);
+ Assert.AreEqual(Parameters.Monitors[0].MonitorNumber, data.AppliedLayouts[0].Device.MonitorNumber);
+ }
+
+ [TestMethod]
+ public void ApplyTemplateLayout()
+ {
+ var layoutType = LayoutType.Columns;
+ var layout = TestConstants.TemplateLayoutNames[layoutType];
+ Assert.IsFalse(Session.Find(layout).Selected);
+ Session.Find(layout).Click();
+
+ Assert.IsTrue(Session.Find(layout).Selected);
+
+ AppliedLayouts appliedLayouts = new AppliedLayouts();
+ var data = appliedLayouts.Read(appliedLayouts.File);
+ Assert.AreEqual(Parameters.Monitors.Count, data.AppliedLayouts.Count);
+ Assert.AreEqual(layoutType.TypeToString(), data.AppliedLayouts[0].AppliedLayout.Type);
+ Assert.AreEqual(Parameters.Monitors[0].MonitorNumber, data.AppliedLayouts[0].Device.MonitorNumber);
+ }
+
+ [TestMethod]
+ public void ApplyLayoutsOnEachMonitor()
+ {
+ // apply the layout on the first monitor
+ var firstLayoutType = LayoutType.Columns;
+ var firstLayoutName = TestConstants.TemplateLayoutNames[firstLayoutType];
+ Session.Find(firstLayoutName).Click();
+ Assert.IsTrue(Session.Find(firstLayoutName)!.Selected);
+
+ // apply the layout on the second monitor
+ Session.Find(PowerToys.UITest.By.AccessibilityId("Monitors")).Find("Monitor 2").Click();
+ var secondLayout = CustomLayoutsList.CustomLayouts[0];
+ Session.Find(secondLayout.Name).Click();
+ Assert.IsTrue(Session.Find(secondLayout.Name)!.Selected);
+
+ // verify the layout on the first monitor wasn't changed
+ Session.Find(PowerToys.UITest.By.AccessibilityId("Monitors")).Find("Monitor 1").Click();
+ Assert.IsTrue(Session.Find(firstLayoutName)!.Selected);
+
+ // verify the file
+ var appliedLayouts = new AppliedLayouts();
+ var data = appliedLayouts.Read(appliedLayouts.File);
+ Assert.AreEqual(Parameters.Monitors.Count, data.AppliedLayouts.Count);
+ Assert.AreEqual(firstLayoutType.TypeToString(), data.AppliedLayouts.Find(x => x.Device.MonitorNumber == 1).AppliedLayout.Type);
+ Assert.AreEqual(secondLayout.Uuid, data.AppliedLayouts.Find(x => x.Device.MonitorNumber == 2).AppliedLayout.Uuid);
+ }
+
+ [TestMethod]
+ public void ApplyTemplateWithDifferentParametersOnEachMonitor()
+ {
+ var layoutType = LayoutType.Columns;
+ var layoutName = TestConstants.TemplateLayoutNames[layoutType];
+
+ // apply the layout on the first monitor, set parameters
+ Session.Find(layoutName).Click();
+ Session.Find(layoutName).Find