AutomationIDs not available when running from custom adapter?!

Jan 4, 2013 at 1:27 PM
Edited Apr 9, 2014 at 9:54 AM
  Goal: Automate the login of a XBAP(xaml browser application). Scenario that works: When I configure the application as a UII Hosted Application and configure it to use the HAT automation adapter, the application runs within the agent desktop. And I am able to automate from a console application with the following code: private void btnStartAutomation_Click(object sender, RoutedEventArgs e) { Thread automateThread = new Thread(new ThreadStart(AutomateSytel)); automateThread.Start(); } private void AutomateSytel() { LogMessage("Getting RootElement..."); AutomationElement rootElement = AutomationElement.RootElement; if (rootElement != null) { //Automation.Condition condition = new PropertyCondition(AutomationElement., "UI Automation Test Window"); Automation.Condition conditie = new PropertyCondition(AutomationElement.AutomationIdProperty, "AgentDesktop"); AutomationElement agentDesktopElement = rootElement.FindFirst(TreeScope.Children, conditie); if (agentDesktopElement != null) { LogMessage("Searching for TextBox Agent Name control..."); AutomationElement agentNameElement = GetTextElement(agentDesktopElement, "GuestName"); if (agentNameElement != null) { LogMessage("Setting Agent Name value..."); try { ValuePattern valuePatternA = agentNameElement.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern; valuePatternA.SetValue("bla"); LogMessage("OK " + Environment.NewLine); } catch(Exception ex) { WriteLogError(); } } else { WriteLogError(); } LogMessage("Searching for TextBox Password control..."); AutomationElement passwordElement = GetTextElement(agentDesktopElement, "PassWord"); if (agentNameElement != null) { LogMessage("OK " + Environment.NewLine); LogMessage("Setting TextBox password value..."); try { ValuePattern valuePatternB = passwordElement.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern; valuePatternB.SetValue("mypassword"); LogMessage("OK " + Environment.NewLine); } catch { WriteLogError(); } } else { WriteLogError(); } LogMessage("Searching for TextBox Extension control..."); AutomationElement extensionElement = GetTextElement(agentDesktopElement, "Extension"); if (passwordElement != null) { LogMessage("OK " + Environment.NewLine); LogMessage("Setting TextBox extension value..."); try { ValuePattern valuePatternC = extensionElement.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern; valuePatternC.SetValue("0101234567"); LogMessage("OK " + Environment.NewLine); } catch { WriteLogError(); } } else { WriteLogError(); } AutomationElement btnElement = GetButtonElement(agentDesktopElement, "Verify"); if (btnElement != null) { LogMessage("OK " + Environment.NewLine); LogMessage("Clicking button Log In..."); try { InvokePattern btnPattern = btnElement.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern; btnPattern.Invoke(); } catch { WriteLogError(); } } else { WriteLogError(); } } else { WriteLogError(); } } } private AutomationElement GetTextElement(AutomationElement parentElement, string value) { Automation.Condition condition = new PropertyCondition(AutomationElement.AutomationIdProperty, value); AutomationElement txtElement = parentElement.FindFirst(TreeScope.Descendants, condition); return txtElement; } private AutomationElement GetButtonElement(AutomationElement parentElement, string value) { Automation.Condition condition = new PropertyCondition(AutomationElement.AutomationIdProperty, value); AutomationElement btnElement = parentElement.FindFirst(TreeScope.Descendants, condition); return btnElement; } private void DisplayLogMessage(string message) { txtLogs.Text += message; } private void LogMessage(string message) { this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new SetMessageCallback(DisplayLogMessage), message); } private void WriteLogError() { LogMessage("ERROR." + Environment.NewLine); } PROBLEM: Of course this code should be run from within the AgentDesktop, therefor I created a custom adapter. But when I ran my custom adapter with the code shown below. It cannot find the textboxes by ID. I noticed when going down the tree, that the AutomationID and classnames are not set in this case. How can I solve this issue? public class SytelAutomationAdapter : WebApplicationAdapter { /// <summary> /// Does the receive action. /// </summary> /// <param name="action">The action specified in the request.</param> /// <param name="args">The <see cref="Microsoft.Uii.Csr.RequestActionEventArgs"/> instance containing the event data.</param> /// <returns>Returns a value indicating the success of the action.</returns> public override bool DoAction(Microsoft.Uii.Csr.Action action, Microsoft.Uii.Csr.RequestActionEventArgs args) { bool actionState = false; if (args != null) { switch (args.Action) { case "default": //perform the login //LoginSytel(); actionState = true; break; default: break; } } return actionState; } public override void DocumentComplete(string urlString) { //perform the login LoginSytel(); base.DocumentComplete(urlString); } private void LoginSytel() { LogMessage("Getting RootElement..."); AutomationElement rootElement = AutomationElement.RootElement; if (rootElement != null) { LogMessage("OK." + Environment.NewLine); //Automation.Condition condition = new PropertyCondition(AutomationElement., "UI Automation Test Window"); Automation.Condition conditie = new PropertyCondition(AutomationElement.AutomationIdProperty, "AgentDesktop"); AutomationElement agentDesktopElement = rootElement.FindFirst(TreeScope.Children, conditie); if (agentDesktopElement != null) { LogMessage("OK " + Environment.NewLine); LogMessage("Searching for TextBox Agent Name control..."); AutomationElement agentNameElement = GetTextElement(agentDesktopElement, "GuestName"); if (agentNameElement != null) { LogMessage("OK " + Environment.NewLine); LogMessage("Setting Agent Name value..."); try { ValuePattern valuePatternA = agentNameElement.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern; valuePatternA.SetValue("bla"); LogMessage("OK " + Environment.NewLine); } catch (Exception ex) { WriteLogError(); } } } else { WriteLogError(); } } } private AutomationElement GetTextElement(AutomationElement parentElement, string value) { Automation.Condition condition = new PropertyCondition(AutomationElement.AutomationIdProperty, value); AutomationElement txtElement = parentElement.FindFirst(TreeScope.Descendants, condition); return txtElement; } private AutomationElement GetButtonElement(AutomationElement parentElement, string value) { Automation.Condition condition = new PropertyCondition(AutomationElement.AutomationIdProperty, value); AutomationElement btnElement = parentElement.FindFirst(TreeScope.Descendants, condition); return btnElement; } private void LogMessage(string message) { Logging.Info("Sytel", message); } private void WriteLogError() { Logging.Error("Sytel", "ERROR." + Environment.NewLine); } }
Feb 12, 2013 at 7:50 PM
I'm not sure if this is 100% the current way or not but when I instantiate my WebApplicationAdapter, I had to instantiate an instance of the WebDDAAdapter and I believe it takes in an xml parameter. I was able to get it to read the AutomationXML. From there I could then reference objects by their automation id in my WebApplicationAdapter.

The downside, I found is that each time I called an Action I head to re-initialize the WebDDAAdapter and set it to null or dispose when my action was completed. If that makes sense.

Jeremy