From fe53a9c89ae2d913f9ba759741a25f05032c40d4 Mon Sep 17 00:00:00 2001 From: Clint Rutkas Date: Thu, 10 Apr 2025 05:27:17 +0000 Subject: [PATCH 01/14] empowering users to maximize OOBE to their heart desire (#37823) empowering users to maximize to their heart desire --- .../SettingsXAML/OobeWindow.xaml.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/settings-ui/Settings.UI/SettingsXAML/OobeWindow.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/OobeWindow.xaml.cs index 48153c127a..56262fea6a 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/OobeWindow.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/OobeWindow.xaml.cs @@ -31,7 +31,6 @@ namespace Microsoft.PowerToys.Settings.UI private WindowId _windowId; private IntPtr _hWnd; private AppWindow _appWindow; - private WindowMessageMonitor _msgMonitor; private bool disposedValue; public OobeWindow(PowerToysModules initialModule) @@ -46,10 +45,6 @@ namespace Microsoft.PowerToys.Settings.UI _appWindow = AppWindow.GetFromWindowId(_windowId); this.Activated += Window_Activated_SetIcon; - OverlappedPresenter presenter = _appWindow.Presenter as OverlappedPresenter; - presenter.IsMinimizable = false; - presenter.IsMaximizable = false; - var dpi = NativeMethods.GetDpiForWindow(_hWnd); _currentDPI = dpi; float scalingFactor = (float)dpi / DefaultDPI; @@ -63,18 +58,6 @@ namespace Microsoft.PowerToys.Settings.UI this.initialModule = initialModule; - _msgMonitor = new WindowMessageMonitor(this); - _msgMonitor.WindowMessageReceived += (_, e) => - { - const int WM_NCLBUTTONDBLCLK = 0x00A3; - if (e.Message.MessageId == WM_NCLBUTTONDBLCLK) - { - // Disable double click on title bar to maximize window - e.Result = 0; - e.Handled = true; - } - }; - this.SizeChanged += OobeWindow_SizeChanged; var loader = Helpers.ResourceLoaderInstance.ResourceLoader; @@ -154,8 +137,6 @@ namespace Microsoft.PowerToys.Settings.UI { if (!disposedValue) { - _msgMonitor?.Dispose(); - disposedValue = true; } } From 6174b76a4fe3872c844e42f087e71d6726b54d31 Mon Sep 17 00:00:00 2001 From: "Yaqing Mi (from Dev Box)" Date: Thu, 10 Apr 2025 14:39:56 +0800 Subject: [PATCH 02/14] Add More Elements support for UITestAutomation --- PowerToys.sln | 11 + .../UITestAutomation/Element/ComboBox.cs | 28 +++ src/common/UITestAutomation/Element/Custom.cs | 25 +++ src/common/UITestAutomation/Element/Group.cs | 25 +++ src/common/UITestAutomation/Element/Slider.cs | 110 ++++++++++ .../UITestAutomation/ModuleConfigData.cs | 3 + src/common/UITestAutomation/Program.cs | 170 +++++++++++++++ src/common/UITestAutomation/SessionHelper.cs | 13 ++ .../Hosts.UITests/FindMyMouse.UITests.csproj | 25 +++ .../Hosts.UITests/FindMyMouseSettingTests.cs | 202 ++++++++++++++++++ .../Hosts.UITests/FindMyMouseTests.cs | 179 ++++++++++++++++ ...lease-Test-Checklist-Migration-Progress.md | 26 +++ 12 files changed, 817 insertions(+) create mode 100644 src/common/UITestAutomation/Element/ComboBox.cs create mode 100644 src/common/UITestAutomation/Element/Custom.cs create mode 100644 src/common/UITestAutomation/Element/Group.cs create mode 100644 src/common/UITestAutomation/Element/Slider.cs create mode 100644 src/common/UITestAutomation/Program.cs create mode 100644 src/modules/MouseUtils/Hosts.UITests/FindMyMouse.UITests.csproj create mode 100644 src/modules/MouseUtils/Hosts.UITests/FindMyMouseSettingTests.cs create mode 100644 src/modules/MouseUtils/Hosts.UITests/FindMyMouseTests.cs create mode 100644 src/modules/MouseUtils/Hosts.UITests/Release-Test-Checklist-Migration-Progress.md diff --git a/PowerToys.sln b/PowerToys.sln index 9b911b388b..8f63987bcf 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -706,6 +706,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegistryPreview.FuzzTests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FindMyMouse.UITests", "src\modules\MouseUtils\Hosts.UITests\FindMyMouse.UITests.csproj", "{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -2582,6 +2584,14 @@ Global {64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.Build.0 = Release|x64 {64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x86.ActiveCfg = Release|x64 {64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x86.Build.0 = Release|x64 + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|ARM64.Build.0 = Debug|ARM64 + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|x64.ActiveCfg = Debug|x64 + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|x64.Build.0 = Debug|x64 + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Release|ARM64.ActiveCfg = Release|ARM64 + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Release|ARM64.Build.0 = Release|ARM64 + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Release|x64.ActiveCfg = Release|x64 + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2852,6 +2862,7 @@ Global {4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA} {5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5} {64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2} + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1} = {322566EF-20DC-43A6-B9F8-616AF942579A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} diff --git a/src/common/UITestAutomation/Element/ComboBox.cs b/src/common/UITestAutomation/Element/ComboBox.cs new file mode 100644 index 0000000000..5462c33910 --- /dev/null +++ b/src/common/UITestAutomation/Element/ComboBox.cs @@ -0,0 +1,28 @@ +// 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 Microsoft.PowerToys.UITest +{ + public class ComboBox : Element + { + private static readonly string ExpectedControlType = "ControlType.ComboBox"; + + /// + /// Initializes a new instance of the class. + /// + public ComboBox() + { + this.TargetControlType = ComboBox.ExpectedControlType; + } + + /// + /// Select the item of the ComboBox. + /// + /// The text to select from the list view. + public void Select(string value) + { + this.Find(value).Click(); + } + } +} diff --git a/src/common/UITestAutomation/Element/Custom.cs b/src/common/UITestAutomation/Element/Custom.cs new file mode 100644 index 0000000000..4875d44fa1 --- /dev/null +++ b/src/common/UITestAutomation/Element/Custom.cs @@ -0,0 +1,25 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.PowerToys.UITest +{ + public class Custom : Element + { + private static readonly string ExpectedControlType = "ControlType.Custom"; + + /// + /// Initializes a new instance of the class. + /// + public Custom() + { + this.TargetControlType = Custom.ExpectedControlType; + } + } +} diff --git a/src/common/UITestAutomation/Element/Group.cs b/src/common/UITestAutomation/Element/Group.cs new file mode 100644 index 0000000000..55619a281d --- /dev/null +++ b/src/common/UITestAutomation/Element/Group.cs @@ -0,0 +1,25 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.PowerToys.UITest +{ + public class Group : Element + { + private static readonly string ExpectedControlType = "ControlType.Group"; + + /// + /// Initializes a new instance of the class. + /// + public Group() + { + this.TargetControlType = Group.ExpectedControlType; + } + } +} diff --git a/src/common/UITestAutomation/Element/Slider.cs b/src/common/UITestAutomation/Element/Slider.cs new file mode 100644 index 0000000000..c08fe92250 --- /dev/null +++ b/src/common/UITestAutomation/Element/Slider.cs @@ -0,0 +1,110 @@ +// 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.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium.Appium.Windows; + +namespace Microsoft.PowerToys.UITest +{ + public class Slider : Element + { + private static readonly string ExpectedControlType = "ControlType.Slider"; + + /// + /// Initializes a new instance of the class. + /// + public Slider() + { + this.TargetControlType = Slider.ExpectedControlType; + } + + /// + /// Sets the value of a Slider (WindowsElement) to the specified integer value. + /// Throws an exception if the value is out of the slider's valid range. + /// + /// The target integer value to set + public void SetValue(int targetValue) + { + // Read range and current value + int min = int.Parse(this.GetAttribute("RangeValue.Minimum")); + int max = int.Parse(this.GetAttribute("RangeValue.Maximum")); + int current = int.Parse(this.Text); + + // Use Assert to check if the target value is within the valid range + Assert.IsTrue( + targetValue >= min && targetValue <= max, + $"Target value {targetValue} is out of range (min: {min}, max: {max})."); + + // Compute difference + int diff = targetValue - current; + if (diff == 0) + { + return; + } + + string key = diff > 0 ? OpenQA.Selenium.Keys.Right : OpenQA.Selenium.Keys.Left; + int steps = Math.Abs(diff); + + for (int i = 0; i < steps; i++) + { + this.SendKeys(key); + + // Thread.Sleep(2); + } + + // Final check + int finalValue = int.Parse(this.Text); + Assert.AreEqual( + targetValue, finalValue, $"Slider value mismatch: expected {targetValue}, but got {finalValue}."); + } + + /// + /// Sets the value of a Slider (WindowsElement) to the specified integer value. + /// Throws an exception if the value is out of the slider's valid range. + /// + /// The target integer value to set + public void QuickSetValue(int targetValue) + { + // Read range and current value + int min = int.Parse(this.GetAttribute("RangeValue.Minimum")); + int max = int.Parse(this.GetAttribute("RangeValue.Maximum")); + int current = int.Parse(this.Text); + + // Use Assert to check if the target value is within the valid range + Assert.IsTrue( + targetValue >= min && targetValue <= max, + $"Target value {targetValue} is out of range (min: {min}, max: {max})."); + + // Compute difference + int diff = targetValue - current; + if (diff == 0) + { + return; + } + + string key = diff > 0 ? OpenQA.Selenium.Keys.Right : OpenQA.Selenium.Keys.Left; + int steps = Math.Abs(diff); + + int maxKeysPerSend = 50; + int fullChunks = steps / maxKeysPerSend; + int remainder = steps % maxKeysPerSend; + for (int i = 0; i < fullChunks; i++) + { + SendKeys(new string(key[0], maxKeysPerSend)); + Thread.Sleep(2); + } + + if (remainder > 0) + { + SendKeys(new string(key[0], remainder)); + Thread.Sleep(2); + } + + // Final check + int finalValue = int.Parse(this.Text); + Assert.AreEqual( + targetValue, finalValue, $"Slider value mismatch: expected {targetValue}, but got {finalValue}."); + } + } +} diff --git a/src/common/UITestAutomation/ModuleConfigData.cs b/src/common/UITestAutomation/ModuleConfigData.cs index d8dd1cac5a..ce04c13429 100644 --- a/src/common/UITestAutomation/ModuleConfigData.cs +++ b/src/common/UITestAutomation/ModuleConfigData.cs @@ -29,6 +29,7 @@ namespace Microsoft.PowerToys.UITest PowerToysSettings, FancyZone, Hosts, + Runner, } internal class ModuleConfigData @@ -52,6 +53,7 @@ namespace Microsoft.PowerToys.UITest [PowerToysModule.PowerToysSettings] = "PowerToys Settings", [PowerToysModule.FancyZone] = "FancyZones Layout", [PowerToysModule.Hosts] = "Hosts File Editor", + [PowerToysModule.Runner] = "PowerToys", }; // Exe start path for the module if it exists. @@ -60,6 +62,7 @@ namespace Microsoft.PowerToys.UITest [PowerToysModule.PowerToysSettings] = @"\..\..\..\WinUI3Apps\PowerToys.Settings.exe", [PowerToysModule.FancyZone] = @"\..\..\..\PowerToys.FancyZonesEditor.exe", [PowerToysModule.Hosts] = @"\..\..\..\WinUI3Apps\PowerToys.Hosts.exe", + [PowerToysModule.Runner] = @"\..\..\..\PowerToys.exe", }; } diff --git a/src/common/UITestAutomation/Program.cs b/src/common/UITestAutomation/Program.cs new file mode 100644 index 0000000000..63de68b568 --- /dev/null +++ b/src/common/UITestAutomation/Program.cs @@ -0,0 +1,170 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.PowerToys.UITest +{ + public class Program + { + private readonly UIntPtr ignoreKeyEventFlag = 0x5555; + + [DllImport("user32.dll")] + private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); + + [StructLayout(LayoutKind.Sequential)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")] + internal struct INPUT + { + internal INPUTTYPE type; + internal InputUnion data; + + internal static int Size + { + get { return Marshal.SizeOf(); } + } + } + + [StructLayout(LayoutKind.Explicit)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")] + internal struct InputUnion + { + [FieldOffset(0)] + internal MOUSEINPUT mi; + [FieldOffset(0)] + internal KEYBDINPUT ki; + [FieldOffset(0)] + internal HARDWAREINPUT hi; + } + + [StructLayout(LayoutKind.Sequential)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")] + internal struct MOUSEINPUT + { + internal int dx; + internal int dy; + internal int mouseData; + internal uint dwFlags; + internal uint time; + internal UIntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")] + internal struct KEYBDINPUT + { + internal short wVk; + internal short wScan; + internal uint dwFlags; + internal int time; + internal UIntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")] + internal struct HARDWAREINPUT + { + internal int uMsg; + internal short wParamL; + internal short wParamH; + } + + internal enum INPUTTYPE : uint + { + INPUT_MOUSE = 0, + INPUT_KEYBOARD = 1, + INPUT_HARDWARE = 2, + } + + [Flags] + internal enum KeyEventF + { + KeyDown = 0x0000, + ExtendedKey = 0x0001, + KeyUp = 0x0002, + Unicode = 0x0004, + Scancode = 0x0008, + } + + private void SendSingleKeyboardInput(short keyCode, uint keyStatus) + { + var inputShift = new INPUT + { + type = INPUTTYPE.INPUT_KEYBOARD, + data = new InputUnion + { + ki = new KEYBDINPUT + { + wVk = keyCode, + dwFlags = keyStatus, + + // Any keyevent with the extraInfo set to this value will be ignored by the keyboard hook and sent to the system instead. + dwExtraInfo = ignoreKeyEventFlag, + }, + }, + }; + + INPUT[] inputs = [inputShift]; + + _ = SendInput(1, inputs, INPUT.Size); + } + + public static void SimulateKeyDown(ushort keyCode) + { + SendKey(keyCode, false); + } + + public static void SimulateKeyUp(ushort keyCode) + { + SendKey(keyCode, true); + } + + public static void SimulateKeyPress(ushort keyCode) + { + SendKey(keyCode, false); + SendKey(keyCode, true); + } + + public static void SimulateShortcut(params ushort[] keyCodes) + { + // 1. 先按下所有按键(顺序) + foreach (var key in keyCodes) + { + SimulateKeyDown(key); + } + + // 2. 再松开所有按键(逆序) + for (int i = keyCodes.Length - 1; i >= 0; i--) + { + SimulateKeyUp(keyCodes[i]); + } + } + + public static void SendKey(ushort keyCode, bool keyUp) + { + var inputShift = new INPUT + { + type = INPUTTYPE.INPUT_KEYBOARD, + data = new InputUnion + { + ki = new KEYBDINPUT + { + wVk = (short)keyCode, + dwFlags = (uint)(keyUp ? KeyEventF.KeyUp : 0), + dwExtraInfo = (uint)IntPtr.Zero, + }, + }, + }; + + INPUT[] inputs = [inputShift]; + + _ = SendInput(1, inputs, INPUT.Size); + } + } +} diff --git a/src/common/UITestAutomation/SessionHelper.cs b/src/common/UITestAutomation/SessionHelper.cs index 324f41e5e3..3fa17a8e63 100644 --- a/src/common/UITestAutomation/SessionHelper.cs +++ b/src/common/UITestAutomation/SessionHelper.cs @@ -20,6 +20,8 @@ namespace Microsoft.PowerToys.UITest // Default session path is PowerToys settings dashboard private readonly string sessionPath = ModuleConfigData.Instance.GetModulePath(PowerToysModule.PowerToysSettings); + private readonly string runnerPath = ModuleConfigData.Instance.GetModulePath(PowerToysModule.Runner); + private string? locationPath; private WindowsDriver Root { get; set; } @@ -27,6 +29,7 @@ namespace Microsoft.PowerToys.UITest private WindowsDriver? Driver { get; set; } private Process? appDriver; + private Process? runner; [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "")] public SessionHelper(PowerToysModule scope) @@ -42,6 +45,14 @@ namespace Microsoft.PowerToys.UITest this.appDriver = Process.Start(winAppDriverProcessInfo); + var runnerProcessInfo = new ProcessStartInfo + { + FileName = locationPath + this.runnerPath, + Verb = "runas", + }; + + this.runner = Process.Start(runnerProcessInfo); + var desktopCapabilities = new AppiumOptions(); desktopCapabilities.AddAdditionalCapability("app", "Root"); this.Root = new WindowsDriver(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), desktopCapabilities); @@ -73,6 +84,8 @@ namespace Microsoft.PowerToys.UITest { appDriver?.Kill(); appDriver?.WaitForExit(); // Optional: Wait for the process to exit + runner?.Kill(); + runner?.WaitForExit(); // Optional: Wait for the process to exit } catch (Exception ex) { diff --git a/src/modules/MouseUtils/Hosts.UITests/FindMyMouse.UITests.csproj b/src/modules/MouseUtils/Hosts.UITests/FindMyMouse.UITests.csproj new file mode 100644 index 0000000000..e5ffb998f1 --- /dev/null +++ b/src/modules/MouseUtils/Hosts.UITests/FindMyMouse.UITests.csproj @@ -0,0 +1,25 @@ + + + + + + {4E0AE3A4-2EE0-44D7-A2D0-8769977254A1} + PowerToys.Hosts.UITestss + PowerToys.Hosts.UITestss + false + true + enable + Library + + + false + + + $(SolutionDir)$(Platform)\$(Configuration)\tests\Hosts.UITestss\ + + + + + + + diff --git a/src/modules/MouseUtils/Hosts.UITests/FindMyMouseSettingTests.cs b/src/modules/MouseUtils/Hosts.UITests/FindMyMouseSettingTests.cs new file mode 100644 index 0000000000..1ef92bf830 --- /dev/null +++ b/src/modules/MouseUtils/Hosts.UITests/FindMyMouseSettingTests.cs @@ -0,0 +1,202 @@ +// 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; +using System.Threading.Tasks; +using System.Xml.Linq; +using Microsoft.PowerToys.UITest; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; +using Windows.Devices.Printers; + +namespace FindMyMouse.UITests +{ + [TestClass] + public class FindMyMouseSettingTests : UITestBase + { + /// + /// Test Warning Dialog at startup + /// + /// + /// Validating Warning-Dialog will be shown if 'Show a warning at startup' toggle is On. + /// + /// + /// Validating Warning-Dialog will NOT be shown if 'Show a warning at startup' toggle is Off. + /// + /// + /// Validating click 'Quit' button in Warning-Dialog, the Hosts File Editor window would be closed. + /// + /// + /// Validating click 'Accept' button in Warning-Dialog, the Hosts File Editor window would NOT be closed. + /// + /// + /// + [TestMethod] + public void TestEnable2() + { + this.LaunchFromSetting(showWarning: true); + this.Find("Enable Find My Mouse").Toggle(true); + + // this.Find("Enable Mouse Pointer Crosshairs").Toggle(true); + // this.Find("Activation method").Click(); + string findMyMouseCombox = "Activation method"; + var foundElements = this.FindAll(findMyMouseCombox); + bool comboBoxFound = false; + foreach (var element in foundElements) + { + string controlType = element.ControlType; + if (controlType == "ControlType.ComboBox") + { + element.Click(); + comboBoxFound = true; + } + } + + Assert.IsTrue(comboBoxFound, "ComboBox is not found in the setting page."); + + // this.Find("Custom shortcut").Click(); + this.Find("Press Left Control twice").Click(); + + bool isfind = FindGroup("Appearance & behavior"); + + Assert.IsTrue(isfind, "Find My Mouse group is not found in the setting page."); + + Program.SimulateKeyPress(0xA2); + Task.Delay(100).Wait(); + Program.SimulateKeyPress(0xA2); + + Task.Delay(10000).Wait(); + } + + [TestMethod] + public void TestEnable3() + { + this.LaunchFromSetting(showWarning: true); + this.Find("Enable Find My Mouse").Toggle(true); + + // this.Find("Enable Mouse Pointer Crosshairs").Toggle(true); + // this.Find("Activation method").Click(); + string findMyMouseCombox = "Activation method"; + var foundElements = this.FindAll(findMyMouseCombox); + if (foundElements.Count != 0) + { + this.Find(findMyMouseCombox).Click(); + var myMouseCombox = this.Find(findMyMouseCombox); + myMouseCombox.Find("Press Left Control twice").Click(); + } + else + { + Assert.IsTrue(false, "ComboBox is not found in the setting page."); + } + + Task.Delay(10000).Wait(); + } + + [TestMethod] + public void TestEnableFz() + { + this.LaunchFromSetting_FZ(showWarning: true); + this.Find("Enable FancyZones").Toggle(true); + + // Session.KeyboardAction(Keys.Shift + Keys.Home + "`"); + Task.Delay(10000).Wait(); + + // Session.HotkeysFz(); + Program.SimulateKeyPress(0x5B); + Task.Delay(10000).Wait(); + Program.SimulateKeyPress(0x5B); + Task.Delay(10000).Wait(); + + Program.SimulateShortcut(0x5B, 0x10, 0x09); + Task.Delay(10000).Wait(); + } + + private bool FindGroup(string groupName) + { + try + { + var foundElements = this.FindAll(groupName); + foreach (var element in foundElements) + { + string className = element.ClassName; + string name = element.Name; + string text = element.Text; + string helptext = element.HelpText; + string controlType = element.ControlType; + } + + if (foundElements.Count == 0) + { + return false; + } + } + catch (Exception ex) + { + // Validate if group is not found by checking exception.Message + return ex.Message.Contains("No element found"); + } + + return true; + } + + private bool IsHostsFileEditorClosed() + { + try + { + this.Session.FindAll("Hosts File Editor"); + } + catch (Exception ex) + { + // Validate if editor window closed by checking exception.Message + return ex.Message.Contains("Currently selected window has been closed"); + } + + return false; + } + + private void LaunchFromSetting(bool showWarning = false, bool launchAsAdmin = false) + { + // Goto Hosts File Editor setting page + if (this.FindAll("Hosts File Editor").Count == 0) + { + // Expand Advanced list-group if needed + this.Find("Input / Output").Click(); + } + + this.Find("Mouse utilities").Click(); + + // this.Find("Enable Hosts File Editor").Toggle(true); + // this.Find("Launch as administrator").Toggle(launchAsAdmin); + // this.Find("Show a warning at startup").Toggle(showWarning); + + // launch Hosts File Editor + + // Task.Delay(500).Wait(); + + // this.Session.Attach(PowerToysModule.Hosts); + } + + private void LaunchFromSetting_FZ(bool showWarning = false, bool launchAsAdmin = false) + { + // Goto Hosts File Editor setting page + if (this.FindAll("FancyZones").Count == 0) + { + // Expand Advanced list-group if needed + this.Find("Windowing & Layouts").Click(); + } + + this.Find("FancyZones").Click(); + + // this.Find("Enable Hosts File Editor").Toggle(true); + // this.Find("Launch as administrator").Toggle(launchAsAdmin); + // this.Find("Show a warning at startup").Toggle(showWarning); + + // launch Hosts File Editor + + // Task.Delay(500).Wait(); + + // this.Session.Attach(PowerToysModule.Hosts); + } + } +} diff --git a/src/modules/MouseUtils/Hosts.UITests/FindMyMouseTests.cs b/src/modules/MouseUtils/Hosts.UITests/FindMyMouseTests.cs new file mode 100644 index 0000000000..fe92fc94e6 --- /dev/null +++ b/src/modules/MouseUtils/Hosts.UITests/FindMyMouseTests.cs @@ -0,0 +1,179 @@ +// 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; +using System.Threading.Tasks; +using System.Xml.Linq; +using Microsoft.PowerToys.UITest; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Windows.Devices.Printers; + +namespace FindMyMouse.UITests +{ + [TestClass] + public class FindMyMouseTests : UITestBase + { + /// + /// Test Warning Dialog at startup + /// + /// + /// Validating Warning-Dialog will be shown if 'Show a warning at startup' toggle is On. + /// + /// + /// Validating Warning-Dialog will NOT be shown if 'Show a warning at startup' toggle is Off. + /// + /// + /// Validating click 'Quit' button in Warning-Dialog, the Hosts File Editor window would be closed. + /// + /// + /// Validating click 'Accept' button in Warning-Dialog, the Hosts File Editor window would NOT be closed. + /// + /// + /// + [TestMethod] + public void TestEnable2() + { + LaunchFromSetting(); + var foundCustom = this.Find("Find My Mouse"); + if (foundCustom != null) + { + foundCustom.Find("Enable Find My Mouse").Toggle(true); + + // foundCustom.Find("Enable Find My Mouse").Toggle(false); + var groupActivation = foundCustom.Find("Activation method"); + if (groupActivation != null) + { + groupActivation.Click(); + groupActivation.Click(); + } + else + { + Assert.Fail("Activation method group not found."); + } + + var groupAppearanceBehavior = foundCustom.Find("Appearance & behavior"); + if (groupAppearanceBehavior != null) + { + // groupAppearanceBehavior.Click(); + if (foundCustom.FindAll("Overlay opacity (%)").Count == 0) + { + groupAppearanceBehavior.Click(); + } + + //// Set the overlay opacity to 100% + // var overlayOpacitySlider = foundCustom.Find("Overlay opacity (%)"); + // Assert.IsNotNull(overlayOpacitySlider); + // overlayOpacitySlider.QuickSetValue(100); + // Assert.AreEqual("100", overlayOpacitySlider.Text); + + //// Changge the edit value + // var spotlightRadiusEdit = foundCustom.Find("Spotlight radius (px) Minimum5"); + // Assert.IsNotNull(spotlightRadiusEdit); + // Task.Delay(10000).Wait(); + // spotlightRadiusEdit.SetText("55"); + // Assert.AreEqual("55", spotlightRadiusEdit.Text); + + // Set the BackGroud color + var backgroundColor = foundCustom.Find("Background color"); + Assert.IsNotNull(backgroundColor); + + // backgroundColor.Click(); + + // var button = backgroundColor.Find