Microsoft UI Automation for Web Application - wpf

Has anyone tried "Microsoft UI Automation" for web application?
I have a WPF application which has a embedded wpfbrowser.
Since this is basically a desktop app, I cant use Selenium Webdriver.
I tried CodedUI but i am facing a issue, Which i have asked here:
Coded UI - Unable to identify a html controls on a Wpfbrowser
I am planning to use UIAutomation, But again itseems that i am unable to identify a control using id property
Ex:
<button id="but1">Click Me</button>
For this i have:
PropertyCondition ps = new PropertyCondition(AutomationElement.AutomationIdProperty, "but1");
AutomationElement Clickme = elementMainWindow.FindFirst(TreeScope.Descendants, ps);
But this is not working. "Clickme" is null.
How to do this is UIAutomation??
EDIT: Attaching a screeshot:

I would try actually navigating the tree view down to the control you are looking for instead of doing it based on decedents. Also another thing you could try is doing a retry loop if it is null. Here is an example of a generic Retry for FlaUI. So your code would look something like this.
PropertyCondition ps = new PropertyCondition(AutomationElement.AutomationIdProperty, "but1");
Func<AutomationElement> func = () => elementMainWindow.FindFirst(TreeScope.Descendants, ps);
Predicate<AutomationElement> retry = element => element == null;
AutomationElement clickMe = Retry.While<AutomationElement>(func, retry, TimeSpan.FromSeconds(1));
So this code will retry finding the element for 1 second and will retry finding it if the element comes back null or it exceptions. If either of those happens it waits 200 milliseconds and tries again. This will tell me if the elements are just not rendered when you try to find them or if their is a difference between how inspect finds them and how System.Windows.Automation is finding them.
If this doesn't work I will post a solution using the tree walker but I suggest using this solution over the tree walker because if this was an application others would want to write automation against they would expect these functions to work the way you are attempting to use them.

Not sure if <button id="but1"> equals with automationId. You can set automation id using AutomationProperties.AutomationId="but1" if you can use that namespace in the code where you define your UI (XAML), which is probaly only for WPF applications.
In your case if your UI defined in HTML I think you can use the button's caption.
So something like this.
var ps = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
new PropertyCondition(AutomationElement.NameProperty, "Click Me"));
AutomationElement Clickme = elementMainWindow.FindFirst(TreeScope.Descendants, ps);
ControlTypeProperty can help in filtering results by type. Not mandatory, but it can help if you have automation elements with different type, but with same name property.

Related

WinAppDriver - How do I get the list of properties available on an element

I am using Appium with WinAppDriver to control a WinForms / WPF application.
I am looking for a programmatic way to get the list of properties available on an element that has been retrieved.
My current thinking is to ask for the className and use this to look up a static dictionary of properties I have pre-configured.
var element = driver.FindElementByXPath(xPath);
var properties = element.getProperties(); // Is there something I can call here?
This is not the greatest solution but I figured I would mention it just in case someone else might find it useful:
It is possible to get the xml of the pagesource and look at the properties there. This can be accomplished by calling driver.PageSource which will return an xml string.
Hope someone finds this useful.
You can use element.GetAttribute("Value") to get the value. You can also use other attributes like LegacyState, Value.Value, IsEnabled, IsOffscreen, ControlType etc. You can catch hold of the list of attributes in Inspect.exe (UI access)that comes with windows tools

Disable active content in WebBrowser control

I have embedded a WebBrowser control in my application and display content that I receive from a server. Specifically: The control is bound to a string which contains the error message from a rest call, that sometimes is HTML.
I wonder if there is a security risk if active content, e.g. JavaScript would be sent as part of the error message. Is there a way to instruct the WebBrowser control to disable all active content?
There are several ways to do:
First way is remove javascript from your string before pass it to browser, from Elian Ebbing's answer:
The quick 'n' dirty method would be a regex like this:
var regex = new Regex(
"(\\<script(.+?)\\</script\\>)|(\\<style(.+?)\\</style\\>)",
RegexOptions.Singleline | RegexOptions.IgnoreCase
);
string ouput = regex.Replace(input, "");
The better* (but possibly slower) option would be to use
HtmlAgilityPack:
HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(htmlInput);
var nodes = doc.DocumentNode.SelectNodes("//script|//style");
foreach (var node in nodes) node.ParentNode.RemoveChild(node);
string htmlOutput = doc.DocumentNode.OuterHtml;
*) For a discussion about why it's better, see this thread.
That way seem better and easier.
Second way is use WinForms webbrowser control, which allow you control lower level of browser, but this involve some invoking to WinAPI.
You can see this link for more info.

Error stating "element is not found in the cache perhaps the page has changed"

I'm trying to click search button on flipkart through Selenium Webdriver using Java, i'm able to click the button by the X-path and i written 'Boolean' to display button was clicked.
Here's the code:
WebElement search = driver.findElement(By.xpath(".//*[#id='fk-header-search-form']/div/div/div[2]/input[1]"));
search.click();
boolean clicked = search.isEnabled();
System.out.println("Serach Button Clicked"+clicked);
If page is change after click on button, it is normal to not find element. You perform a search peocess, after click, new page being loading.
Another point, isEnabled, everytime returns true except disabled. In this situation, it looks already active.
There are a few issues.
.isEnabled() Determines whether the element is enabled. According to the docs, this is pretty much always going to be true except in a case where there's an INPUT that is disabled (which doesn't apply here). So your code is just telling you that the Search button is not disabled, not whether you clicked it or not.
You didn't post enough code to tell why you are getting this error. I can see what you are trying to do and wrote a simple example of how to do this.
Try this
FirefoxDriver driver = new FirefoxDriver();
driver.get("http://www.flipkart.com/");
By searchBoxLocator = By.id("fk-top-search-box");
By searchButtonLocator = By.cssSelector("input[value='Search']");
driver.findElement(searchBoxLocator).sendKeys("watch");
driver.findElement(searchButtonLocator).click();
I would suggest that you use something other than XPaths. They are brittle and slower than other methods. In the code above, I used a CSS Selector. Read some tutorials and use this page as a reference. They are very powerful and are, IMHO, better than XPath. There is some stuff that can only be done with XPath... avoid XPath until you hit one of those cases.

Clicking/Selecting Check box(s) in CodedUI Testing

I'm trying to create an Automation CodedUI Testing script (using Visual Studio Premium 2013) where I'm trying to click/Select a check box(s). I have the procedure codes names for few nodes in procedure codes.
How do I make VS to click those check boxes?
Thanks :)
Check over what you get back from calling GetChildren() on your identified WinTreeItem.
If in the list is a WinCheckBox that is most likely what you need to define.
var checkBox = new WinCheckBox(yourTreeItem);
checkBox.TryFind();
Mouse.Click(checkBox);
Now it is worth mentioning as well CodedUI also provides the WinCheckBoxTreeItem type of control. Which might bind to your desired check box as well.
var treeCheckItem = new WinCheckBoxTreeItem(yourWinTree);
// add search properties like display text
treeCheckItem.TryFind();
treeCheckItem.Checked = true;

Sharing Linq to SQL DataContext between WP7.1 and WPF apps?

I have built a WP7.1 application that uses a local database. I used sqlmetal to generate the data context as per this article. http://blogs.microsoft.co.il/blogs/alex_golesh/archive/2011/05/24/windows-phone-mango-what-s-new-local-database-part-1-of-8.aspx
This works as expected using this in the ViewModel.
context = new BirdsnBflysDC("DataSource='isostore:BirdsnBflys.sdf'");`
I am now attempting to "share" the Model and ViewModel code with a WPF application. Initially I added the appropriate files as a link to the WPF project. Creating an instance of the context didn't work so as a test I have added just the data context code to a WPF project and attempt to create an instance of the context in the Loaded event handler as follows.
BirdsnBflysDC context = new BirdsnBflysDC("DataSource='C:\BirdsnBflys.sdf'");
DataContext = context;
The code actually has the complete path to the database. When I step through this in the debugger the context initialization in the data context quits running as if there was an exception, the second line of code above is never reached and the WPF window is shown as if things completed correctly.
I've tried several variation in the DataSource string including "|DataDirectory|\\BirdsnBflys.sdf" all with the same result.
Any suggestions as where to go with this? How to figure out what isn't working correctly?
Thanks,
Dave
The problem is that what is expected in the connection string is different for the two environments.
WP7 works with this.
context = new BirdsnBflysDC("DataSource='isostore:BirdsnBflys.sdf'");
WPF works with this.
context = new BirdsnBflysDC("|DataDirectory|\BirdsnBflys.sdf");
If you give WPF a file name that isn't there you get no error information, the instantiation of the data context fails quietly and any additional code does not get executed.
Dave
Did you remove the 2 methods from the generated cs file? I mean the methods unsupported by mango.
public ExternalDB(System.Data.IDbConnection connection) :
base(connection, mappingSource)
{
OnCreated();
}
public ExternalDB(System.Data.IDbConnection connection,
System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
I am not sure about this, but they might be needed for wpf.
Hope this helps.

Resources