简体   繁体   中英

Can't find element contains some text

There is a bit of the page:

 <label> <input type="checkbox"> </input> " some text" </label>

I need to find an element which contains "some text". If I use

WebElement().ByXPath("//div/label[contains(text(),'some text')]");

But this does not give results. Element could not be found.

But!! If I try get Attribute (InnerHTML, GetText, innerText) for such element with

    WebElement.ByXPath("//div/label").GetAttribute("InnerHTML"/"innerText");
   WebElement.ByXPath("//div/label").Text; 

There is the right result (WebElement.ByXPath("//div/label").Text=="some text")!

For this XPath elements:

WebElement().ByXPath("//div/label[contains(@innerHtml,'some text')]");
WebElement().ByXPath("//div/label[contains(@innerText,'some text')]");

It doesn't work too.

Why is this possible? Why I can't find element by unique text on the page?

your xpath seems correct, but I can't tell without looking at your page. Your example works just fine for this stackoverflow page:

//p[contains(text(), 'Why is this possible?')]

I know this works because I tested it with FireFox's FirePath extension. Try using this to test it: https://addons.mozilla.org/en-US/firefox/addon/firepath/

Probably due to the page not fully loading before the element has been displayed, when building selenium tests you will have errors that are not errors, just do to the inconsistency of browsers and speed. You can prepare for them by building stable code that plans for items that can not be found.

A wait function helps

public IWebElement WaitForElement(By element)
    {
            return new WebDriverWait(this.browser,
                TimeSpan.FromSeconds(10)).
                Until(ExpectedConditions.
                ElementIsVisible(element));
    }

You could also prepare by allowing your program to refresh the page if you think that is needed and attempt test again if it fails, ways of double checking.

For your xpath I always use, if they have no name or id

By.Xpath("//*[contains(text(), 'Some Text')]");

I'm not sure what is causing this issue, but I agree that sometimes there is one. I suggest you to try the following:

//div//label[contains(node(),'some text')]

Or, as redp suggested, you can go with * but be sure that you specify parent elements correctly in case your page has several labels with the same text:

//div//*[contains(node(),'some text')]

If memory serves, you can alco use contains(.,'some text') insted of contains(node(),'some text)' . Also, consider inspecting your element closely in inspector tools, looking at Properties tab with attention. And, remember that you can find your elements using search inside Inspector , this will save you a lot of time.

Please, update me if this helps you.

That should have a span tag around "some text". It is just bad html markup.

You can also use:

//label/text()[last()]
//label/text()[2]

It's true that the html isn't great practice, but it's around and people have to deal with it. I think what will help here is normalize-space() . Try this in a chrome console on a page that has that html:

$x(`//label[contains(normalize-space(), "some text")]`);

I think the above code breaks down into this:

  1. Find all label nodes
  2. For each of those nodes
    1. Get all the text nodes inside that node and its descendant nodes
    2. Combine their text
    3. Remove extra whitespace from the text in each text node
    4. If the exact string I want ("some text") is in there, add that label to the list of nodes to return.
  3. Return a list of all the nodes that had that text (or an empty list if none matched)

To get a bit more complicated, if I want to find the node that is the direct parent of a text node that has "some text" I can do this:

$x(`//label//text()[contains(normalize-space(), "some text")]/..`);

That gets tricky, though. For every text node that contains the given string, it gets the direct parent. It works fine for this because "some text" is all in one text node. In other situations it could trip someone up. For example, look at this html:

<label>
  <span> text </span>
  some other text
</label>

As a human, I can read "text some other text" so it seems like I should be able to find the parent of "text some". If I use the first method to look for a label with "text some" in it, this code will find that label just fine:

$x(`//label[contains(normalize-space(), "text some")]`);

That's because a combination of all the text nodes does have "text some" in it. I can't use the second method, though. For example, using this code on that html only gives me an empty list:

$x(`//label//text()[contains(normalize-space(), "text some")]/..`);

That is because when xpath looks in each individual text node, none of them has "text some" inside it. If I think about it, "text some" doesn't really have one direct parent. It sort of has two direct parents. xpath chooses to give no parents instead of both of them. Seems fair enough.

I haven't found any great explanations of normalize-space() and I don't know why it combines the text of all its descendant nodes. As far as why text() doesn't work, I found this answer from 2014:

text() is short for child::text() , and selects the text nodes that are immediate children of the label element. -- https://stackoverflow.com/a/26823289/14144258

It might still be right.

Also, I know this is an old question, but I ran into the same problem trying to troubleshoot my own code and it took ages to find a solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM