Skip to content

Commit

Permalink
Merge pull request #21 from Redth/dev/queryable
Browse files Browse the repository at this point in the history
New Query API, AutoWaiting
  • Loading branch information
Redth authored Oct 16, 2022
2 parents ec88c37 + fdcd590 commit 6f58231
Show file tree
Hide file tree
Showing 47 changed files with 1,297 additions and 693 deletions.
19 changes: 12 additions & 7 deletions src/Agent/Apple/iOSApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,20 @@ public override async Task<string> GetProperty(string elementId, string property
return string.Empty;
}

public override Task<IEnumerable<Element>> GetElements()
public override Task<IEnumerable<IElement>> GetElements()
{
var root = GetRootElements(-1);
IEnumerable<IElement> root = Enumerable.Empty<IElement>();

UIApplication.SharedApplication.InvokeOnMainThread(() =>
{
root = GetRootElements(-1);
});

return Task.FromResult(root);
}


IEnumerable<Element> GetRootElements(int depth)
IEnumerable<IElement> GetRootElements(int depth)
{
var children = new List<Element>();

Expand Down Expand Up @@ -86,20 +91,20 @@ IEnumerable<Element> GetRootElements(int depth)
return children;
}

public override Task<IEnumerable<Element>> FindElements(Predicate<Element> matcher)
public override Task<IEnumerable<IElement>> FindElements(Predicate<IElement> matcher)
{
var windows = GetRootElements(-1);

var matches = new List<Element>();
var matches = new List<IElement>();
Traverse(windows, matches, matcher);

return Task.FromResult<IEnumerable<Element>>(matches);
return Task.FromResult<IEnumerable<IElement>>(matches);
}

public override Task<PerformActionResult> PerformAction(string action, string elementId, params string[] arguments)
=> Task.FromResult(new PerformActionResult { Status = -1 });

void Traverse(IEnumerable<Element> elements, IList<Element> matches, Predicate<Element> matcher)
void Traverse(IEnumerable<IElement> elements, IList<IElement> matches, Predicate<IElement> matcher)
{
foreach (var e in elements)
{
Expand Down
33 changes: 23 additions & 10 deletions src/Agent/Apple/iOSExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,36 @@ static string TextFromUIInput(IUITextInput ti)
var end = ti.EndOfDocument;
var range = ti.GetTextRange(start, end);
return ti.TextInRange(range);
}
}

internal static string EnsureUniqueId(this UIKit.UIView view)
{
var id = view.AccessibilityIdentifier;

if (string.IsNullOrEmpty(id))
{
id = Guid.NewGuid().ToString();
view.AccessibilityIdentifier = id;
}

return id;
}

public static Element GetElement(this UIKit.UIView uiView, IApplication application, string parentId = "", int currentDepth = -1, int maxDepth = -1)
{
var scale = uiView.Window?.Screen?.NativeScale.Value ?? 1.0f;

var viewFrame = uiView.Frame.ToFrame();
var windowFrame = uiView.ConvertRectToView(uiView.Bounds, uiView.Window).ToFrame();
var windowFrame = uiView.ConvertRectToView(uiView.Bounds, uiView.Window).ToFrame();

#if MACCATALYST
var nsWindow = UINSWindow.From(uiView.Window);
var screenFrame = nsWindow.ConvertRectToScreen(uiView.Frame).ToFrame();
#else
var screenFrame = UIAccessibility.ConvertFrameToScreenCoordinates(uiView.Frame, uiView).ToFrame();
var screenFrame = UIAccessibility.ConvertFrameToScreenCoordinates(uiView.Frame, uiView).ToFrame();
#endif

var e = new Element(application, Platform.Ios, uiView.Handle.ToString(), uiView, parentId)
var e = new Element(application, Platform.Ios, uiView.EnsureUniqueId(), uiView, parentId)
{
AutomationId = uiView.AccessibilityIdentifier ?? string.Empty,
Visible = !uiView.Hidden,
Expand Down Expand Up @@ -95,20 +108,20 @@ public static Frame ToFrame(this CGRect rect)

public static Element GetElement(this UIWindow window, IApplication application, int currentDepth = -1, int maxDepth = -1)
{
var scale = window?.Screen?.NativeScale.Value ?? 1.0f;
var scale = window?.Screen?.NativeScale.Value ?? 1.0f;

#if MACCATALYST
var nsWindow = UINSWindow.From(window);
var nsWindow = UINSWindow.From(window);

var viewFrame = window.Frame.ToFrame();
var windowFrame = nsWindow.Frame.ToFrame();
var screenFrame = nsWindow.ConvertRectToScreen(window.Frame).ToFrame();
#else
var viewFrame = window.Frame.ToFrame();
var windowFrame = window.Frame.ToFrame();
var screenFrame = UIAccessibility.ConvertFrameToScreenCoordinates(window.Frame, window).ToFrame();
var viewFrame = window.Frame.ToFrame();
var windowFrame = window.Frame.ToFrame();
var screenFrame = UIAccessibility.ConvertFrameToScreenCoordinates(window.Frame, window).ToFrame();
#endif
var e = new Element(application, Platform.Ios, window.Handle.ToString(), window)
var e = new Element(application, Platform.Ios, window.EnsureUniqueId(), window)
{
AutomationId = window.AccessibilityIdentifier ?? window.Handle.ToString(),
ViewFrame = viewFrame,
Expand Down
25 changes: 13 additions & 12 deletions src/Agent/MauiApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks;
using MauiIElement = Microsoft.Maui.IElement;

namespace Microsoft.Maui.Automation
{
Expand Down Expand Up @@ -42,38 +43,38 @@ void Dispatch(Action action)

public readonly IApplication PlatformApplication;

public override Task<IEnumerable<Element>> GetElements()
=> Dispatch<IEnumerable<Element>>(() =>
public override Task<IEnumerable<IElement>> GetElements()
=> Dispatch<IEnumerable<IElement>>(() =>
{
var windows = new List<Element>();
var windows = new List<IElement>();

foreach (var window in MauiPlatformApplication.Windows)
{
var w = window.GetMauiElement(this, currentDepth: 1, maxDepth: -1);
windows.Add(w);
}

return Task.FromResult<IEnumerable<Element>>(windows);
return Task.FromResult<IEnumerable<IElement>>(windows);
});

public override Task<IEnumerable<Element>> FindElements(Predicate<Element> matcher)
=> Dispatch<IEnumerable<Element>>(() =>
public override Task<IEnumerable<IElement>> FindElements(Predicate<IElement> matcher)
=> Dispatch<IEnumerable<IElement>>(() =>
{
var windows = new List<Element>();
var windows = new List<IElement>();

foreach (var window in MauiPlatformApplication.Windows)
{
var w = window.GetMauiElement(this, currentDepth: 1, maxDepth: 1);
windows.Add(w);
}

var matches = new List<Element>();
var matches = new List<IElement>();
Traverse(windows, matches, matcher);

return Task.FromResult<IEnumerable<Element>>(matches);
return Task.FromResult<IEnumerable<IElement>>(matches);
});

void Traverse(IEnumerable<Element> elements, IList<Element> matches, Predicate<Element> matcher)
void Traverse(IEnumerable<IElement> elements, IList<IElement> matches, Predicate<IElement> matcher)
{
foreach (var e in elements)
{
Expand Down Expand Up @@ -111,7 +112,7 @@ public override async Task<PerformActionResult> PerformAction(string action, str
var elements = await this.GetElements();
var element = elements.Find(e => e.Id == elementId).FirstOrDefault();

if (element.PlatformElement is IElement mauiElement)
if (element.PlatformElement is MauiIElement mauiElement)
{

if (action == Actions.InputText)
Expand Down
10 changes: 5 additions & 5 deletions src/Agent/MauiExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ internal static Element[] GetChildren(this Maui.IView view, IApplication applica
}
else if (view is Microsoft.Maui.Controls.NavigationPage navigationPage)
{
return new[] { navigationPage.CurrentPage.GetMauiElement(application, parentId, currentDepth, maxDepth) };
}
return new[] { navigationPage.CurrentPage.GetMauiElement(application, parentId, currentDepth, maxDepth) };
}
else if (view is IContentView content && content?.Content is Maui.IView contentView)
{
return new[] { contentView.GetMauiElement(application, parentId, currentDepth, maxDepth) };
Expand All @@ -39,7 +39,7 @@ internal static Element[] GetChildren(this Maui.IView view, IApplication applica
}


internal static Element GetPlatformWindowElement(this Maui.IWindow window, IApplication application)
internal static IElement GetPlatformWindowElement(this Maui.IWindow window, IApplication application)
{
#if ANDROID
if (window.Handler.PlatformView is Android.App.Activity activity)
Expand All @@ -54,7 +54,7 @@ internal static Element GetPlatformWindowElement(this Maui.IWindow window, IAppl
return null;
}

internal static Element GetPlatformViewElement(this Maui.IView view, IApplication application, string parentId = "")
internal static IElement GetPlatformViewElement(this Maui.IView view, IApplication application, string parentId = "")
{
#if ANDROID
if (view.Handler.PlatformView is Android.Views.View androidview)
Expand Down Expand Up @@ -86,7 +86,7 @@ internal static Element GetPlatformViewElement(this Maui.IView view, IApplicatio
// }


internal static Element GetMauiElement(this Maui.IWindow window, IApplication application, string parentId = "", int currentDepth = -1, int maxDepth = -1)
internal static IElement GetMauiElement(this Maui.IWindow window, IApplication application, string parentId = "", int currentDepth = -1, int maxDepth = -1)
{
var platformElement = window.GetPlatformWindowElement(application);

Expand Down
8 changes: 4 additions & 4 deletions src/Agent/Platforms/Android/AndroidApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,19 @@ public override Task<string> GetProperty(string elementId, string propertyName)
throw new NotImplementedException();
}

public override Task<IEnumerable<Element>> GetElements()
public override Task<IEnumerable<IElement>> GetElements()
{
return Task.FromResult(LifecycleListener.Activities.Select(a => a.GetElement(this, 1, -1)));
return Task.FromResult<IEnumerable<IElement>>(LifecycleListener.Activities.Select(a => a.GetElement(this, 1, -1)));
}

public override Task<IEnumerable<Element>> FindElements(Predicate<Element> matcher)
public override Task<IEnumerable<IElement>> FindElements(Predicate<IElement> matcher)
{
var windows = LifecycleListener.Activities.Select(a => a.GetElement(this, 1, 1));

var matches = new List<Element>();
Traverse(windows, matches, matcher);

return Task.FromResult<IEnumerable<Element>>(matches);
return Task.FromResult<IEnumerable<IElement>>(matches);
}

public override async Task<PerformActionResult> PerformAction(string action, string elementId, params string[] arguments)
Expand Down
6 changes: 3 additions & 3 deletions src/Agent/Platforms/Windows/WindowsAppSdkApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public class WindowsAppSdkApplication : Application
public override Platform DefaultPlatform => Platform.Winappsdk;


public override Task<IEnumerable<Element>> GetElements()
=> Task.FromResult<IEnumerable<Element>>(new[] { UI.Xaml.Window.Current.GetElement(this, 1, -1) });
public override Task<IEnumerable<IElement>> GetElements()
=> Task.FromResult<IEnumerable<IElement>>(new[] { UI.Xaml.Window.Current.GetElement(this, 1, -1) });

public override async Task<string> GetProperty(string elementId, string propertyName)
{
Expand All @@ -30,7 +30,7 @@ public override async Task<string> GetProperty(string elementId, string property
}


public override async Task<IEnumerable<Element>> FindElements(Predicate<Element> matcher)
public override async Task<IEnumerable<IElement>> FindElements(Predicate<IElement> matcher)
{
var windows = new[] { UI.Xaml.Window.Current.GetElement(this, 1, 1) };

Expand Down
11 changes: 6 additions & 5 deletions src/Core/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;

using Microsoft.Maui.Automation.Querying;

namespace Microsoft.Maui.Automation
{
{
public class ElementNotFoundException : Exception
{
public ElementNotFoundException(string elementId)
Expand Down Expand Up @@ -80,9 +81,9 @@ protected virtual void DisposeUnmanagedResources()

public abstract Task<string> GetProperty(string elementId, string propertyName);

public abstract Task<IEnumerable<Element>> GetElements();
public abstract Task<IEnumerable<IElement>> GetElements();

public abstract Task<IEnumerable<Element>> FindElements(Predicate<Element> matcher);
public abstract Task<IEnumerable<IElement>> FindElements(Predicate<IElement> matcher);

public Task<PerformActionResult> PerformAction(string action, params string[] arguments)
=> PerformAction(action, string.Empty, arguments);
Expand All @@ -97,5 +98,5 @@ public Task<string[]> Backdoor(string fullyQualifiedTypeName, string staticMetho
return Task.FromResult(result as string[] ?? new string[0] );
}

}
}
}
Loading

0 comments on commit 6f58231

Please sign in to comment.