1

Given the following (generic) dynamic HTML structure:

<ol id="myOrderedList">
    <li id="someGuidICantPredict">
        <span data-serial="someData1">someData1</span>
        <span data-manufacturer="someDataB1">someDataB1</span>
    </li>
    //(repeated many times with different data)
</ol>

How do I find the following:

Find the <li> where the spans match by CssSelector for both data-serial and data-manufacturer?

I know how to do this for one or the other span tag thusly:

By.CssSelector($"#olCurrentTanks li span[data-serial={serial1}]")

or

By.CssSelector($"#olCurrentTanks li span[data-manufacturer={manufacturer1}]")

But I don't know how to find the parent <li> element where both spans match. Meaning I need to get the IWebElement listItem where the both span's data attributes match the corresponding data which I can predict.

Edit: Difficulty: Okay to use x-path to get the li parent but not to find the spans.

user4593252
  • 3,496
  • 6
  • 29
  • 55
  • Look here, css doesn't have the capability to look up element based on its children elements - https://stackoverflow.com/questions/4220327/css-selector-element-with-a-given-child. Even in your sample where you successfully matched based on one element, you were matching the `span`, not the `li` you were after. xpath is the way to go for anything more complex in the DOM. – Todor Minakov Apr 05 '19 at 05:38
  • Are you trying to say that "CSS can't find a parent"? Because that's certainly true. But we're not 100% working in CSS. We're working with what amounts to a modified query selector format that can include all kinds of interesting things because it's selenium :) – user4593252 Apr 05 '19 at 17:00
  • :) yes, and xpath has a solid place in my heart at least :) I was just commenting re: your original intent, to accomplish that with a css, not really possible. – Todor Minakov Apr 05 '19 at 17:18
  • I was trying to limit xpath simply because if I wrap those controls in, say, a div, the xpath changes and my tests break. The less fragile it is, the happier I am :) – user4593252 Apr 05 '19 at 17:26

1 Answers1

1

With you can get li element with specific spans children:

//li[./span[@data-serial="someData1"] and ./span[@data-manufacturer="someDataB1"]]

Selector below will give all li elements as a list for FindElements and single first one for FindElement:

By.XPath("//li[./span[@data-serial='someData1'] and ./span[@data-manufacturer='someDataB1']]")

Code examples:

IList<IWebElement> allMyLi = driver.FindElements(By.XPath($"//li[./span[@data-serial='{serial1}'] and ./span[@data-manufacturer='{manufacturer1}']]"));

foreach (var myLi in allMyLi)
{
    IWebElement serial = myLi.FindElement(By.CssSelector($"span[data-serial={serial1}]"));
    IWebElement manufacturer = myLi.FindElement(By.CssSelector($"span[data-manufacturer={manufacturer1}]"));

    Console.WriteLine("serial, manufacturer: {0}, {1}", serial.Text, manufacturer.Text);
}
Sers
  • 12,047
  • 2
  • 12
  • 31
  • As long as the Xpath doesn't require other DOM structures except the ol and li, this *might* work. But I need to know how to do a By.XPath("xpath1 && xpath2") because the By.XPath parameter is a single string. Or is that literally the string? – user4593252 Apr 04 '19 at 20:16
  • why you need `xpath1 && xpath2`? what is your goal, can you clarify. – Sers Apr 04 '19 at 20:27
  • This was what I was looking for: By.XPath($"//li[./span[@data-serial='{serialNumber}'] and ./span[@data-manufacturer='{manufacturer}']]") Your answer got me there so I'm calling it as the right one. The reason I need it this way is that the list items are inside a jquery ui selectable with a remove feature. I need to check to see if the item that was removed is actually gone. The only way to predictably check that is for the serial number AND manufacturer spans to be gone along with parent list item as both count as a complex primary key. Thank you! – user4593252 Apr 04 '19 at 20:34