Skip to content

Commit

Permalink
More fixes for newer query API
Browse files Browse the repository at this point in the history
  • Loading branch information
Redth committed Oct 15, 2022
1 parent 7401aaf commit 809401b
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 140 deletions.
2 changes: 1 addition & 1 deletion src/Core/Query/DescendantsQueryStep.cs
Expand Up @@ -4,7 +4,7 @@ namespace Microsoft.Maui.Automation.Querying;

public class DescendantsQueryStep : PredicateQueryStep
{
public DescendantsQueryStep(Predicate<IElement> predicate) : base(predicate)
public DescendantsQueryStep(Predicate<IElement>? predicate) : base(predicate)
{
}

Expand Down
61 changes: 54 additions & 7 deletions src/Core/Query/DriverQuery.cs
Expand Up @@ -7,9 +7,12 @@
using System.Threading.Tasks;

namespace Microsoft.Maui.Automation.Querying
{
{
public class DriverQuery
{
public const int DefaultAutoWaitMilliseconds = 3000;
public const int DefaultAutoWaitRetryMilliseconds = 200;

public DriverQuery(IDriver driver)
{
Driver = driver;
Expand All @@ -31,16 +34,60 @@ public DriverQuery(IDriver driver, Platform automationPlatform)
public readonly IDriver Driver;
public readonly Query Query;

public async Task<IElement?> Element(int autoWaitMs = DefaultAutoWaitMilliseconds, int retryDelayMs = DefaultAutoWaitRetryMilliseconds)
=> (await AutoWait(autoWaitMs, retryDelayMs, false).ConfigureAwait(false)).FirstOrDefault();

public async Task<bool> NoElements(int autoWaitMs = DefaultAutoWaitMilliseconds, int retryDelayMs = DefaultAutoWaitRetryMilliseconds)
=> !(await AutoWait(autoWaitMs, retryDelayMs, true).ConfigureAwait(false)).Any();

public async Task<IEnumerable<IElement>> Execute()
=> await Query.Execute(Driver, await Driver.GetElements().ConfigureAwait(false)).ConfigureAwait(false);
public async Task<IEnumerable<IElement>> Elements(int autoWaitMs = DefaultAutoWaitMilliseconds, int retryDelayMs = DefaultAutoWaitRetryMilliseconds)
=> await AutoWait(autoWaitMs, retryDelayMs, false).ConfigureAwait(false);

public TaskAwaiter<IEnumerable<IElement>> GetAwaiter()
=> AutoWait().GetAwaiter();

public TaskAwaiter<IEnumerable<IElement>> GetAwaiter()
async Task<IEnumerable<IElement>> AutoWait(int autoWaitMs = DefaultAutoWaitMilliseconds, int retryDelayMs = DefaultAutoWaitRetryMilliseconds, bool waitForNone = false)
{
return Execute().GetAwaiter();
}
var waited = 0;

while (waited < autoWaitMs || autoWaitMs <= 0)
{
// See which automation platform to use
var platform = Query.AutomationPlatform ?? Driver.Configuration.AutomationPlatform;

var elements = await Driver.GetElements(platform).ConfigureAwait(false);

var results = await Query.Execute(Driver, elements);

var anyResults = results.Any();

if (waitForNone)
{
// Wait until no results found
if (autoWaitMs <= 0 || !anyResults)
{
if (anyResults)
throw new ElementsStillFoundException(Query);

return results;
}
}
else
{
// Wait until we find 1 or more
if (autoWaitMs <= 0 || anyResults)
return results;
}

Thread.Sleep(retryDelayMs);
waited += retryDelayMs;
}

if (waitForNone)
throw new ElementsStillFoundException(Query);
else
throw new ElementsNotFoundException(Query);
}

}
}
}
23 changes: 23 additions & 0 deletions src/Core/Query/FirstQueryStep.cs
@@ -0,0 +1,23 @@
using Microsoft.Maui.Automation.Driver;

namespace Microsoft.Maui.Automation.Querying;

class FirstQueryStep : PredicateQueryStep
{
public FirstQueryStep() : base()
{ }

public FirstQueryStep(Predicate<IElement>? predicate = null) : base(predicate)
{ }

public override Task<IEnumerable<IElement>> Execute(IDriver driver, IEnumerable<IElement> tree, IEnumerable<IElement> currentSet)
{
var first = currentSet.FirstOrDefault(e => Predicate(e));

if (first is not null)
return Task.FromResult<IEnumerable<IElement>>(new[] { first });
else
return Task.FromResult(Enumerable.Empty<IElement>());
}
}

80 changes: 56 additions & 24 deletions src/Core/Query/QueryExtensions.cs
Expand Up @@ -49,7 +49,7 @@ public static Query ClearText(this Query query, string text)

public static class DriverQueryExtensions
{
static DriverQuery Append(this DriverQuery query, Predicate<IElement> predicate)
static DriverQuery AppendChildren(this DriverQuery query, Predicate<IElement> predicate)
{
query.Query.Append(predicate);
return query;
Expand All @@ -59,35 +59,67 @@ static DriverQuery Append(this DriverQuery query, IQueryStep step)
{
query.Query.Append(step);
return query;
}

public static DriverQuery By(this DriverQuery query, Predicate<IElement> predicate)
=> query.Append(predicate);

public static DriverQuery ByAutomationId(this DriverQuery query, string automationId)
=> query.Append(e => e.AutomationId == automationId);

public static DriverQuery ById(this DriverQuery query, string id)
=> query.Append(e => e.Id == id);

public static DriverQuery OfType(this DriverQuery query, string typeName)
=> query.Append(e => e.Type == typeName);

public static DriverQuery OfFullType(this DriverQuery query, string fullTypeName)
=> query.Append(e => e.FullType == fullTypeName);

public static DriverQuery ContainingText(this DriverQuery query, string text, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> query.Append(e => e.Text.Contains(text, comparisonType));

public static DriverQuery Marked(this DriverQuery query, string marked, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> query.Append(e => e.Id.Equals(marked, comparisonType)
}


public static DriverQuery By(this DriverQuery query, Predicate<IElement>? predicate = null)
=> query.Append(new DescendantsQueryStep(predicate));


public static DriverQuery AutomationId(this DriverQuery query, string automationId)
=> query.By(e => e.AutomationId == automationId);

public static DriverQuery Id(this DriverQuery query, string id)
=> query.By(e => e.Id == id);

public static DriverQuery Type(this DriverQuery query, string typeName)
=> query.By(e => e.Type == typeName);

public static DriverQuery FullType(this DriverQuery query, string fullTypeName)
=> query.By(e => e.FullType == fullTypeName);

public static DriverQuery Text(this DriverQuery query, string text, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> query.By(e => e.Text.Equals(text, comparisonType));

public static DriverQuery ContainsText(this DriverQuery query, string text, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> query.By(e => e.Text.Contains(text, comparisonType));

public static DriverQuery Marked(this DriverQuery query, string marked, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> query.By(e => e.Id.Equals(marked, comparisonType)
|| e.AutomationId.Equals(marked, comparisonType)
|| e.Text.Equals(marked, comparisonType));

public static DriverQuery First(this DriverQuery query)
=> query.Append(new FirstQueryStep());


public static DriverQuery Children(this DriverQuery query, Predicate<IElement> predicate)
=> query.AppendChildren(predicate);

public static DriverQuery ChildrenByAutomationId(this DriverQuery query, string automationId)
=> query.AppendChildren(e => e.AutomationId == automationId);

public static DriverQuery ChildrenById(this DriverQuery query, string id)
=> query.AppendChildren(e => e.Id == id);

public static DriverQuery ChildrenOfType(this DriverQuery query, string typeName)
=> query.AppendChildren(e => e.Type == typeName);

public static DriverQuery ChildrenOfFullType(this DriverQuery query, string fullTypeName)
=> query.AppendChildren(e => e.FullType == fullTypeName);

public static DriverQuery ChildrenContainingText(this DriverQuery query, string text, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> query.AppendChildren(e => e.Text.Contains(text, comparisonType));

public static DriverQuery ChildrenMarked(this DriverQuery query, string marked, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> query.AppendChildren(e => e.Id.Equals(marked, comparisonType)
|| e.AutomationId.Equals(marked, comparisonType)
|| e.Text.Equals(marked, comparisonType));

public static DriverQuery Siblings(this DriverQuery query, Predicate<IElement>? predicate = null)
=> query.Append(new SiblingsQueryStep(predicate));

public static DriverQuery AtIndex(this DriverQuery query, int index)
public static DriverQuery Index(this DriverQuery query, int index)
=> query.Append(new IndexQueryStep(index));

public static DriverQuery Tap(this DriverQuery query)
Expand Down
1 change: 0 additions & 1 deletion src/Core/Query/SiblingsQueryStep.cs
Expand Up @@ -28,4 +28,3 @@ public override Task<IEnumerable<IElement>> Execute(IDriver driver, IEnumerable<
return Task.FromResult<IEnumerable<IElement>>(newSet);
}
}

114 changes: 45 additions & 69 deletions src/Driver/Extensions/DriverExtensions.cs
Expand Up @@ -12,83 +12,59 @@ namespace Microsoft.Maui.Automation.Driver;

public static partial class DriverExtensions
{

public static DriverQuery On(this IDriver driver, Platform automationPlatform)
=> new DriverQuery(driver, automationPlatform);

public static DriverQuery Query(this IDriver driver)
=> new DriverQuery(driver);


public static DriverQuery Query(this IDriver driver, Platform automationPlatform)
=> new DriverQuery(driver, automationPlatform);


public static DriverQuery ChildrenBy(this IDriver driver, Predicate<IElement> predicate)
=> new DriverQuery(driver).Children(predicate);

public static DriverQuery ChildrenByAutomationId(this IDriver driver, string automationId)
=> new DriverQuery(driver).ChildrenByAutomationId(automationId);

public static Task<IEnumerable<IElement>> All(this IDriver driver, Query query)
=> driver.AutoWait(query);

public static Task<IEnumerable<IElement>> Any(this IDriver driver, Query query)
=> driver.AutoWait(query);

public static Task<IElement?> First(this IDriver driver, Query query)
=> driver.AutoWaitFirst(query);




static async Task<IElement?> AutoWaitFirst(this IDriver driver, Query query, int autoWaitMs = 3000, int retryDelayMs = 200)
=> (await driver.AutoWait(query, autoWaitMs, retryDelayMs).ConfigureAwait(false)).FirstOrDefault();


//static async Task<IEnumerable<IElement>> AutoWait(this DriverQuery query, int autoWaitMs = 3000, int retryDelayMs = 200, bool waitForNone = false)
//{
// var elements = await AutoWait(query.Driver, query.Query, autoWaitMs, retryDelayMs).ConfigureAwait(false);


// return elements;
//}

static async Task<IEnumerable<IElement>> AutoWait(this IDriver driver, Query query, int autoWaitMs = 3000, int retryDelayMs = 200, bool waitForNone = false)
{
var waited = 0;

while (waited < autoWaitMs || autoWaitMs <= 0)
{
// See which automation platform to use
var platform = query.AutomationPlatform ?? driver.Configuration.AutomationPlatform;

var elements = await driver.GetElements(platform).ConfigureAwait(false);

var results = await query.Execute(driver, elements);

var anyResults = results.Any();

if (waitForNone)
{
// Wait until no results found
if (autoWaitMs <= 0 || !anyResults)
{
if (anyResults)
throw new ElementsStillFoundException(query);

return results;
}
}
else
{
// Wait until we find 1 or more
if (autoWaitMs <= 0 || anyResults)
return results;
}

Thread.Sleep(retryDelayMs);
waited += retryDelayMs;
}

if (waitForNone)
throw new ElementsStillFoundException(query);
else
throw new ElementsNotFoundException(query);
}
public static DriverQuery ChildrenById(this IDriver driver, string id)
=> new DriverQuery(driver).ChildrenById(id);

public static DriverQuery ChildrenOfType(this IDriver driver, string typeName)
=> new DriverQuery(driver).ChildrenOfType(typeName);

public static DriverQuery ChildrenOfFullType(this IDriver driver, string fullTypeName)
=> new DriverQuery(driver).ChildrenOfFullType(fullTypeName);

public static DriverQuery ChildrenContainingText(this IDriver driver, string text, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> new DriverQuery(driver).ChildrenContainingText(text, comparisonType);

public static DriverQuery ChildrenMarked(this IDriver driver, string marked, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> new DriverQuery(driver).ChildrenMarked(marked, comparisonType);


public static DriverQuery By(this IDriver driver, Predicate<IElement>? predicate = null)
=> new DriverQuery(driver).By(predicate);

public static DriverQuery AutomationId(this IDriver driver, string automationId)
=> new DriverQuery(driver).AutomationId(automationId);

public static DriverQuery Id(this IDriver driver, string id)
=> new DriverQuery(driver).Id(id);

public static DriverQuery Type(this IDriver driver, string typeName)
=> new DriverQuery(driver).Type(typeName);

public static DriverQuery FullType(this IDriver driver, string fullTypeName)
=> new DriverQuery(driver).FullType(fullTypeName);

public static DriverQuery Text(this IDriver driver, string text, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> new DriverQuery(driver).Text(text, comparisonType);

public static DriverQuery ContainsText(this IDriver driver, string text, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> new DriverQuery(driver).ContainsText(text, comparisonType);

public static DriverQuery Marked(this IDriver driver, string marked, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
=> new DriverQuery(driver).Marked(marked, comparisonType);
}

2 changes: 1 addition & 1 deletion src/Interactive/AutomationExtension.cs
Expand Up @@ -191,7 +191,7 @@ Task DisposeAppDriver(IDriver driver)
{
try
{
driver.Dispose();
driver.DisposeAsync();
}
catch
{ }
Expand Down

0 comments on commit 809401b

Please sign in to comment.