How to get a HTML table row with Capybara
Asked Answered
S

2

10

I am trying to scan rows in a HTML table using partial href xpath and perform further tests with that row's other column values.

  <div id = "blah">
  <table>
    <tr>
      <td><a href="afile?key=HONDA">link</a></td>
      <td>29 33 485</td>
      <td>45.2934,00 EUR</td>
    </tr>
    <tr>
      <td><a href="afile?key=HONDA">link</a></td>
      <td>22 93 485</td>
      <td>38.336.934,123 EUR</td>
    </tr>
    <tr>
      <td><a href="afile?key=something_else">link</a></td>
      <td>394 27 3844</td>
      <td>3.485,2839 EUR</td>
    </tr>    
  </table>
  </div>

In cucumber-jvm step definition, I performed this much easily like below (I am more comfortable using Ruby)

@Given("^if there are...$")
public void if_there_are...() throws Throwable {
            ...
            ...
           baseTable = driver.findElement(By.id("blah"));
           tblRows = baseTable.findElements(By.tagName("tr"));

        for(WebElement row : tblRows) {                                                 
            if (row.findElements(By.xpath(".//a[contains(@href,'key=HONDA')]")).size() > 0) {
                List<WebElement> col = row.findElements(By.tagName("td")); 
                tblData dummyThing = new tblData();
                dummyThing.col1 = col.get(0).getText();
                dummyThing.col2 = col.get(1).getText();
                dummyThing.col3 = col.get(2).getText();
                dummyThing.col4 = col.get(3).getText();
                dummyThings.add(dummyThing);
            }
        }

I am clueless here

page.find('#blah').all('tr').each { |row|
  # if row matches xpath then grab that complete row
  # so that other column values can be verified
  # I am clueless from here
  row.find('td').each do { |c|

  }
  page.find('#blah').all('tr').find(:xpath, ".//a[contains(@href,'key=HONDA')]").each { |r|
    #we got the row that matches xpath, let us do something
  }
}
Spirochete answered 11/12, 2013 at 17:33 Comment(0)
C
17

I think you are looking to do:

page.all('#blah tr').each do |tr|
  next unless tr.has_selector?('a[href*="HONDA"]')

  # Do stuff with trs that meet the href requirement
  puts tr.text
end
#=> link 29 33 485 45.2934,00 EUR
#=> link 22 93 485 38.336.934,123 EUR

This basically says to:

  1. Find all trs in the element with id 'blah'
  2. Iterate through each of the trs
  3. If the tr does not have a link that has a href containing HONDA, ignore it
  4. Otherwise, output the text of the row (that matches the criteria). You could do whatever you need with the tr here.

You could also use xpath to collapse the above into a single statement. However, I do not think it is as readable:

page.all(:xpath, '//div[@id="blah"]//tr[.//a[contains(@href, "HONDA")]]').each do |tr|
  # Do stuff with trs that meet the href requirement
  puts tr.text
end
#=> link 29 33 485 45.2934,00 EUR
#=> link 22 93 485 38.336.934,123 EUR

Here is an example of how to inspect each matching row's link url and column values:

page.all('#blah tr').each do |tr|
  next unless tr.has_selector?('a[href*="HONDA"]')

  # Do stuff with trs that meet the href requirement
  href = tr.find('a')['href']
  column_value_1 = tr.all('td')[1].text
  column_value_2 = tr.all('td')[2].text

  puts href, column_value_1, column_value_2
end
#=> file:///C:/Scripts/Misc/Programming/Capybara/afile?key=HONDA
#=> 29 33 485
#=> 45.2934,00 EUR
#=> file:///C:/Scripts/Misc/Programming/Capybara/afile?key=HONDA
#=> 22 93 485
#=> 38.336.934,123 EUR
Chrisman answered 11/12, 2013 at 18:13 Comment(5)
Hi Ko, how do I get the href of the link that matches xpath. I need to check few things with the column values of matching row. So, how do I get that matching columns(values)?Spirochete
You can use the normal finders to inspect the tr. An example has been added.Chrisman
I get Selenium error Element not found in the cache - perhaps the page has changed since it was looked up.... But works if I simply puts tr.text removing tr.has_selector?....Spirochete
Using your xpath single statement solution is working and seem to be the solution for now. ThanksSpirochete
has_selector? will wait for the Capybara timeout, causing tests to perform really slowly when it doesn't match a row. Better to take an approach that looks for what you specifically want rather than checking whether something is there.Jaffna
J
0

If you need the table row, you could probably use something like the ancestor method:

anchors = page.all('#blah a[href*="HONDA"]')
trs = anchors.map { |anchor| anchor.ancestor('tr') }
Jaffna answered 27/6, 2022 at 18:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.