WinAppDriver icon indicating copy to clipboard operation
WinAppDriver copied to clipboard

Can't get selected item in WPF ComboBox when using ItemsSource with custom objects

Open craigbrown opened this issue 7 years ago • 5 comments

My WPF app has a ComboBox which allows users to select a currency from a list of options. The ComboBox items are custom Currency objects. These objects have a Name property, which is used as the text in the ComboBox items. The XAML looks like this:

<ComboBox x:Uid="CurrencyComboBox" ItemsSource="{Binding Currencies}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCurrency}" IsEnabled="{Binding IsCurrencyBoxEnabled}" />

When a separate radio button is clicked, this ComboBox is disabled and a particular currency is selected. I'm trying to write a test for this behaviour. Here's my test code so far:

[TestMethod]
public void DetailsTabWhenLloydsSelectedTest()
{
    Session.FindElementByAccessibilityId("MyRadioButton").Click();

    var currencyComboBox = Session.FindElementByAccessibilityId("CurrencyComboBox");

    Assert.IsFalse(currencyComboBox.Enabled);
    Assert.AreEqual(Currencies.PoundSterling, _viewModel.SelectedCurrency);
    Assert.AreEqual(Currencies.PoundSterling.Name, currencyComboBox.Text); // this fails

}

I can test the Enabled status fine, but I can't see any way of testing what text is being displayed in the ComboBox. This ComboBox test sample seems to suggest using the .Text property to get the displayed text. However, that seems to only work when the underlying items are strings. In my case, the value of this property is the string "My.Name.Space.Currency" even though the ComboBox itself correctly displays the string "Pound Sterling".

I believe this is a bug with the framework not allowing for the use of the DisplayMemberPath property on the ComboBox. But it's possible I'm missing something obvious, so any help would be appreciated.

craigbrown avatar Dec 18 '18 16:12 craigbrown

Hi @Frakur,

Can you try reporting back what Inspect.exe is able to pick up? Inspect should display all values that are being picked up the UIA accessibility tree - and if the desired string isn't there, then that would imply it isn't part of the UIA tree for WinAppDriver to automate against.

hassanuz avatar Dec 18 '18 23:12 hassanuz

The only thing I can see through Inspect is a property on the ComboBox called Selection.Selection with the value ""My.Name.Space.Currency" list item". But a call to currencyComboBox.GetAttribute("Selection.Selection") returns the following string:

A collection of MS.Internal.Mita.Foundation.UIObject instances in the set defined as A retrying Navigator around 'A list of items provided by an IEnumerable implementation matching Condition: 'True'.'..

I'm not quite sure what this means, but it does imply it's getting a different value to what Inspect is picking up. I was hoping I could do something like currencyComboBox.GetAttribute("Selection.Selection.Name") but that doesn't work.

There are also no child elements of the ComboBox, unless I first call two .Click() actions on the ComboBox (one to show the dropdown, one to close it again). Only then do the child elements appear in the UIA tree.

Using these child elements I am in fact able to access that string, albeit in a rather convoluted way:

var selectedCurrencyString = currencyComboBox.FindElementsByClassName("ListBoxItem").FirstOrDefault(i => i.Selected)?.FindElementByClassName("TextBlock").Text;

So my test method now looks like this, and it works:

[TestMethod]
public void DetailsTabWhenLloydsSelectedTest()
{
    var currencyComboBox = Session.FindElementByAccessibilityId("CurrencyComboBox");

    currencyComboBox.Click();
    currencyComboBox.Click();
    Session.FindElementByAccessibilityId("MyRadioButton").Click();

    var selectedCurrencyString = currencyComboBox.FindElementsByClassName("ListBoxItem").FirstOrDefault(i => i.Selected)?.FindElementByClassName("TextBlock").Text;

    Assert.IsFalse(currencyComboBox.Enabled);
    Assert.AreEqual(Currencies.PoundSterling, _viewModel.SelectedCurrency);
    Assert.AreEqual(Currencies.PoundSterling.Name, selectedCurrencyString);

}

So I guess my issue is solved, but I think there's a couple of problems with it.

  1. The fact that those two Click calls are necessary doesn't seem right. Without them, there's no way to get the string displayed in the ComboBox. Which means this UI testing tool can't test whether something is displayed in the UI - unless a particular type (a string) is used in the underlying implementation. I accept that WinAppDriver is just picking up what's in the UIA tree, but in that case there's an issue with the UIA tree.

  2. The amount of logic needed to just get the string displayed in the combo box seems way too complicated for such a simple thing.

Anyway I don't know if there's anything you can actually do about those things, so feel free to close this issue if not. Hopefully the solution above will help others.

craigbrown avatar Dec 19 '18 22:12 craigbrown

Just chiming in to say that I am encountering the same issue where GetAttribute("Selection.Selection") yields

A collection of MS.Internal.Mita.Foundation.UIObject instances in the set defined as A list of items provided by an IEnumerable implementation matching Condition: 'True'..

ChristoWolf avatar Mar 06 '24 06:03 ChristoWolf

I'm pretty sure this tool isn't being updated anymore, so I wouldn't expect to see this fixed.

craigbrown avatar Mar 08 '24 13:03 craigbrown

Yeah absolutely, I'm just documenting things in this repo nowadays.

ChristoWolf avatar Mar 08 '24 15:03 ChristoWolf