Search code examples
pythonunit-testingseleniumxpathsplinter

xpath for obtaining button within a row


I writing some browser tests with splinter and have a page with clearly-defined rows containing their own titles, buttons, etc. Something like:

enter image description here

In my particular case, I can obtain a single row as follows:

row = lambda title: browser.find_by_xpath("//div[@class='my-row'][contains(., '{0}')]".format(title))

row1 = row('Row 1')
row2 = row('Row 2')

Then, with this lamba:

button = lambda elmt, text: elmt.find_by_xpath("//a[@class='btn'][contains(.,'{0}')]".format(text))

I could hone in on the correct regular button or say something like:

assert button(row1, 'Special button')
assert not button(row2, 'Special button')

But when I call the button lambda, it returns buttons from other rows.

From my understanding, finding by xpath via this lamba says, "starting from elmt, look for buttons nested within elmt that contain the given text". Since I am getting stuff from other rows not nested within the current one, though, what am I missing here?

What is wrong with my xpath?


Solution

  • XPath expressions that start with // start at the root node of the document, and select nodes regardless of their position in the document. The current context node of such an expression, for example

    //div
    

    has no effect on the result set that is returned. To search the // (descendant-or-self::) axis starting from the context node, you need to use

    .//div
    

    In your case, this means changing

    button = lambda elmt, text: elmt.find_by_xpath("//a[@class='btn'][contains(.,'{0}')]".format(text))
    

    to

    button = lambda elmt, text: elmt.find_by_xpath(".//a[@class='btn'][contains(.,'{0}')]".format(text))
    

    (Caveat: That's all concerning the XPath expressions in your code, I cannot comment on the rest.)