UITestAutomation Framework (#37461)

* Add UITestAutomation framework

* add code comments

* Optimized code format

* Optimized code format

* Update commons and add keyboard manager ui test project

* Optimized code format

* test scope and fix fancyzone exe path

* Add readme

* Optimize helper functions and UI test method

* Fix spelling errors and restore module UI tests

* Restore Indent

* Update NOTICE.md

* Update comments to Session and Elements

* Update comments for Button and Window

* delete unnecessary code

* change FindElementByName to FindElmenet

* Update comments for ModuleConfigData

* Update readme and comments

* Remove extra comments

* change public property

* Optimize code readability

* add default Attach Function

* change attach function name

* Update comments to XML format

* Hide by internal functions

* Update readme

* Refine the framework

* Fix process start position and update readme

* Remove Enum PowerToysModuleWindow

* Update attach comments

* Update ModuleConfigData comments

---------

Co-authored-by: Zhaopeng Wang (from Dev Box) <zhaopengwang@microsoft.com>
Co-authored-by: Xiaofeng Wang (from Dev Box) <xiaofengwang@microsoft.com>
Co-authored-by: urnotdfs <709586527@qq.com>
This commit is contained in:
dreamstart
2025-02-20 13:25:20 +08:00
committed by GitHub
parent a1a02889d5
commit 9453e38881
12 changed files with 889 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
// 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.PowerToys.UITest
{
/// <summary>
/// Represents a button in the UI test environment.
/// </summary>
public class Button : Element
{
}
}

View File

@@ -0,0 +1,69 @@
// 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 static OpenQA.Selenium.By;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// This class represents a By selector.
/// </summary>
public class By
{
private readonly OpenQA.Selenium.By by;
private By(OpenQA.Selenium.By by)
{
this.by = by;
}
/// <summary>
/// Creates a By object using the name attribute.
/// </summary>
/// <param name="name">The name attribute to search for.</param>
/// <returns>A By object.</returns>
public static By Name(string name) => new By(OpenQA.Selenium.By.Name(name));
/// <summary>
/// Creates a By object using the ID attribute.
/// </summary>
/// <param name="id">The ID attribute to search for.</param>
/// <returns>A By object.</returns>
public static By Id(string id) => new By(OpenQA.Selenium.By.Id(id));
/// <summary>
/// Creates a By object using the XPath expression.
/// </summary>
/// <param name="xpath">The XPath expression to search for.</param>
/// <returns>A By object.</returns>
public static By XPath(string xpath) => new By(OpenQA.Selenium.By.XPath(xpath));
/// <summary>
/// Creates a By object using the CSS selector.
/// </summary>
/// <param name="cssSelector">The CSS selector to search for.</param>
/// <returns>A By object.</returns>
public static By CssSelector(string cssSelector) => new By(OpenQA.Selenium.By.CssSelector(cssSelector));
/// <summary>
/// Creates a By object using the link text.
/// </summary>
/// <param name="linkText">The link text to search for.</param>
/// <returns>A By object.</returns>
public static By LinkText(string linkText) => new By(OpenQA.Selenium.By.LinkText(linkText));
/// <summary>
/// Creates a By object using the tag name.
/// </summary>
/// <param name="tagName">The tag name to search for.</param>
/// <returns>A By object.</returns>
public static By TagName(string tagName) => new By(OpenQA.Selenium.By.TagName(tagName));
/// <summary>
/// Converts the By object to an OpenQA.Selenium.By object.
/// </summary>
/// <returns>An OpenQA.Selenium.By object.</returns>
internal OpenQA.Selenium.By ToSeleniumBy() => by;
}
}

View File

@@ -0,0 +1,185 @@
// 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.ObjectModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.Events;
using static Microsoft.PowerToys.UITest.UITestBase;
[assembly: InternalsVisibleTo("Session")]
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Represents a basic UI element in the application.
/// </summary>
public class Element
{
private WindowsElement? windowsElement;
private WindowsDriver<WindowsElement>? driver;
internal void SetWindowsElement(WindowsElement windowsElement) => this.windowsElement = windowsElement;
internal void SetSession(WindowsDriver<WindowsElement> driver) => this.driver = driver;
/// <summary>
/// Gets the name of the UI element.
/// </summary>
public string Name
{
get { return GetAttribute("Name"); }
}
/// <summary>
/// Gets the text of the UI element.
/// </summary>
public string Text
{
get { return GetAttribute("Value"); }
}
/// <summary>
/// Gets the AutomationID of the UI element.
/// </summary>
public string AutomationId
{
get { return GetAttribute("AutomationId"); }
}
/// <summary>
/// Gets the class name of the UI element.
/// </summary>
public string ClassName
{
get { return GetAttribute("ClassName"); }
}
/// <summary>
/// Gets the help text of the UI element.
/// </summary>
public string HelpText
{
get { return GetAttribute("HelpText"); }
}
/// <summary>
/// Gets the control type of the UI element.
/// </summary>
public string ControlType
{
get { return GetAttribute("ControlType"); }
}
/// <summary>
/// Checks if the UI element is enabled.
/// </summary>
/// <returns>True if the element is enabled; otherwise, false.</returns>
public bool IsEnabled() => GetAttribute("IsEnabled") == "True";
/// <summary>
/// Checks if the UI element is selected.
/// </summary>
/// <returns>True if the element is selected; otherwise, false.</returns>
public bool IsSelected() => GetAttribute("IsSelected") == "True";
/// <summary>
/// Click the UI element.
/// </summary>
/// <param name="rightClick">If true, performs a right-click; otherwise, performs a left-click.</param>
public void Click(bool rightClick = false)
{
PerformAction(actions =>
{
if (rightClick)
{
actions.ContextClick();
}
else
{
actions.Click();
}
});
}
/// <summary>
/// Gets the attribute value of the UI element.
/// </summary>
/// <param name="attributeName">The name of the attribute to get.</param>
/// <returns>The value of the attribute.</returns>
public string GetAttribute(string attributeName)
{
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method GetAttribute with parameter: attributeName = {attributeName}");
var attributeValue = this.windowsElement.GetAttribute(attributeName);
Assert.IsNotNull(attributeValue, $"Attribute '{attributeName}' is null.");
return attributeValue;
}
/// <summary>
/// Finds an element by the selector.
/// </summary>
/// <typeparam name="T">The class type of the element to find.</typeparam>
/// <param name="by">The selector to use for finding the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>The found element.</returns>
public T Find<T>(By by, int timeoutMS = 3000)
where T : Element, new()
{
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
var foundElement = FindElementHelper.Find<T, AppiumWebElement>(
() =>
{
var element = this.windowsElement.FindElement(by.ToSeleniumBy());
Assert.IsNotNull(element, $"Element not found using selector: {by}");
return element;
},
this.driver,
timeoutMS);
return foundElement;
}
/// <summary>
/// Finds all elements by the selector.
/// </summary>
/// <typeparam name="T">The class type of the elements to find.</typeparam>
/// <param name="by">The selector to use for finding the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds.</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<T>? FindAll<T>(By by, int timeoutMS = 3000)
where T : Element, new()
{
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method FindAll<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
var foundElements = FindElementHelper.FindAll<T, AppiumWebElement>(
() =>
{
var elements = this.windowsElement.FindElements(by.ToSeleniumBy());
Assert.IsTrue(elements.Count > 0, $"Elements not found using selector: {by}");
return elements;
},
this.driver,
timeoutMS);
return foundElements;
}
/// <summary>
/// Simulates a manual operation on the element.
/// </summary>
private void PerformAction(Action<Actions> action)
{
var element = this.windowsElement;
Actions actions = new Actions(this.driver);
actions.MoveToElement(element);
action(actions);
actions.Build().Perform();
}
}
}

View File

@@ -0,0 +1,60 @@
// 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.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
[assembly: InternalsVisibleTo("Element")]
[assembly: InternalsVisibleTo("Session")]
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Helper class for finding elements.
/// </summary>
internal static class FindElementHelper
{
public static T Find<T, TW>(Func<TW> findElementFunc, WindowsDriver<WindowsElement>? driver, int timeoutMS)
where T : Element, new()
{
var item = findElementFunc() as WindowsElement;
return NewElement<T>(item, driver, timeoutMS);
}
public static ReadOnlyCollection<T>? FindAll<T, TW>(Func<ReadOnlyCollection<TW>> findElementsFunc, WindowsDriver<WindowsElement>? driver, int timeoutMS)
where T : Element, new()
{
var items = findElementsFunc();
var res = items.Select(item =>
{
var element = item as WindowsElement;
return NewElement<T>(element, driver, timeoutMS);
}).ToList();
return new ReadOnlyCollection<T>(res);
}
public static T NewElement<T>(WindowsElement? element, WindowsDriver<WindowsElement>? driver, int timeoutMS)
where T : Element, new()
{
Assert.IsNotNull(driver, $"New Element {typeof(T).Name} error: driver is null.");
Assert.IsNotNull(element, $"New Element {typeof(T).Name} error: element is null.");
T newElement = new T();
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(timeoutMS);
newElement.SetSession(driver);
newElement.SetWindowsElement(element);
return newElement;
}
}
}

View File

@@ -0,0 +1,92 @@
// 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.PowerToys.UITest
{
/// <summary>
/// Represents a window in the UI test environment.
/// </summary>
public class Window : Element
{
/// <summary>
/// Maximizes the window.
/// </summary>
/// <param name="byClickButton">If true, clicks the Maximize button; otherwise, sets the window state.</param>
/// <returns>The current Window instance.</returns>
public Window Maximize(bool byClickButton = true)
{
if (byClickButton)
{
Find<Button>(By.Name("Maximize")).Click();
}
else
{
// TODO: Implement maximizing the window using an alternative method
}
return this;
}
/// <summary>
/// Restores the window.
/// </summary>
/// <param name="byClickButton">If true, clicks the Restore button; otherwise, sets the window state.</param>
/// <returns>The current Window instance.</returns>
public Window Restore(bool byClickButton = true)
{
if (byClickButton)
{
Find<Button>(By.Name("Restore")).Click();
}
else
{
// TODO: Implement restoring the window using an alternative method
}
return this;
}
/// <summary>
/// Minimizes the window.
/// </summary>
/// <param name="byClickButton">If true, clicks the Minimize button; otherwise, sets the window state.</param>
/// <returns>The current Window instance.</returns>
public Window Minimize(bool byClickButton = true)
{
if (byClickButton)
{
Find<Button>(By.Name("Minimize")).Click();
}
else
{
// TODO: Implement minimizing the window using an alternative method
}
return this;
}
/// <summary>
/// Closes the window.
/// </summary>
/// <param name="byClickButton">If true, clicks the Close button; otherwise, closes the window using an alternative method.</param>
public void Close(bool byClickButton = true)
{
if (byClickButton)
{
Find<Button>(By.Name("Close")).Click();
}
else
{
// TODO: Implement closing the window using an alternative method
}
}
}
}

View File

@@ -0,0 +1,72 @@
// 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.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("UITestBase")]
[assembly: InternalsVisibleTo("Session")]
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// This file manages the configuration of modules for UI tests.
/// </summary>
/// <remarks>
/// How to add a new module:
/// 1. Define the new module in the PowerToysModule enum.
/// 2. Add the exe window name to the ModuleWindowName dictionary in the ModuleConfigData constructor.
/// 3. Add the exe path to the ModulePath dictionary in the ModuleConfigData constructor.
/// </remarks>
/// <summary>
/// Represents the modules in PowerToys.
/// </summary>
public enum PowerToysModule
{
PowerToysSettings,
FancyZone,
Hosts,
}
internal class ModuleConfigData
{
private Dictionary<PowerToysModule, string> ModulePath { get; }
// Singleton instance of ModuleConfigData.
private static readonly Lazy<ModuleConfigData> SingletonInstance = new Lazy<ModuleConfigData>(() => new ModuleConfigData());
public static ModuleConfigData Instance => SingletonInstance.Value;
public const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
public Dictionary<PowerToysModule, string> ModuleWindowName { get; }
private ModuleConfigData()
{
// The exe window name for each module.
ModuleWindowName = new Dictionary<PowerToysModule, string>
{
[PowerToysModule.PowerToysSettings] = "PowerToys Settings",
[PowerToysModule.FancyZone] = "FancyZones Layout",
[PowerToysModule.Hosts] = "Hosts File Editor",
};
// Exe start path for the module if it exists.
ModulePath = new Dictionary<PowerToysModule, string>
{
[PowerToysModule.PowerToysSettings] = @"\..\..\..\WinUI3Apps\PowerToys.Settings.exe",
[PowerToysModule.FancyZone] = @"\..\..\..\PowerToys.FancyZonesEditor.exe",
[PowerToysModule.Hosts] = @"\..\..\..\WinUI3Apps\PowerToys.Hosts.exe",
};
}
public string GetModulePath(PowerToysModule scope) => ModulePath[scope];
public string GetWindowsApplicationDriverUrl() => WindowsApplicationDriverUrl;
public string GetModuleWindowName(PowerToysModule scope) => ModuleWindowName[scope];
}
}

View File

@@ -0,0 +1,129 @@
// 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.ObjectModel;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Provides interfaces for interacting with UI elements.
/// </summary>
public class Session
{
private WindowsDriver<WindowsElement> Root { get; set; }
private WindowsDriver<WindowsElement> WindowsDriver { get; set; }
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(nint hWnd);
public Session(WindowsDriver<WindowsElement> root, WindowsDriver<WindowsElement> windowsDriver)
{
this.Root = root;
this.WindowsDriver = windowsDriver;
}
/// <summary>
/// Finds an element by selector.
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="by">The selector to find the element.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>The found element.</returns>
public T Find<T>(By by, int timeoutMS = 3000)
where T : Element, new()
{
Assert.IsNotNull(this.WindowsDriver, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
var foundElement = FindElementHelper.Find<T, WindowsElement>(
() =>
{
var element = this.WindowsDriver.FindElement(by.ToSeleniumBy());
Assert.IsNotNull(element, $"Element not found using selector: {by}");
return element;
},
this.WindowsDriver,
timeoutMS);
return foundElement;
}
/// <summary>
/// Finds all elements by selector.
/// </summary>
/// <typeparam name="T">The class of the elements, should be Element or its derived class.</typeparam>
/// <param name="by">The selector to find the elements.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
/// <returns>A read-only collection of the found elements.</returns>
public ReadOnlyCollection<T>? FindAll<T>(By by, int timeoutMS = 3000)
where T : Element, new()
{
Assert.IsNotNull(this.WindowsDriver, $"WindowsElement is null in method FindAll<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
var foundElements = FindElementHelper.FindAll<T, WindowsElement>(
() =>
{
var elements = this.WindowsDriver.FindElements(by.ToSeleniumBy());
Assert.IsTrue(elements.Count > 0, $"Elements not found using selector: {by}");
return elements;
},
this.WindowsDriver,
timeoutMS);
return foundElements;
}
/// <summary>
/// Attaches to an existing PowerToys module.
/// </summary>
/// <param name="module">The PowerToys module to attach to.</param>
/// <returns>The attached session.</returns>
public Session Attach(PowerToysModule module)
{
string windowName = ModuleConfigData.Instance.GetModuleWindowName(module);
return this.Attach(windowName);
}
/// <summary>
/// Attaches to an existing exe by string window name.
/// The session should be attached when a new app is started.
/// </summary>
/// <param name="windowName">The window name to attach to.</param>
/// <returns>The attached session.</returns>
public Session Attach(string windowName)
{
if (this.Root != null)
{
var window = this.Root.FindElementByName(windowName);
Assert.IsNotNull(window, $"Failed to attach. Window '{windowName}' not found");
var windowHandle = new nint(int.Parse(window.GetAttribute("NativeWindowHandle")));
SetForegroundWindow(windowHandle);
var hexWindowHandle = windowHandle.ToString("x");
var appCapabilities = new AppiumOptions();
appCapabilities.AddAdditionalCapability("appTopLevelWindow", hexWindowHandle);
appCapabilities.AddAdditionalCapability("deviceName", "WindowsPC");
this.WindowsDriver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), appCapabilities);
Assert.IsNotNull(this.WindowsDriver, "Attach WindowsDriver is null");
// Set implicit timeout to make element search retry every 500 ms
this.WindowsDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(3);
}
else
{
Assert.IsNotNull(this.Root, $"Failed to attach to the window '{windowName}'. Root driver is null");
}
return this;
}
}
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Appium.WebDriver" />
<PackageReference Include="MSTest" />
<PackageReference Include="System.IO.Abstractions" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,130 @@
// 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.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Base class that should be inherited by all Test Classes.
/// </summary>
public class UITestBase
{
public Session Session { get; set; }
private readonly TestInit testInit = new TestInit();
public UITestBase(PowerToysModule scope = PowerToysModule.PowerToysSettings)
{
this.testInit.SetScope(scope);
this.testInit.Init();
this.Session = new Session(this.testInit.GetRoot(), this.testInit.GetDriver());
}
~UITestBase()
{
this.testInit.Cleanup();
}
/// <summary>
/// Nested class for test initialization.
/// </summary>
private sealed class TestInit
{
private WindowsDriver<WindowsElement> Root { get; set; }
private WindowsDriver<WindowsElement>? Driver { get; set; }
private static Process? appDriver;
// Default session path is PowerToys settings dashboard
private static string sessionPath = ModuleConfigData.Instance.GetModulePath(PowerToysModule.PowerToysSettings);
public TestInit()
{
appDriver = Process.Start(new ProcessStartInfo
{
FileName = "C:\\Program Files (x86)\\Windows Application Driver\\WinAppDriver.exe",
Verb = "runas",
});
var desktopCapabilities = new AppiumOptions();
desktopCapabilities.AddAdditionalCapability("app", "Root");
this.Root = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), desktopCapabilities);
// Set default timeout to 5 seconds
this.Root.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
}
/// <summary>
/// Initializes the test environment.
/// </summary>
[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "<Pending>")]
public void Init()
{
string? path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
this.StartExe(path + 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);
}
/// <summary>
/// Cleans up the test environment.
/// </summary>
public void Cleanup()
{
try
{
appDriver?.Kill();
}
catch (Exception ex)
{
// Handle exceptions if needed
Debug.WriteLine($"Exception during Cleanup: {ex.Message}");
}
}
/// <summary>
/// Starts a new exe and takes control of it.
/// </summary>
/// <param name="appPath">The path to the application executable.</param>
public void StartExe(string appPath)
{
var opts = new AppiumOptions();
opts.AddAdditionalCapability("app", appPath);
this.Driver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), opts);
}
/// <summary>
/// Sets scope to the Test Class.
/// </summary>
/// <param name="scope">The PowerToys module to start.</param>
public void SetScope(PowerToysModule scope)
{
sessionPath = ModuleConfigData.Instance.GetModulePath(scope);
}
public WindowsDriver<WindowsElement> GetRoot() => this.Root;
public WindowsDriver<WindowsElement> GetDriver()
{
Assert.IsNotNull(this.Driver, $"Failed to get driver. Driver is null.");
return this.Driver;
}
}
}
}