Search code examples
rubyselenium-webdrivercucumbercapybaracucumber-jvm

How to get a HTML table row with Capybara


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
  }
}

Solution

  • 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