Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguous match using nth-child capybara

Tags:

html

capybara

I am trying to test that sorting works on an app I am testing. I have added 2 entries 'a' and 'b'. I wish to test that a appear before b. Html is as follows:

<ul id="attendee-list" class="bars">
<div>
    <li id="attendee-812202" class="bar border link attendee">
    <a class="expandable clearfix" href="#!/person/812202/">
</div>
     <div class="description">
     <p class="title">a</p>
     <p class="subtitle"></p>
     <p class="subtitle"></p>
</div>
</a>
</li>
</div>
<div>
     <li id="attendee-812206" class="bar border link attendee">
     <a class="expandable clearfix" href="#!/person/812206/">
     <div class="description">
     <p class="title">b</p>
<p class="subtitle"></p>
<p class="subtitle"></p>
</div>
</a>
</li>
</div>
</ul>

So what I have tried is the following:

  find("ul.bars li:nth-child(1) a div.description p.title").should have_content("a")
  find("ul.bars li:nth-child(2) a div.description p.title").should have_content("b")

However I get an ambiguous match error. Does anyone know if I am doing anything wrong here or perhaps an alternative method to verify?

like image 288
user1523236 Avatar asked Jul 29 '13 18:07

user1523236


1 Answers

Problem

The problem is the li:nth-child(1). This says to find an li that is the first child of its parent. Since each li is wrapped in a div, both li elements are first children - ie both of the titles are returned by selector ul.bars li:nth-child(1) a div.description p.title (hence the ambiguous match).

Solution 1 - Find All

I think the easiest solution is to use the css-selector to return all titles and then use Capybara to check the first and second ones.

# Get all titles
titles = page.all("ul.bars li a div.description p.title")

# Make sure that the first and second have the correct content
titles[0].should have_content("a")
titles[1].should have_content("b")

Solution 2 - Xpath

An alternative solution, if you do not want to get all (perhaps there are too many on the page), is to try xpath. It is not very pretty, but you can do:

page.find(:xpath, '(//ul[@class="bars"]/div/li/a/div[@class="description"]/p[@class="title"])[1]').should have_content("a")
page.find(:xpath, '(//ul[@class="bars"]/div/li/a/div[@class="description"]/p[@class="title"])[2]').should have_content("b")
like image 59
Justin Ko Avatar answered Sep 22 '22 16:09

Justin Ko