Verifying WPF data bound item controls in Coded UI Test recording context


Coded UI Test relies on unique identification properties of controls to form a resilient search condition during recording. In WPF you can data bind properties of a control and its children collection of ItemsControl such as ListBox, ComboBox, DataGrid, TreeView, etc. An earlier post here describes the problem in more detail. Coded UI Test makes a best attempt to recognize this problem and reports an error during recording. When I say best attempt, it relies on certain heuristics to deduce this based on the amount of information provided by UI Automation layer. It may not work well for Datagrid rows or rich data templates.This post lists out a series of verifications you can do at your end if ever you hit this error while recording. If you see any discrepancies in the behavior, or certain scenarios which are unhandled, feel free to post your comment. We will analyze it and see if they can be incorporated in the heuristic.

1. Check if Automation Name of the item element looks like a default object .ToString() of a Class Type (e.g. System.Xml.XmlElement) i.e. has ‘.’ somewhere in the middle of the string (not first or last char)

2. Check if sibling are of same control type and name i.e. previous and next sibling. For Datagrid scenario, check for extended siblings of the dataitem, around 10 siblings (previous/next). For expandable
items (such as MenuItem, TreeItem), check if it’s parent/child are of similar control type and name.

3. Check if the item has a TextBlock child. The additional conditions are –

    A. TextBlock exists only in UI Automation’s RawView tree and not in ControlView tree.
    B. There should be exactly one such TextBlock in the children list.   
         For performance reasons, we navigate only through first 3 children to look for this TextBlock child. So the heuristic would miss out if the TextBlock is somewhere beyond the 3rd child, which is rare though.

4.  Once such a TextBlock child exists as per conditions in [3], check if this TextBlock’s Name is NOT equal to the ItemElement’s Name (so the item element will have some name like System.Xml.XmlElement and the TextBlock will typically have a good name which is the visually text seen in UI).

If all the above 4 conditions are satisfied, the item is deduced as data-bound.

Comments (4)

  1. i am trying to automate my outlook 2010 using visual studio 2012 coded UI test.

    My question is – I am able to record launching outlook 2012 step, but I have list of profiles configured to my outlook.

    So when i try to select the particular profile and login to outlook, this step is not being recorded by Coded UI test builder. when i try to generate the code, the test builder is crashing.

    I checked with "cross hair", i found that coded UI test builder is identifying this object correctly as Combo box.

    The Error is listed in next comment  which i can see is as below :

    could you please help me out on this.

  2. Microsoft.VisualStudio.TestTools.UITest.Extension.UITestException was unhandled  HResult=-2146233087

     Message=Error validating the UITest xml: '.', hexadecimal value 0x00, is an invalid character. Line 54, position 50.

     Source=Microsoft.VisualStudio.TestTools.UITest.Common

     BasicMessage=Error validating the UITest xml: '.', hexadecimal value 0x00, is an invalid character. Line 54, position 50.

     StackTrace:

          at Microsoft.VisualStudio.TestTools.UITest.Common.UITest.Validate(Stream stream)

          at Microsoft.VisualStudio.TestTools.UITest.Common.UITest.Create(Stream reader)

          at Microsoft.VisualStudio.TestTools.UITesting.CodedUITestServiceUtility.GetUITestFromXML(String uiTestString)

          at Microsoft.VisualStudio.TestTools.CodedUITest.Controls.CodedUITestBuilder.UITestBuilder.OnRecorderCodeGeneration(Object sender, CodeGenerationEventArgs codeGenEventArgs)

          at Microsoft.VisualStudio.TestTools.CodedUITest.Controls.RecorderUI.RecorderGUIController.OnCodeGenerationEvent(Object sender, CodeGenerationEventArgs eventArgs)

          at Microsoft.VisualStudio.TestTools.CodedUITest.Controls.CodedUITestBuilder.RecorderUI.GenerateRecordedCode(CodeGenerationEventArgs eventArgs)

          at Microsoft.VisualStudio.TestTools.CodedUITest.Controls.CodedUITestBuilder.GenerateCodeUI.generateCodeButton_Click(Object sender, RoutedEventArgs e)

          at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)

          at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)

          at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)

          at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)

          at System.Windows.Controls.Primitives.ButtonBase.OnClick()

          at System.Windows.Controls.Button.OnClick()

          at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)

          at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)

          at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)

  3. at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)

          at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)

          at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)

          at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)

          at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)

          at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)

          at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)

          at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)

          at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)

          at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)

          at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)

          at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)

          at System.Windows.Input.InputManager.ProcessStagingArea()

          at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)

          at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)

          at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)

          at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

          at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

          at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

          at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)

          at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)

          at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)

  4.  at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)

          at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)

          at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)

          at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)

          at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)

          at System.Windows.Threading.Dispatcher.Run()

          at System.Windows.Application.RunDispatcher(Object ignore)

          at System.Windows.Application.RunInternal(Window window)

          at System.Windows.Application.Run(Window window)

          at Microsoft.VisualStudio.TestTools.UITest.CodedUITest.CodedUITestBuilder.Program.Main(String[] args)

     InnerException: System.Xml.XmlException

          HResult=-2146232000

          Message='.', hexadecimal value 0x00, is an invalid character. Line 54, position 50.

          Source=System.Xml

          LineNumber=54

          LinePosition=50

          SourceUri=""

          StackTrace:

               at System.Xml.XmlTextReaderImpl.Throw(Exception e)

               at System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)

               at System.Xml.XmlTextReaderImpl.Throw(Int32 pos, String res, String[] args)

               at System.Xml.XmlTextReaderImpl.ParseNumericCharRefInline(Int32 startPos, Boolean expand, StringBuilder internalSubsetBuilder, Int32& charCount, EntityType& entityType)

               at System.Xml.XmlTextReaderImpl.ParseCharRefInline(Int32 startPos, Int32& charCount, EntityType& entityType)

               at System.Xml.XmlTextReaderImpl.ParseText(Int32& startPos, Int32& endPos, Int32& outOrChars)

               at System.Xml.XmlTextReaderImpl.ParseText()

               at System.Xml.XmlTextReaderImpl.ParseElementContent()

               at System.Xml.XmlTextReaderImpl.Read()

               at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)

               at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)

               at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)

               at System.Xml.XmlDocument.Load(XmlReader reader)

               at Microsoft.VisualStudio.TestTools.UITest.Common.UITest.Validate(Stream stream)

          InnerException: