/
githubmirror
/
PowerToys
Обзор
Документация
Войти
/
githubmirror
/
PowerToys
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/common/UITestAutomation/Element/Element.cs
394 строки
14 KB
Josh Soref
Refresh check-spelling 0.0.26 (#47119)
24 апр 2026, 03:05
Не верифицирован
24 апр 2026, 03:05
2e5c7d2
Код
Авторство
О чём код?
// 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.Drawing; using System.Runtime.CompilerServices; using System.Xml.Linq; using ABI.Windows.Foundation; using Microsoft.PowerToys.UITest; using Microsoft.VisualStudio.TestTools.UnitTesting; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Windows; using OpenQA.Selenium.Interactions; [assembly: InternalsVisibleTo("Session")] namespace Microsoft.PowerToys.UITest { /// <summary> /// Represents a basic UI element in the application. /// </summary> public class Element { private WindowsElement? windowsElement; protected internal WindowsElement? WindowsElement { get => windowsElement; set => windowsElement = value; } private WindowsDriver<WindowsElement>? driver; protected internal WindowsDriver<WindowsElement>? Driver { get => driver; set => driver = value; } protected string? TargetControlType { get; set; } internal bool IsMatchingTarget() { var ct = this.ControlType; return string.IsNullOrEmpty(this.TargetControlType) || this.TargetControlType == this.ControlType; } 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 this.windowsElement?.Text ?? string.Empty; } } /// <summary> /// Gets a value indicating whether or not the UI element is Enabled. /// </summary> public bool Enabled { get { return this.windowsElement?.Enabled ?? false; } } public bool Selected { get { return this.windowsElement?.Selected ?? false; } } /// <summary> /// Gets a value indicating whether the UI element is visible to the user. /// </summary> public bool Displayed { get { return this.windowsElement?.Displayed ?? false; } } /// <summary> /// Gets the Rect of the UI element. /// </summary> public Rectangle? Rect { get { return this.windowsElement?.Rect; } } /// <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> /// Click the UI element. /// </summary> /// <param name="rightClick">If true, performs a right-click; otherwise, performs a left-click. Default value is false</param> /// <param name="msPreAction">Delay in milliseconds before performing the click action. Default is 500 ms.</param> /// <param name="msPostAction">Delay in milliseconds after performing the click action. Default is 500 ms.</param> public virtual void Click(bool rightClick = false, int msPreAction = 500, int msPostAction = 500) { PerformAction( (actions, windowElement) => { actions.MoveToElement(windowElement); // Move 2by2 offset to make click more stable instead of click on the border of the element actions.MoveByOffset(2, 2); if (rightClick) { actions.ContextClick(); } else { actions.Click(); } actions.Build().Perform(); }, msPreAction, msPostAction); } /// <summary> /// Double Click the UI element. /// </summary> public virtual void DoubleClick() { PerformAction((actions, windowElement) => { actions.MoveToElement(windowElement); // Move 2by2 offset to make click more stable instead of click on the border of the element actions.MoveByOffset(2, 2); actions.DoubleClick(); actions.Build().Perform(); }); } /// <summary> /// Release action /// </summary> public void ReleaseAction() { var releaseAction = new Actions(driver); releaseAction.Release().Perform(); } /// <summary> /// Release key /// </summary> public void ReleaseKey(Key key) { KeyboardHelper.ReleaseKey(key); } /// <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); 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 = 5000) where T : Element, new() { Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}"); // leverage findAll to filter out mismatched elements var collection = this.FindAll<T>(by, timeoutMS); Assert.IsTrue(collection.Count > 0, $"UI-Element({typeof(T).Name}) not found using selector: {by}"); return collection[0]; } /// <summary> /// Finds an element by the selector. /// Shortcut for this.Find<T>(By.Name(name), timeoutMS) /// </summary> /// <typeparam name="T">The class type of the element to find.</typeparam> /// <param name="name">The name for finding the element.</param> /// <param name="timeoutMS">The timeout in milliseconds.</param> /// <returns>The found element.</returns> public T Find<T>(string name, int timeoutMS = 5000) where T : Element, new() { return this.Find<T>(By.Name(name), timeoutMS); } /// <summary> /// Finds an element by the selector. /// Shortcut for this.Find<Element>(by, timeoutMS) /// </summary> /// <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 Element Find(By by, int timeoutMS = 5000) { return this.Find<Element>(by, timeoutMS); } /// <summary> /// Finds an element by the selector. /// Shortcut for this.Find<Element>(By.Name(name), timeoutMS) /// </summary> /// <param name="name">The name for finding the element.</param> /// <param name="timeoutMS">The timeout in milliseconds.</param> /// <returns>The found element.</returns> public Element Find(string name, int timeoutMS = 5000) { return this.Find<Element>(By.Name(name), timeoutMS); } /// <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 = 5000) 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 = FindHelper.FindAll<T, AppiumWebElement>( () => { 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); return foundElements ?? new ReadOnlyCollection<T>([]); } /// <summary> /// Finds all elements by the selector. /// Shortcut for this.FindAll<T>(By.Name(name), timeoutMS) /// </summary> /// <typeparam name="T">The class type of the elements to find.</typeparam> /// <param name="name">The name for finding the element.</param> /// <param name="timeoutMS">The timeout in milliseconds.</param> /// <returns>A read-only collection of the found elements.</returns> public ReadOnlyCollection<T> FindAll<T>(string name, int timeoutMS = 5000) where T : Element, new() { return this.FindAll<T>(By.Name(name), timeoutMS); } /// <summary> /// Finds all elements by the selector. /// Shortcut for this.FindAll<Element>(by, timeoutMS) /// </summary> /// <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<Element> FindAll(By by, int timeoutMS = 5000) { return this.FindAll<Element>(by, timeoutMS); } /// <summary> /// Finds all elements by the selector. /// Shortcut for this.FindAll<Element>(By.Name(name), timeoutMS) /// </summary> /// <param name="name">The name for finding the element.</param> /// <param name="timeoutMS">The timeout in milliseconds.</param> /// <returns>A read-only collection of the found elements.</returns> public ReadOnlyCollection<Element> FindAll(string name, int timeoutMS = 5000) { return this.FindAll<Element>(By.Name(name), timeoutMS); } /// <summary> /// Send Key of the element. /// </summary> /// <param name="key">The Key to Send.</param> public void SendKeys(string key) { PerformAction((actions, windowElement) => { windowElement.SendKeys(key); }); } /// <summary> /// Simulates a manual operation on the element. /// </summary> /// <param name="action">The action to perform on the element.</param> /// <param name="msPreAction">The number of milliseconds to wait before the action. Default value is 500 ms</param> /// <param name="msPostAction">The number of milliseconds to wait after the action. Default value is 500 ms</param> protected void PerformAction(Action<Actions, WindowsElement> action, int msPreAction = 500, int msPostAction = 500) { if (msPreAction > 0) { Task.Delay(msPreAction).Wait(); } var windowElement = this.windowsElement!; Actions actions = new Actions(this.driver); action(actions, windowElement); if (msPostAction > 0) { Task.Delay(msPostAction).Wait(); } } /// <summary> /// Save UI Element to a PNG file. /// </summary> /// <param name="path">the full path</param> public void SaveToPngFile(string path) { Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method SaveToPngFile with parameter: path = {path}"); this.windowsElement.GetScreenshot().SaveAsFile(path); } public void EnsureVisible(Element scrollViewer, int maxScrolls = 10) { int count = 0; if (scrollViewer.WindowsElement != null) { while (!this.windowsElement!.Displayed && count < maxScrolls) { scrollViewer.WindowsElement.SendKeys(OpenQA.Selenium.Keys.PageDown); Task.Delay(250).Wait(); count++; } } } } }