Skip to content

Commit

Permalink
support forceMatchAppTitle and forceMatchClassName (#17)
Browse files Browse the repository at this point in the history
* support forceMatchAppTitle

* forceMatchClassName
  • Loading branch information
licanhua committed Nov 20, 2020
1 parent b903c4a commit 820d649
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 8 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,31 @@ We finished the prototype. Because the legal concern and there is no business va

I think YWinAppDriver is able to address above problems, and possible make every body happy.

## Supported Locators to Find UI Elements

Windows Application Driver supports various locators to find UI element in the application session. The table below shows all supported locator strategies with their corresponding UI element attributes shown in **inspect.exe**.

| Client API | Locator Strategy | Matched Attribute in inspect.exe | Example |
|------------------------------ |------------------ |---------------------------------------- |-------------- |
| FindElementByAccessibilityId | accessibility id | AutomationId | AppNameTitle |
| FindElementByClassName | class name | ClassName | TextBlock |
| FindElementById | id | RuntimeId (decimal) | 42.333896.3.1 |
| FindElementByName | name | Name | Calculator |
| FindElementByTagName | tag name | LocalizedControlType (upper camel case) | Text |
| FindElementByXPath | xpath | Any | //Button[0] |

## Supported Capabilities

Below are the capabilities that can be used to create Windows Application Driver session.

| Capabilities | Descriptions | Example |
|-------------------- |------------------------------------------------------- |------------------------------------------------------- |
| app | Application identifier or executable full path | Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge |
| appArguments | Application launch arguments | https://github.com/Microsoft/WinAppDriver |
| attachToTopLevelWindowClassName | app should be "Root", Existing application top level window to attach to. if you are using WinAppDriver, please use appTopLevelWindow | `0xB822E2` |
| appWorkingDir | Application working directory (Classic apps only) | `C:\Temp` |
| forceMatchAppTitle | If app is launched, but have problem to match it, YWinAppDriver do the last try to match with the application title | Calculator |
| forceMatchClassName | If app is launched, but have problem to match it, YWinAppDriver do the last try to match with the class name | Calculator |

## Known issue

Expand Down
2 changes: 2 additions & 0 deletions src/Infra/Capabilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ public class Capabilities
public string attachToTopLevelWindowClassName;
public string appArguments;
public string appWorkingDir;
public string forceMatchAppTitle;
public string forceMatchClassName;
}
}
43 changes: 35 additions & 8 deletions src/Infra/Communication/ApplicationMananger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,38 @@ private UIObject GetTopLevelWindow(UIObject uiObject)
return uiObject;
}

private UICondition GetForceMatchCondition(string forceMatchAppTitle, string forceMatchClassName)
{
if (string.IsNullOrEmpty(forceMatchAppTitle))
{
return string.IsNullOrEmpty(forceMatchClassName) ? null : UICondition.CreateFromClassName(forceMatchClassName);
}
else if (string.IsNullOrEmpty(forceMatchClassName))
{
return UICondition.CreateFromName(forceMatchAppTitle);
}
return UICondition.CreateFromName(forceMatchAppTitle).AndWith(UICondition.CreateFromClassName(forceMatchClassName));
}

// refer https://github.com/microsoft/microsoft-ui-xaml/blob/40531c714f8003bf0d341a0729fa04dd2ed87710/test/testinfra/MUXTestInfra/Infra/Application.cs#L269
public IApplication LaunchModernApp(string appName)
public IApplication LaunchModernApp(string appName, string forceMatchAppTitle, string forceMatchClassName)
{
UICondition condition = UICondition.CreateFromClassName("ApplicationFrameWindow").OrWith(UICondition.CreateFromClassName("Windows.UI.Core.CoreWindow"));
var forceMatch = GetForceMatchCondition(forceMatchAppTitle, forceMatchClassName);
if (forceMatch != null)
{
condition = condition.OrWith(forceMatch);
}

var coreWindow = UAPApp.Launch(appName, condition);
var rootWindow = GetTopLevelWindow(coreWindow);
return new Application(new Element(rootWindow), coreWindow.ProcessId);
}

public IApplication LaunchLegacyApp(string filename, string arguments, string workingDirectory)
public IApplication LaunchLegacyApp(string filename, string arguments, string workingDirectory, string forceMatchAppTitle, string forceMatchClassName)
{
var forceMatch = GetForceMatchCondition(forceMatchAppTitle, forceMatchClassName);

// refer to https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.-ctor?view=netcore-3.1#System_Diagnostics_ProcessStartInfo__ctor_System_String_System_String_
ProcessStartInfo startInfo;

Expand Down Expand Up @@ -71,18 +91,25 @@ public IApplication LaunchLegacyApp(string filename, string arguments, string wo
while (retry-- > 0)
{
// check if the new opened window
if (windowOpenedWaiter.Source != null && windowOpenedWaiter.Source.ProcessId == process.Id)
{
// found
if (windowOpenedWaiter.Source != null)
{
var root = GetTopLevelWindow(windowOpenedWaiter.Source);
return new Application(new Element(root), process.Id);
if (windowOpenedWaiter.Source.ProcessId == process.Id || (forceMatch != null && root.Matches(forceMatch)))
{
return new Application(new Element(root), process.Id);
}
}
Task.Delay(sleepTimer).Wait(sleepTimer);
}

}

var condition = UICondition.Create(UIProperty.Get(ActionStrings.ProcessId), process.Id);
if (forceMatch != null)
{
condition = condition.OrWith(forceMatch);
}

var matched = UIObject.Root.Children.FindMultiple(condition).FirstOrDefault();
if (matched != null)
{
Expand Down Expand Up @@ -130,12 +157,12 @@ public IApplication LaunchApplication(Capabilities capabilities)
else if (app.Contains("!"))
{
Debug.WriteLine("Start UWPApp " + app);
return LaunchModernApp(capabilities.app);
return LaunchModernApp(capabilities.app, capabilities.forceMatchAppTitle, capabilities.forceMatchClassName);
}
else
{
Debug.WriteLine("Start Legacy app " + capabilities.ToString());
return LaunchLegacyApp(app, capabilities.appArguments, capabilities.appWorkingDir);
return LaunchLegacyApp(app, capabilities.appArguments, capabilities.appWorkingDir, capabilities.forceMatchAppTitle, capabilities.forceMatchClassName);
}

}
Expand Down

0 comments on commit 820d649

Please sign in to comment.