Stepan Salin
Stepan Salin

Reputation: 179

selenium + capybara: find selector anywhere within element

Assume we have a <div class='whatever'> and somewhere deep inside there is an element <div class='inside-whatever'>

What i need is a way to access that particular inside-whatever-div using Capybara's and/or Selenium's methods.

Problem is, there is another <div class='inside-whatever'> on the page not inside <div class='whatever'>, so

within(:xpath,'//div[@class="whatever"]') do
  find(:xpath,'//div[@class="inside-whatever"])
end

returns an error basically saying that there are multiple inside-whatever divs on the page.

What works is to build the xpath from whatever like

'//div[@class="whatever"]/div/div[3]/div/div[5]'

but that is pure madness.

So, is there any better way to look for selector anywhere inside any given element without having to specify a direct path?

Upvotes: 3

Views: 1557

Answers (2)

Thomas Walpole
Thomas Walpole

Reputation: 49870

The real issue here is that you've fallen into the XPath // trap

find(:xpath,'//div[@class="inside-whatever"])

searches globally rather than from the context node. Instead you should get used to starting your XPaths with .// which will search from the current context node

within(:xpath,'.//div[@class="whatever"]') do
  find(:xpath,'.//div[@class="inside-whatever"])
end

and do what you expect. This is mentioned in the Capybara README - https://github.com/teamcapybara/capybara#beware-the-xpath--trap

Note: CSS selectors don't have this issue and for most elements people are selecting read cleaner, which is why Capybara defaults to the :css selector

within('div.whatever') do
  find('div.inside-whatever")
end

Upvotes: 2

Granitosaurus
Granitosaurus

Reputation: 21406

You can merge your xpaths like this:

//div[@class="whatever"]//div[@class="inside-whatever"]

Upvotes: 2

Related Questions