Refactor the API code structure

This commit is contained in:
Zhaopeng Wang (from Dev Box)
2025-02-07 17:00:45 +08:00
parent 7f214160f2
commit d51305d7cb
7 changed files with 272 additions and 79 deletions

View File

@@ -19,6 +19,16 @@ namespace Microsoft.UITests.API
{
public class APPManager
{
private static readonly Lazy<APPManager> MInstance = new Lazy<APPManager>(() => 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<WindowsElement>? 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<WindowsElement>? 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<WinDriver> mWindowListTemp = new Stack<WinDriver>();
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<WindowsElement>(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<WindowsElement>(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<WindowsElement>(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<WindowsElement>? GetCurrentWindow()
public WindowsDriverWrapper? GetCurrentWindow()
{
return CurrentDriver.Session;
}
public WindowsDriver<WindowsElement>? GetWindowInList(string appName)
public WindowsDriverWrapper? GetWindowInList(string appName)
{
while (mWindowList.Count > 0)
{

View File

@@ -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<WindowsElement>? session = APPManager.Instance.GetCurrentWindow();
var element = WindowsElement;
Actions actions = new Actions(session);
actions.MoveToElement(element);
actions.Click();
actions.Build().Perform();
}
public T? FindElementByName<T>(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();
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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<WindowsElement>
#pragma warning restore SA1649 // File name should match first type name
{
public WindowsDriverWrapper(Uri remoteAddress, AppiumOptions appiumOptions)
: base(remoteAddress, appiumOptions)
{
}
public T? FindElementByName<T>(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;
}
}
}

View File

@@ -27,7 +27,31 @@ namespace Microsoft.UITests.API
Hosts,
}
public struct ModuleConfigData(string moduleName, string windowName)
public class ModuleConfigData
{
private static readonly Lazy<ModuleConfigData> MInstance = new Lazy<ModuleConfigData>(() => new ModuleConfigData());
public static ModuleConfigData Instance
{
get
{
return MInstance.Value;
}
}
public Dictionary<PowerToysModuleWindow, ModuleWindowData> ModuleWindowName { get; private set; }
private ModuleConfigData()
{
ModuleWindowName = new Dictionary<PowerToysModuleWindow, ModuleWindowData>();
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;

View File

@@ -24,21 +24,10 @@ namespace Microsoft.UITests.API
{
protected const string PowerToysPath = @"\..\..\..\WinUI3Apps\PowerToys.Settings.exe";
public Dictionary<PowerToysModuleWindow, ModuleConfigData> ModuleConfig { get; private set; }
public APPManager APPManager { get; private set; }
private static Process? appDriver;
public UITestAPI()
{
ModuleConfig = new Dictionary<PowerToysModuleWindow, ModuleConfigData>();
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 = "<Pending>")]
@@ -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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement> GetElements(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None)
{
WindowsDriver<WindowsElement>? 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<WindowsElement>? 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<Element>(elementName);
Assert.IsNotNull(item, "ElementName " + elementName + " not found");
}
}
public void Click_Element(string elementName, PowerToysModuleWindow module = PowerToysModuleWindow.None)
{
WindowsDriver<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? 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<WindowsElement>? session = GetSession(module);
WindowsDriverWrapper? session = GetSession(module);
var layout = GetLayout(layoutName, module);
Actions actions = new Actions(session);
actions.MoveToElement(layout);

View File

@@ -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<string> windowTitles = new List<string>();
_ = 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);