diff --git a/src/UITestAPI/src/APPManager.cs b/src/UITestAPI/src/APPManager.cs index 7801ba06a0..934a39f20b 100644 --- a/src/UITestAPI/src/APPManager.cs +++ b/src/UITestAPI/src/APPManager.cs @@ -19,6 +19,16 @@ namespace Microsoft.UITests.API { public class APPManager { + private static readonly Lazy MInstance = new Lazy(() => new APPManager()); + + public static APPManager Instance + { + get + { + return MInstance.Value; + } + } + [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); @@ -33,7 +43,7 @@ namespace Microsoft.UITests.API public struct WinDriver { - public WindowsDriver? Session { get; set; } + public WindowsDriverWrapper Session { get; set; } public string AppName; public string WindowName; @@ -41,7 +51,7 @@ namespace Microsoft.UITests.API protected const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723"; - public WindowsDriver? Root { get; private set; } + public WindowsDriverWrapper Root { get; private set; } public WinDriver CurrentDriver { get; private set; } @@ -49,7 +59,7 @@ namespace Microsoft.UITests.API private Stack mWindowListTemp = new Stack(); - public APPManager() + private APPManager() { if (mWindowList == null) { @@ -63,7 +73,7 @@ namespace Microsoft.UITests.API var desktopCapabilities = new AppiumOptions(); desktopCapabilities.AddAdditionalCapability("app", "Root"); - Root = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), desktopCapabilities); + Root = new WindowsDriverWrapper(new Uri(WindowsApplicationDriverUrl), desktopCapabilities); } // Create a new application and take control of it @@ -71,7 +81,7 @@ namespace Microsoft.UITests.API { AppiumOptions opts = new AppiumOptions(); opts.AddAdditionalCapability("app", appPath); - var session = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), opts); + var session = new WindowsDriverWrapper(new Uri(WindowsApplicationDriverUrl), opts); WinDriver winDriver = default(WinDriver); winDriver.Session = session; winDriver.AppName = appName; @@ -102,7 +112,7 @@ namespace Microsoft.UITests.API var appCapabilities = new AppiumOptions(); appCapabilities.AddAdditionalCapability("appTopLevelWindow", hexWindowHandle); appCapabilities.AddAdditionalCapability("deviceName", "WindowsPC"); - var appSession = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), appCapabilities); + var appSession = new WindowsDriverWrapper(new Uri(WindowsApplicationDriverUrl), appCapabilities); WinDriver winDriver = default(WinDriver); winDriver.Session = appSession; winDriver.AppName = appName; @@ -192,12 +202,12 @@ namespace Microsoft.UITests.API Assert.IsNotNull(null, "appName not found"); } - public WindowsDriver? GetCurrentWindow() + public WindowsDriverWrapper? GetCurrentWindow() { return CurrentDriver.Session; } - public WindowsDriver? GetWindowInList(string appName) + public WindowsDriverWrapper? GetWindowInList(string appName) { while (mWindowList.Count > 0) { diff --git a/src/UITestAPI/src/Element/Element.cs b/src/UITestAPI/src/Element/Element.cs new file mode 100644 index 0000000000..72fdd55dda --- /dev/null +++ b/src/UITestAPI/src/Element/Element.cs @@ -0,0 +1,123 @@ +// 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; +using OpenQA.Selenium.Appium.Windows; +using OpenQA.Selenium.Interactions; +using OpenQA.Selenium.Remote; +using OpenQA.Selenium.Support.Events; +using static Microsoft.UITests.API.APPManager; + +namespace Microsoft.UITests.API +{ + public class Element + { + public WindowsElement? WindowsElement { get; set; } + + public Element() + { + WindowsElement = null; + } + + public void SetWindowsElement(WindowsElement windowsElement) + { + WindowsElement = windowsElement; + } + + public string GetName() + { + if (WindowsElement == null) + { + Assert.IsNotNull(null); + return " "; + } + + return WindowsElement.GetAttribute("Name"); + } + + public string GetText() + { + if (WindowsElement == null) + { + Assert.IsNotNull(null); + return " "; + } + + return WindowsElement.GetAttribute("Value"); + } + + public string GetAutomationId() + { + if (WindowsElement == null) + { + Assert.IsNotNull(null); + return " "; + } + + return WindowsElement.GetAttribute("AutomationId"); + } + + public string GetClassName() + { + if (WindowsElement == null) + { + Assert.IsNotNull(null); + return " "; + } + + return WindowsElement.GetAttribute("ClassName"); + } + + public bool IsEnable() + { + if (WindowsElement == null) + { + Assert.IsNotNull(null); + } + + return WindowsElement?.GetAttribute("IsEnabled") == "True" ? true : false; + } + + public bool IsSelected() + { + if (WindowsElement == null) + { + Assert.IsNotNull(null); + } + + return WindowsElement?.GetAttribute("IsSelected") == "True" ? true : false; + } + + public void Click() + { + WindowsDriver? session = APPManager.Instance.GetCurrentWindow(); + var element = WindowsElement; + Actions actions = new Actions(session); + actions.MoveToElement(element); + actions.Click(); + actions.Build().Perform(); + } + + public T? FindElementByName(string name) + where T : Element, new() + { + var item = WindowsElement?.FindElementByName(name); + Assert.IsNotNull(item, "Can`t find this element"); + T element = new T(); + return element; + } + + public Screenshot? GetScreenShot() + { + if (WindowsElement == null) + { + Assert.IsNotNull(null); + return null; + } + + return WindowsElement?.GetScreenshot(); + } + } +} diff --git a/src/UITestAPI/src/Element/Window.cs b/src/UITestAPI/src/Element/Window.cs new file mode 100644 index 0000000000..b447111542 --- /dev/null +++ b/src/UITestAPI/src/Element/Window.cs @@ -0,0 +1,32 @@ +// 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; +using OpenQA.Selenium.Appium.Windows; +using OpenQA.Selenium.Interactions; +using OpenQA.Selenium.Remote; +using OpenQA.Selenium.Support.Events; + +namespace Microsoft.UITests.API +{ + public class Window : Element + { + public Window() + : base() + { + } + + public string GetHelpText() + { + if (WindowsElement == null) + { + Assert.IsNotNull(null); + return " "; + } + + return WindowsElement.GetAttribute("HelpText"); + } + } +} diff --git a/src/UITestAPI/src/Element/WindowsDriverWrapper.cs b/src/UITestAPI/src/Element/WindowsDriverWrapper.cs new file mode 100644 index 0000000000..b168e86831 --- /dev/null +++ b/src/UITestAPI/src/Element/WindowsDriverWrapper.cs @@ -0,0 +1,35 @@ +// 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; +using OpenQA.Selenium.Appium; +using OpenQA.Selenium.Appium.Android; +using OpenQA.Selenium.Appium.Enums; +using OpenQA.Selenium.Appium.Interfaces; +using OpenQA.Selenium.Appium.Service; +using OpenQA.Selenium.Appium.Windows; +using OpenQA.Selenium.Remote; + +namespace Microsoft.UITests.API +{ +#pragma warning disable SA1649 // File name should match first type name + public class WindowsDriverWrapper : WindowsDriver +#pragma warning restore SA1649 // File name should match first type name + { + public WindowsDriverWrapper(Uri remoteAddress, AppiumOptions appiumOptions) + : base(remoteAddress, appiumOptions) + { + } + + public T? FindElementByName(string name) + where T : Element, new() + { + var item = this.FindElementByName(name); + Assert.IsNotNull(item, "Can`t find this element"); + T element = new T(); + return element; + } + } +} diff --git a/src/UITestAPI/src/ModuleConfigData.cs b/src/UITestAPI/src/ModuleConfigData.cs index 49cf61bc19..18e33cdeea 100644 --- a/src/UITestAPI/src/ModuleConfigData.cs +++ b/src/UITestAPI/src/ModuleConfigData.cs @@ -27,7 +27,31 @@ namespace Microsoft.UITests.API Hosts, } - public struct ModuleConfigData(string moduleName, string windowName) + public class ModuleConfigData + { + private static readonly Lazy MInstance = new Lazy(() => new ModuleConfigData()); + + public static ModuleConfigData Instance + { + get + { + return MInstance.Value; + } + } + + public Dictionary ModuleWindowName { get; private set; } + + private ModuleConfigData() + { + ModuleWindowName = new Dictionary(); + ModuleWindowName[PowerToysModuleWindow.Fancyzone] = new ModuleWindowData("Fancyzone", "FancyZones Layout"); + ModuleWindowName[PowerToysModuleWindow.KeyboardManagerKeys] = new ModuleWindowData("KeyboardManagerKeys", "Remap keys"); + ModuleWindowName[PowerToysModuleWindow.KeyboardManagerShortcuts] = new ModuleWindowData("KeyboardManagerShortcuts", "Remap shortcuts"); + ModuleWindowName[PowerToysModuleWindow.Hosts] = new ModuleWindowData("Hosts", "Hosts File Editor"); + } + } + + public struct ModuleWindowData(string moduleName, string windowName) { public string ModuleName = moduleName; public string WindowName = windowName; diff --git a/src/UITestAPI/src/UITestAPI.cs b/src/UITestAPI/src/UITestAPI.cs index 94527f113e..e12f8c5c84 100644 --- a/src/UITestAPI/src/UITestAPI.cs +++ b/src/UITestAPI/src/UITestAPI.cs @@ -24,21 +24,10 @@ namespace Microsoft.UITests.API { protected const string PowerToysPath = @"\..\..\..\WinUI3Apps\PowerToys.Settings.exe"; - public Dictionary ModuleConfig { get; private set; } - - public APPManager APPManager { get; private set; } - private static Process? appDriver; public UITestAPI() { - ModuleConfig = new Dictionary(); - ModuleConfig[PowerToysModuleWindow.Fancyzone] = new ModuleConfigData("Fancyzone", "FancyZones Layout"); - ModuleConfig[PowerToysModuleWindow.KeyboardManagerKeys] = new ModuleConfigData("KeyboardManagerKeys", "Remap keys"); - ModuleConfig[PowerToysModuleWindow.KeyboardManagerShortcuts] = new ModuleConfigData("KeyboardManagerShortcuts", "Remap shortcuts"); - ModuleConfig[PowerToysModuleWindow.Hosts] = new ModuleConfigData("Hosts", "Hosts File Editor"); - - APPManager = new APPManager(); } [UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "")] @@ -49,9 +38,9 @@ namespace Microsoft.UITests.API // Launch Exe string? path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); path += PowerToysPath; - APPManager.StartExe("PowerToys", "PowerToys Settings", path); + APPManager.Instance.StartExe("PowerToys", "PowerToys Settings", path); - var session = APPManager.GetCurrentWindow(); + var session = APPManager.Instance.GetCurrentWindow(); Assert.IsNotNull(session, "Session not initialized"); // Set implicit timeout to make element search to retry every 500 ms @@ -60,7 +49,7 @@ namespace Microsoft.UITests.API public void Close(TestContext testContext) { - var session = APPManager.GetCurrentWindow(); + var session = APPManager.Instance.GetCurrentWindow(); // Close the session if (session != null) @@ -83,47 +72,47 @@ namespace Microsoft.UITests.API // Create a new application and take control of it public void StartExe(string appName, string windowName, string appPath) { - APPManager.StartExe(appName, windowName, appPath); + APPManager.Instance.StartExe(appName, windowName, appPath); } // Take control of an application that already exists public void LaunchModuleWithWindowName(PowerToysModuleWindow module) { - APPManager.LaunchModuleWithWindowName(ModuleConfig[module].ModuleName, ModuleConfig[module].WindowName); + APPManager.Instance.LaunchModuleWithWindowName(ModuleConfigData.Instance.ModuleWindowName[module].ModuleName, ModuleConfigData.Instance.ModuleWindowName[module].WindowName); } // Use the name to switch the current driver public void SwitchModule(PowerToysModuleWindow module) { - APPManager.SwitchApp(ModuleConfig[module].ModuleName); + APPManager.Instance.SwitchApp(ModuleConfigData.Instance.ModuleWindowName[module].ModuleName); } public void CloseModule(PowerToysModuleWindow module) { - APPManager.CloseApp(ModuleConfig[module].ModuleName); + APPManager.Instance.CloseApp(ModuleConfigData.Instance.ModuleWindowName[module].ModuleName); } - public WindowsDriver? GetWindowInList(PowerToysModuleWindow module) + public WindowsDriverWrapper? GetWindowInList(PowerToysModuleWindow module) { - return APPManager.GetWindowInList(ModuleConfig[module].ModuleName); + return APPManager.Instance.GetWindowInList(ModuleConfigData.Instance.ModuleWindowName[module].ModuleName); } - public WindowsDriver? GetSession(PowerToysModuleWindow module = PowerToysModuleWindow.None) + public WindowsDriverWrapper? GetSession(PowerToysModuleWindow module = PowerToysModuleWindow.None) { if (module == PowerToysModuleWindow.None) { - return APPManager.GetCurrentWindow(); + return APPManager.Instance.GetCurrentWindow(); } else { - return APPManager.GetWindowInList(ModuleConfig[module].ModuleName); + return APPManager.Instance.GetWindowInList(ModuleConfigData.Instance.ModuleWindowName[module].ModuleName); } } // ===================================Control API================================================ private WindowsElement? GetElement(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var item = session?.FindElementByName(elementName); Assert.IsNotNull(item, "ElementName " + elementName + " not found"); return item; @@ -131,7 +120,7 @@ namespace Microsoft.UITests.API private ReadOnlyCollection GetElements(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var listItem = session?.FindElementsByName(elementName); Assert.IsNotNull(listItem, "ElementName " + elementName + " not found"); return listItem; @@ -139,16 +128,27 @@ namespace Microsoft.UITests.API public WindowsElement? NewOpenContextMenu(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); RightClick_Element(elementName); var menu = session?.FindElementByClassName("ContextMenu"); Assert.IsNotNull(menu, "Context menu not found"); return menu; } + public void TestCode(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None) + { + WindowsDriverWrapper? session = GetSession(module); + if (session != null) + { + Assert.IsNotNull(session, "testSession is null"); + Element? item = session.FindElementByName(elementName); + Assert.IsNotNull(item, "ElementName " + elementName + " not found"); + } + } + public void Click_Element(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var element = GetElement(elementName); Actions actions = new Actions(session); actions.MoveToElement(element); @@ -158,7 +158,7 @@ namespace Microsoft.UITests.API public void Click_Elements(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var elements = GetElements(elementName); Actions actions = new Actions(session); foreach (var element in elements) @@ -173,7 +173,7 @@ namespace Microsoft.UITests.API public void Click_Element(string elementName, string helpText, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var elements = GetElements(elementName); Actions actions = new Actions(session); bool buttonClicked = false; @@ -195,7 +195,7 @@ namespace Microsoft.UITests.API public void Enable_Module_from_Dashboard(string moduleName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var elements = GetElements("Enable module"); Actions actions = new Actions(session); bool buttonFound = false; @@ -221,7 +221,7 @@ namespace Microsoft.UITests.API public void Disable_Module_from_Dashboard(string moduleName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var elements = GetElements("Enable module"); Actions actions = new Actions(session); bool buttonFound = false; @@ -247,7 +247,7 @@ namespace Microsoft.UITests.API public void RightClick_Element(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var element = GetElement(elementName); Actions actions = new Actions(session); actions.MoveToElement(element); @@ -258,7 +258,7 @@ namespace Microsoft.UITests.API private WindowsElement? GetLayout(string layoutName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var listItem = session?.FindElementByName(layoutName); Assert.IsNotNull(listItem, "Layout " + layoutName + " not found"); return listItem; @@ -266,7 +266,7 @@ namespace Microsoft.UITests.API public WindowsElement? OpenContextMenu(string layoutName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); RightClick_Layout(layoutName); var menu = session?.FindElementByClassName("ContextMenu"); Assert.IsNotNull(menu, "Context menu not found"); @@ -275,7 +275,7 @@ namespace Microsoft.UITests.API public void Click_CreateNewLayout(PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var button = session?.FindElementByAccessibilityId("NewLayoutButton"); Assert.IsNotNull(button, "Create new layout button not found"); button?.Click(); @@ -291,7 +291,7 @@ namespace Microsoft.UITests.API public void RightClick_Layout(string layoutName, PowerToysModuleWindow module = PowerToysModuleWindow.None) { - WindowsDriver? session = GetSession(module); + WindowsDriverWrapper? session = GetSession(module); var layout = GetLayout(layoutName, module); Actions actions = new Actions(session); actions.MoveToElement(layout); diff --git a/src/modules/fancyzones/UITests-FancyZones/RunFancyZonesTest.cs b/src/modules/fancyzones/UITests-FancyZones/RunFancyZonesTest.cs index 0651dfde60..01eb6e0c64 100644 --- a/src/modules/fancyzones/UITests-FancyZones/RunFancyZonesTest.cs +++ b/src/modules/fancyzones/UITests-FancyZones/RunFancyZonesTest.cs @@ -48,44 +48,13 @@ namespace UITests_FancyZones _context = null; } - [DllImport("user32.dll", SetLastError = true)] - private static extern int EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); - - [DllImport("user32.dll", SetLastError = true)] - private static extern bool IsWindowVisible(IntPtr hWnd); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); - - private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); - [TestMethod] public void RunFancyZones() { - List windowTitles = new List(); - _ = EnumWindows( - (hWnd, lParam) => - { - if (IsWindowVisible(hWnd)) - { - StringBuilder windowText = new StringBuilder(256); - _ = GetWindowText(hWnd, windowText, windowText.Capacity); - if (windowText.Length > 0) - { - windowTitles.Add(windowText.ToString()); - } - } - - return true; - }, - IntPtr.Zero); - - foreach (string title in windowTitles) - { - Console.WriteLine(title); - } - Assert.IsNotNull(mUITestAPI); + Thread.Sleep(2000); + mUITestAPI.TestCode("Launch layout editor"); + Thread.Sleep(2000); mUITestAPI.Click_Element("Launch layout editor"); Thread.Sleep(4000); mUITestAPI.LaunchModuleWithWindowName(PowerToysModuleWindow.Fancyzone);