5

I know how to locate div inside the button:

//button/div[contains(text(),'Save')]

I'd like to know is it possible to locate any button which contains div with text "Save" inside?

<button class="PinBetterSave__Button" data-test-id="PinBetterSaveButton"><div class="_w7 _0 _1 _2 _wa _36 _d _b _6">Save</div></button>
kjhughes
  • 106,133
  • 27
  • 181
  • 240
F. Vosnim
  • 476
  • 2
  • 8
  • 23

2 Answers2

5

You can try

//button[contains(div,'Save')]

to locate button with child div that contains specific text. To locate button with descendant div that contains specific text use

//button[contains(.//div,'Save')]
JaSON
  • 4,843
  • 2
  • 8
  • 15
  • **Warning:** There are [issues](https://stackoverflow.com/a/54224863/290085) with both of the provided XPaths. These problems are subtle, common mistakes and currently missed by OP, who accepted this answer, and by 5 up-voters, who blindly supported what is only superficially correct. – kjhughes May 04 '23 at 11:56
3

Issues with the other, currently accepted, answer: Careful, both XPaths in the other answer have problems:

  1. //button[contains(div,'Save')] works in this case, but be aware that it will fail when

    • The button contains a span or another or no element, rather than a div.
    • Other buttons exist with div elements whose string values contain the substring, "Save": "Save this", "Save that", "Jesus Saves", etc.
  2. //button[contains(.//div,'Save')] also works in this case, but be aware that it will fail if there are multiple div descendants and,

    • XPath 1.0: the Save div is not the first div.
    • XPath 2.0+: it is an error to pass a sequence of more than one item (div elements, in this case) as the first argument to contains().

Consider instead this XPath,

//button[normalize-space() = 'Save']

which will select button elements whose space-normalized string value is exactly "Save".

Or, if for substring testing:

//button[contains(., 'Save')]

See also

kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • Talking about "problems" :) Your warnings do have sense, however, suggested solutions don't really solves OP issue since `//button[normalize-space() = 'Save']` works only if the text content (ignoring starting and trailing spaces) of *button* (not its child *div*) is **equal to** (not **contains**) specific text and `//button[contains(., 'Save')]` also doesn't answer the question "How to locate any button which contains **div** with text 'Save' inside?" – JaSON May 05 '23 at 09:32
  • @JaSON: **Incorrect.** As I've explained in the referenced "See also" links, *contains* has two meanings, and OPs often confuse the two. Here, I've been very careful to provide solutions that cover the most likely needs: exact match, the first XPath) and substring containment (the second match). Anyone having trouble in this area is not looking specifically for a `div` child or descendant element; they're thrown off by how to select their target element based on its string value regardless of any possible additional markup. – kjhughes May 05 '23 at 12:41
  • Incorrect just because you think that if OP ask a question OP means not what exactly been asked but something else?:) And all those who search for the same also means something else... Interesting assumption, but IMO it's a road to nowhere:)) – JaSON May 05 '23 at 13:46
  • 1
    @JaSON: You've always received feedback well on the rare occasions that your answer isn't already perfect. That I've failed to convince you here must be a shortcoming in my explanation. If I think of a better way to explain it beyond what I've said here and in the linked answers, I'll try again. – kjhughes May 05 '23 at 15:19