microsoft / WinAppDriver

Windows Application Driver
MIT License
3.7k stars 1.4k forks source link

FindElementsByXPath inexplicably searching too deep / need search depth constraints on other Find methods #1664

Open 0lks opened 2 years ago

0lks commented 2 years ago

I'm working with a DevExpress WinForms application in which there are forms containing comboboxes absolutely packed with ridiculously long lists of data. The user is of course not expected to scroll through these - instead they start typing the value into the input field. The combobox will filter the list according to user input and, eventually, when enough characters are typed in, displays the desired value at the top.

Be that as awkward as it may, that's what I'm working with. This requires me to be particularly careful about avoiding any sort of recursive searching within those comboboxes. If WinAppDriver ever enters one of those comboboxes when searching, it will always stall and time out. It is also impossible to pull page source when I have even one such combobox in view.

Because of these long lists I'm having problems with certain 'Find' functions which undesirably search too deep in the tree, eventually entering one of these comboboxes when I absolutely do not want them to do that. Consequently I am often limited in my options when getting references to certain elements positioned outside those comboboxes.

To illustrate, I have a tab control. There are six tabs total and two of them open views where each contains at least one combobox with a million list items. If the tab is not open then the contents are offloaded and do not exist in the tree. Therefore the contents pose a threat only when the tab is open.

When one of the tabs containing the long combobox is open, the tree looks something like this:

<TabControl> // Referenced as WindowsElement  
    <Pane> // Contains the elements of the opened tab  
        <Pane>  
            <Pane>  
                <Pane> 
                    <ComboBox> 
                        <List> // Long list - children need to be avoided in driver calls.
                            <ListItem>
                            <ListItem>
                            <ListItem>
                            ... // repeat 1 000 000 times
                        </List>
                    </ComboBox>
                </Pane> 
            </Pane> 
        </Pane> 
    </Pane>
    <TabItem>
    <TabItem>
    <TabItem>
    <TabItem>
    <TabItem>
    <TabItem>
</TabControl>

I am trying to collect the references to the TabItem elements by calling WindowsElement.FindElementsByXPath("/TabControl/TabItem/")

And it successfully collects the items I need, but only if the first Pane is NOT one of the aforementioned two tabs. The contents of any tab are loaded under that first Pane and if I have one of those two tabs open, it will contain the ComboBox with the List with too many listitems. I'm not expecting this XPath call to even reach that far down the hierarchy for these comboboxes to be a problem, but somehow this call still stalls and times out.

The only logical explanation I can come up with is that the call is somehow leading the driver into one these comboboxes and it stalls while recursively iterating through them. I don't understand why it would even go that deep in the tree though - isn't the expected behavior with that XPath that it should not search for elements beyond the level the TabItem elements are at?

I have tried to use other functions such as FindElementsByTag, but they present the same problem as there seems to be no way to control the max depth of the search.

Thanks

0lks commented 2 years ago

It does not seem to matter what XPath I use. I think an even likelier explanation is that the driver is attempting to construct the whole XML under that root element, before executing that XPath call. This means I can't use XPath in this situation at all. I am again quite limited in the tools available to me in these circumstances.

liljohnak commented 2 years ago

Have you tried AppiumWebElement.FindElementsByXPath("*/*") where the element is the application window. I have found this to be faster than the call from the driver level. Furthermore, no need to use the control type in your XPath it does not speed it up.

0lks commented 2 years ago

Thank you for the reply. I tried it, but there seems to be no improvement. As per Timotius's recommendations here I'm storing references to most of the elements I regularly need and I have a whole wrapper system for them, which works great. Therefore I don't need to search for any of my elements from the window or driver level. In the example I gave I already have the reference to the TabControl and I just need its immediate TabItem children, but I'm missing a method to get them without other descendants causing a performance drop.