Hi Katalon community,
I want to locate a td element by the text inside; however the text is separated by i elements inside td element.
<td> "first"
<i></i>
"second"
<i></i>
"third"
</td>
There are multiple tags on the webpage. If I write //td[contains(text(),‘first’)], it locates all of them. If I write the xpath such that it include the texts “first”, “second” and “third”, it would locate the exact td element. I tried //td[contains(text(),‘first’)][contains(text(),‘second’)][contains(text(),‘third’)]
However, this xpath does not work. Is there a way to write the xpath that includes all the text?
Any help would be appreciated.
Thanks : D
//td[contains(text(),‘first’)][contains(text(),‘second’)][contains(text(),‘third’)]
I find this XPath is OK. This is not a problem.
I guess you have a problem somewhere else, other than XPath syntax, in your Test Case script. For example, you do not wait for the page to load before trying to find the <td>
element inside it.
Just use the ‘and’ operator:
//td[contains(text(),‘first’) and contains(text(),‘second’) and contains(text(),‘third’)]
hmm, for some reason, the ‘and’ operator that @Brandon_Hein suggested does not work. And the syntax suggested by @kazurayam also does not work. I tried copy and pasting both approaches and switching out the text.Maybe if I give more details; something can be found. I will also see if any of the devs in my company have any idea.
<td>Workflow <i class="icon-caret-right muted">::before</i> Record <i class="icon-caret-right muted">::before</i> New</td>
The XPath that @Brandon_Hein suggested is equivalent to the one I suggested. Both failed. Then it proves that you have a problem in your test case other than XPath. For example, you do not wait for the page to load before trying to find the <td>
element inside it. Do you do verifyElementPresent() in your test case? Please share the code of your test case.
Give this one a try:
//td[contains(normalize-space(), 'Workflow') and contains(normalize-space(), 'Record') and contains(normalize-space(), 'New')]
The idea here is to use the normalize-space() function as a predicate. This function considers not only the first text node found, but all child text nodes of the specified element.
Thanks @Brandon_Hein and @kazurayam! : D
The normalize-space approach worked for me
This is an interest post for me. It motivated me to study in depth how XPath functions text(), contains() and normalize-space() work.
I have made a project on Github.
The sample code is here: XPathWritingExample/Script1558585003703.groovy at master · kazurayam/XPathWritingExample · GitHub
This code emits the folloing output:
tdWithMixedContent is '<td>Workflow <i class="icon-caret-right muted">::before</i> Record <i class="icon-caret-right muted">::before</i> New</td>'
# XPath text() functions returns a NodeList when applied to an HTML Element with mixed content
'count(//td/text())' returns 3.0
'//td/text()[1]' returns 'Workflow '
'//td/text()[2]' returns ' Record '
'//td/text()[3]' returns ' New'
# XPath contains(nodelist,pattern) function silently chooses only the 1st node of the nodelist given as 1st argument
'//td[contains(text(), "Workflow")]' returns true
'//td[contains(text(), "Record")]' returns false !!!
'//td[contains(text(), "New")]' returns false !!!
# you can choose a node out of the nodelist returned by text()
'//td[contains(text()[1], "Workflow")]' returns true
'//td[contains(text()[2], "Record")]' returns true
'//td[contains(text()[3], "New")]' returns true
# normalize-space() function scans the descendent nodes of the target element recursively for text contents, concatinates them to a string, normalizes white space characters
'normalize-space(//td)' returns 'Workflow ::before Record ::before New'
# it is convenient to call contains() with normalize-space() as the 1st argument
'//td[contains(normalize-space(), "Workflow")]' returns true
'//td[contains(normalize-space(), "Record")]' returns true
'//td[contains(normalize-space(), "New")]' returns true
'//td[contains(normalize-space(), "Workflow") and contains(normalize-space(), "Record") and contains(normalize-space(), "New")]' returns true
'//td[contains(normalize-space(.), "Workflow")][contains(normalize-space(.), "Record")][contains(normalize-space(.), "New")]' returns true
2019-05-24 10:27:30.121 INFO c.k.katalon.core.main.TestCaseExecutor - END Test Cases/TC1
2 Likes