Home > OS >  Selenium: Looping through IWebElements consistently gives me the wrong element
Selenium: Looping through IWebElements consistently gives me the wrong element

Time:08-20

This has been driving me bonkers for days. I did finally get it working, but I want to know why everything I tried prior is not working.

I can't post my full HTML as it is too long, but I do have an xpath that pulls a list of locations. The HTML includes 5 locations, here is the html I pull out for each location into a list of IWebElements, this is just one location, to show what each 'loc' IWebElement is. I'm trying to ultimately get the 'ANAHEIM, CA 92805' from the span tag nested in the p tag:

<div  data-bind="visible: !missingService() || isSelected(), with: $root.locationLookup[Entity.EntityCode]">
                        <div  data-bind=" css: {match: isMatch(), nonmatch: !isMatch(), 'toggle-closed': !isSelected() }">
                            <h3  data-bind="click: $root.selectEntity.bind($data, Entity.EntityCode),css: { 'toggle-visible' : isSelected() }">
                                <span  data-bind="text: $index()   1, attr: { title: getPinTitle() }, css: {preferred: isMatch() &amp;&amp; !isOWFMatch(), 'alternate-marker': !isMatch() &amp;&amp; !isOWFMatch(), 'owfleet-marker': isOWFMatch() }" aria-hidden="true" title="Available">1</span>
                                <span data-bind="text: Entity.Name">U-HAUL MOVING &amp; STORAGE AT ANAHEIM BLVD</span>
                                <span data-bind="visible: missingService()" style="float: right; display: none;"><i data-tooltip="" style="color:red;"  data-selector="tooltip-l70lja6w5" aria-describedby="tooltip-l70lja6w5" title=""></i></span>
                            </h3>
                            <div style="display: none;" data-bind="visible: isSelected()">
                                <p>
                                    <span data-bind="text: Entity.Address">626 S ANAHEIM BL</span><br>
                                    <span data-bind="text: Entity.City   ', '   Entity.State   ' '   Entity.ZipCode">ANAHEIM, CA 92805</span><br>
                                    <i data-bind="text: Entity.Distance   ' mile(s)'">0.5 mile(s)</i>
                                </p>
                                <div >
                                    <div >
                                        <ul  style="margin: 0">
                                            <li>
                                                <a tabindex="-1" href="/secure/CSFRewriteConsole1/(S(2RwHZU)/Misc/GetDirections/715058" data-bind="attr: {href: '/secure/CSFRewriteConsole1/(S(2RwHZU)/Misc/GetDirections/-9999999'.replace('-9999999', Entity.EntityCode) }" target="_blank">
                                                    <i ></i>Directions
                                                </a>
                                            </li>
                                            <li>
                                                <a tabindex="-1" href="/secure/CSFRewriteConsole1/(S(2RwHZU)/Misc/RedirectToCrossContact/715058" data-bind="attr: {href: '/secure/CSFRewriteConsole1/(S(2RwHZU)/Misc/RedirectToCrossContact/-9999999'.replace('-9999999', Entity.EntityCode) }" target="_blank">
                                                    <i ></i>Cross Contact (<span data-bind="text: Entity.EntityCode">715058</span>)
                                                </a>
                                            </li>
                                                <li>
                                                    <a tabindex="-1" href="/secure/CSFRewriteConsole1/(S(2RwHZU)/Misc/RedirectToESL/715058" data-bind="attr: {href: '/secure/CSFRewriteConsole1/(S(2RwHZU)/Misc/RedirectToESL/-9999999'.replace('-9999999', Entity.EntityCode) }" target="_blank">
                                                        <i ></i>View ESL
                                                    </a>
                                                </li>
                                        </ul>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

What I need is the span with the city/state/zip of the location, so I can pass it into a service and get lat/lon for it.

Here is the relevent C# code that is driving me bonkers:

IReadOnlyList<IWebElement> locationsCollection = Driver.FindElements(By.XPath("//div[@class='location'][not (@style='display: none;')]"));

//...

            int mainLocationIndex = 0;  // index starts at 0 here for C# entityinfo object, but must be  1'd where used against selenium elements, like location index
            // Loop through each location listed
            foreach (IWebElement loc in locationsCollection)  //this loc element is the weird thing
            {
                //...
                string locText = loc.GetAttribute("innerHTML");  //on inspection shows correct iteration of loc, on each iteration of the loc loop
                IWebElement locationCityStateZip = loc.FindElement(By.XPath("//h3//following-sibling::div/p"));  //should pull the whole p element of each loc, but...
                string locCityStateString = locationCityStateZip.GetAttribute("innerHTML"); //always shows first iteration of loc's city/state/zip <p> tag, despite locText being correct above 
                //...
                mainLocationIndex  ;
            }

I've had my manager look at this, they are stumped as I am. I have found a workaround, but I would really like to know why this is not working. Here is what I finally got to work:

                IList<IWebElement> spans = loc.FindElements(By.TagName("span"));  //get all spans in loc
                string span4 = spans[4].GetAttribute("innerHTML");  //city, state  zip span is correct here

If anyone has any insight, I would appreciate being let in on the secret. My brain hurts.

CodePudding user response:

The issue is the XPath here

loc.FindElement(By.XPath("//h3//following-sibling::div/p"));

You are using an XPath to search from an existing element, loc. CSS selectors in this instance will work fine but for XPaths, you must start it with a ., e.g.

loc.FindElement(By.XPath(".//h3//following-sibling::div/p"));
                          ^ add this "."

This tells the XPath to start at a relative position.

I would write this code as

ReadOnlyCollection<IWebElement> locations = driver.FindElements(By.CssSelector("div.location span[data-bind^='text: Entity.City']"));
foreach (IWebElement location in locations)
{
    string locCityStateString = location.GetAttribute("innerHTML");
    ...
}

This gets you what you want with much less code.

  • Related