Pulling information from a table

Hello,

I am struggling with how to identify and pull information from a table. From my research, there doesn’t appear to be a consistent solution, since each table would be created in different ways. Here is a sample of how the table looks:

Any help would be greatly appreciated.

Your question is similar to the following:

See what you can gleam from it.

Can you provide an example of how your code will work with this? I need to be able to pull a specific row and determine if the values are correct. Thanks!

You have only shown the top level of your table so you will have to work on the table contents, however, start with something like:

import org.openqa.selenium.WebDriver
import org.openqa.selenium.By
import org.openqa.selenium.WebElement
import com.kms.katalon.core.webui.driver.DriverFactory

WebDriver driver = DriverFactory.getWebDriver()
List<WebElement> myList = driver.findElements(By.xpath('//mat-row[@class="mat-row ng-star-inserted")]//*[*you will have to determine this area*]'))
int element_count = myList.size();
println ("Found count of " + element_count.toString());
WebUI.comment("Found count of " + element_count.toString())

loop:
for(int cnt = 0; cnt < element_count; cnt++)  {
// your comparison to some element contents here 
}

Here is the rest of a table row down to the Full Name column:

What would the rest of the xpath be? Also, is this code populating the values in an array? If so, how would I access a value in it?

I chose to use the role attribute because it was less typing but check out if the role attribute is the same in all mat-cell or if perhaps it is the class that may be. Anyways, like I had above:

import org.openqa.selenium.WebDriver import org.openqa.selenium.By 
import org.openqa.selenium.WebElement 
import com.kms.katalon.core.webui.driver.DriverFactory 

WebDriver driver = DriverFactory.getWebDriver();
List<WebElement> myList = driver.findElements(By.xpath('//mat-row[@class="mat-row ng-star-inserted")]/mat-cell[@role="gridcell"]')) 
int element_count = myList.size(); 
println ("Found count of " + element_count.toString()); 
WebUI.comment("Found count of " + element_count.toString()) 

loop: for(int cnt = 0; cnt < element_count; cnt++) { 
// get access to a value in the array
  if (WebUI.verifyMatch(myList[cnt].getText(),  **yourText**, false)) {
       exit loop;
  }
}

I have yourText as a String (such as Patient2, Conductor) that you could match, or if you want to get the text then just use myList[cnt].getText().

Note there is white space surrounding the String so you may have to match with Regular Expression using WebUI.verifyMatch(myList[cnt].getText(), '\\s'+ yourText+'\\s', true) or WebUI.verifyMatch(myList[cnt].getText(), yourText+'\\s', true))

Sorry for the late response. I do appreciate the assistance, since I am not as familiar with the coding aspects of this tool. I tried running the code against a table in the application. Here is the code:

WebDriver driver = DriverFactory.getWebDriver();
List myList = driver.findElements(By.xpath(’//mat-row[@class=“mat-row cdk-row ng-star-inserted”)]/mat-cell[@role=“gridcell”]’))
int element_count = myList.size();
println ("Found count of " + element_count.toString());
WebUI.comment("Found count of " + element_count.toString())

loop: for(int cnt = 0; cnt < element_count; cnt++) {
WebUI.comment(myList[cnt])
}

I am receiving the following error:

=============== ROOT CAUSE =====================

For trouble shooting, please visit: https://docs.katalon.com/katalon-studio/docs/troubleshoot-common-execution-exceptions-web-test.html

10-27-2020 09:15:09 AM Test Cases/Drug Dashboard/Settings/My Team/Test

Elapsed time: 23.183s

Test Cases/Drug Dashboard/Settings/My Team/Test FAILED.
Reason:
org.openqa.selenium.InvalidSelectorException: invalid selector: Unable to locate an element with the xpath expression //mat-row[@class=“mat-row cdk-row ng-star-inserted”)]/mat-cell[@role=“gridcell”] because of the following error:
SyntaxError: Failed to execute ‘evaluate’ on ‘Document’: The string ‘//mat-row[@class=“mat-row cdk-row ng-star-inserted”)]/mat-cell[@role=“gridcell”]’ is not a valid XPath expression.
(Session info: chrome=86.0.4240.111)
For documentation on this error, please visit: https://www.seleniumhq.org/exceptions/invalid_selector_exception.html
Build info: version: ‘3.141.59’, revision: ‘e82be7d358’, time: ‘2018-11-14T08:25:53’
System info: host: ‘DESKTOP-C7224O5’, ip: ‘192.168.1.129’, os.name: ‘Windows 10’, os.arch: ‘amd64’, os.version: ‘10.0’, java.version: ‘1.8.0_181’
Driver info: com.kms.katalon.selenium.driver.CChromeDriver
Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 86.0.4240.111, chrome: {chromedriverVersion: 85.0.4183.87 (cd6713ebf92fa…, userDataDir: C:\Users\TIMHAT~1\AppData\L…}, goog:chromeOptions: {debuggerAddress: localhost:51278}, javascriptEnabled: true, networkConnectionEnabled: false, pageLoadStrategy: normal, platform: WINDOWS, platformName: WINDOWS, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:virtualAuthenticators: true}
Session ID: b36ef28662d6c8f8963fa264f4ffd6ab
*** Element info: {Using=xpath, value=//mat-row[@class=“mat-row cdk-row ng-star-inserted”)]/mat-cell[@role=“gridcell”]}
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
at com.kms.katalon.selenium.driver.CChromeDriver.execute(CChromeDriver.java:19)
at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:353)
at org.openqa.selenium.remote.RemoteWebDriver.findElementsByXPath(RemoteWebDriver.java:432)
at org.openqa.selenium.By$ByXPath.findElements(By.java:348)
at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:311)
at org.openqa.selenium.support.events.EventFiringWebDriver.lambda$new$1(EventFiringWebDriver.java:105)
at com.sun.proxy.$Proxy9.findElements(Unknown Source)
at org.openqa.selenium.support.events.EventFiringWebDriver.findElements(EventFiringWebDriver.java:182)
at org.openqa.selenium.WebDriver$findElements.call(Unknown Source)
at Test.run(Test:32)
at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
at com.kms.katalon.core.main.ScriptEngine.runScriptAsRawText(ScriptEngine.java:119)
at com.kms.katalon.core.main.TestCaseExecutor.runScript(TestCaseExecutor.java:339)
at com.kms.katalon.core.main.TestCaseExecutor.doExecute(TestCaseExecutor.java:330)
at com.kms.katalon.core.main.TestCaseExecutor.processExecutionPhase(TestCaseExecutor.java:309)
at com.kms.katalon.core.main.TestCaseExecutor.accessMainPhase(TestCaseExecutor.java:301)
at com.kms.katalon.core.main.TestCaseExecutor.execute(TestCaseExecutor.java:235)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:114)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:105)
at com.kms.katalon.core.main.TestCaseMain$runTestCase$0.call(Unknown Source)
at TempTestCase1603808106750.run(TempTestCase1603808106750.groovy:25)

Here is the code for the table:

image

As you state in your first post, each table would be created in different ways, so you likely cannot use one xpath for all. I also assume you want information from one of the td tags. This is so similar to the link I supplied earlier:

Each of your columns (td tags) has a unique class name, like Practice, Occupation, Status and Action. So you could just create an xpath to move to that specific column to get your information if that be your intention or we can be generic.

WebDriver driver = DriverFactory.getWebDriver();
WebElement myTable = driver.findElement(By.xpath('//table/tbody')) 

List<WebElement> rows_in_table = myTable.findElements(By.tagName('tr'))
'To calculate no of rows In table'
int rows_count = rows_in_table.size()

Loop:
for (int row = 0; row < rows_count; row++) {
   'To locate columns(cells) of that specific row'
   List<WebElement> columns_in_row = rows_in_table.get(row).findElements(By.tagName('td'))
 
   'To calculate no of columns(cells) In that specific row'
   int columns_count = columns_in_row.size()

   for (int column = 0; column < columns_count; column++) {
      'It will retrieve text from each cell'
      String celltext = columns_in_row.get(column).getText();

     'Checking if cell text is matching with the expected value'
     if (celltext == ExpectedValue) {
       columns_in_row.get(column).click();
      break Loop;
     }
   }
}

If you just want to get all the information that is in the columns, you would not need the final for loop, but could set the index specifically with column values and get the text such as:

 WebUI.verifyMatch(columns_in_row.get(0).getText(), 'ExpectedName', false)
 WebUI.verifyMatch(columns_in_row.get(1).getText(), 'ExpectedPractice', false)
 WebUI.verifyMatch(columns_in_row.get(2).getText(), 'ExpectedOccupation', false)
 WebUI.verifyMatch(columns_in_row.get(3).getText(), 'ExpectedStatus', false)
 WebUI.verifyMatch(columns_in_row.get(4).getText(), 'ExpectedAction', false)

It looks like it’s having an issue with the webdriver statement, but not sure.

=============== ROOT CAUSE =====================

For trouble shooting, please visit: https://docs.katalon.com/katalon-studio/docs/troubleshoot-common-execution-exceptions-web-test.html

10-27-2020 02:52:23 PM Test Cases/Drug Dashboard/Settings/My Team/Test

Elapsed time: 23.342s

Test Cases/Drug Dashboard/Settings/My Team/Test FAILED.
Reason:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object ‘[[[CChromeDriver: chrome on WINDOWS (46cfe650e29dd643fb829ce75f49e83a)] -> xpath: //table/tbody]]’ with class ‘java.util.ArrayList’ to class ‘org.openqa.selenium.WebElement’ due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: org.openqa.selenium.WebElement(org.openqa.selenium.support.events.EventFiringWebDriver$EventFiringWebElement)
at Test.run(Test:32)
at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
at com.kms.katalon.core.main.ScriptEngine.runScriptAsRawText(ScriptEngine.java:119)
at com.kms.katalon.core.main.TestCaseExecutor.runScript(TestCaseExecutor.java:339)
at com.kms.katalon.core.main.TestCaseExecutor.doExecute(TestCaseExecutor.java:330)
at com.kms.katalon.core.main.TestCaseExecutor.processExecutionPhase(TestCaseExecutor.java:309)
at com.kms.katalon.core.main.TestCaseExecutor.accessMainPhase(TestCaseExecutor.java:301)
at com.kms.katalon.core.main.TestCaseExecutor.execute(TestCaseExecutor.java:235)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:114)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:105)
at com.kms.katalon.core.main.TestCaseMain$runTestCase$0.call(Unknown Source)
at TempTestCase1603828341514.run(TempTestCase1603828341514.groovy:25)

My error. I had a plural when I shouldn’t. I made a change in the following statement:

WebElement myTable = driver.findElement(By.xpath('//table/tbody'))

First off, a HUGE thanks for your help on this table. I’m starting to learn a bit more about how this works. I now have the ability to match on a specific row value and then check the values on that row.

I’m trying to apply what I’ve learned so far on this other table, which I originally posted above:

The code I have written based on what you have assisted with is here:

WebDriver driver = DriverFactory.getWebDriver();
WebElement myTable = driver.findElement(By.xpath(‘//mat-table[@role=“grid”]’))

List rows_in_table = myTable.findElements(By.xpath(‘//mat-row[@role=“row”]’))
‘To calculate no of rows In table’
int rows_count = rows_in_table.size()

Loop:
for (int row = 0; row < rows_count; row++) {
‘To locate columns(cells) of that specific row’
List columns_in_row = rows_in_table.get(row).findElements(By.xpath(‘/mat-header-cell[@role=“gridcell”]’))

int column = 0;
String celltext = ‘\s’+columns_in_row.get(column).getText()+‘\s’;

if (celltext == “Patient4, Conductor”) {
WebUI.verifyMatch(columns_in_row.get(0).getText(), ‘Patient4, Conductor’, false)
WebUI.verifyMatch(columns_in_row.get(1).getText(), ‘13/08/2020’, false)
WebUI.verifyMatch(columns_in_row.get(2).getText(), ‘24/08/2020’, false)
WebUI.verifyMatch(columns_in_row.get(3).getText(), ‘26/08/2020 *’, false)
WebUI.verifyMatch(columns_in_row.get(4).getText(), ‘Scheduling Needed’, false)
WebUI.verifyMatch(columns_in_row.get(5).getText(), ‘The Infusion Clinic’, false)
WebUI.verifyMatch(columns_in_row.get(6).getText(), ‘PPMS’, false)
break Loop;
}
column++
}

I’m really not sure that I have the xpath correct, but the code seems to be dropping into the for loop correctly. However, it fails on the String celltext line, which I am using to try to match on.

Here is the error I am receiving:

=============== ROOT CAUSE =====================

For trouble shooting, please visit: https://docs.katalon.com/katalon-studio/docs/troubleshoot-common-execution-exceptions-web-test.html

10-28-2020 11:07:31 AM Test Cases/Drug Dashboard/Settings/My Team/Patient List Table

Elapsed time: 47.982s

Test Cases/Drug Dashboard/Settings/My Team/Patient List Table FAILED.
Reason:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java_util_List$get$1.call(Unknown Source)
at Patient List Table.run(Patient List Table:42)
at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
at com.kms.katalon.core.main.ScriptEngine.runScriptAsRawText(ScriptEngine.java:119)
at com.kms.katalon.core.main.TestCaseExecutor.runScript(TestCaseExecutor.java:339)
at com.kms.katalon.core.main.TestCaseExecutor.doExecute(TestCaseExecutor.java:330)
at com.kms.katalon.core.main.TestCaseExecutor.processExecutionPhase(TestCaseExecutor.java:309)
at com.kms.katalon.core.main.TestCaseExecutor.accessMainPhase(TestCaseExecutor.java:301)
at com.kms.katalon.core.main.TestCaseExecutor.execute(TestCaseExecutor.java:235)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:114)
at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:105)
at com.kms.katalon.core.main.TestCaseMain$runTestCase$0.call(Unknown Source)
at TempTestCase1603901249104.run(TempTestCase1603901249104.groovy:25)

Any help would be greatly appreciated. I feel like its close, but I’m not used to this syntax.

Actually, I just noticed a flaw in the code from my other table, which I have corrected now. It was working completely by accident. However, in working with this other table, I have it running now, but it only seems to compare the patient name in the first row and never increment to the other rows. Here is the code:

WebDriver driver = DriverFactory.getWebDriver();
WebElement myTable = driver.findElement(By.xpath(’//mat-table[@role=“grid”]’))

List rows_in_table = myTable.findElements(By.xpath(’//mat-row[@role=“row”]’))
‘To calculate no of rows In table’
int rows_count = rows_in_table.size()

Loop:
for (int row = 0; row < rows_count; row++) {
‘To locate columns(cells) of that specific row’
List columns_in_row = rows_in_table.get(row).findElements(By.xpath(’//mat-row[@role=“row”]/mat-cell[@role=“gridcell”]’))

String celltext = ‘\s’+columns_in_row.get(0).getText()+’\s’;
println(celltext)

if (celltext == “Patient4, Conductor”) {
WebUI.verifyMatch(columns_in_row.get(0).getText(), ‘Patient4, Conductor’, false)
WebUI.verifyMatch(columns_in_row.get(1).getText(), ‘13/08/2020’, false)
WebUI.verifyMatch(columns_in_row.get(2).getText(), ‘24/08/2020’, false)
WebUI.verifyMatch(columns_in_row.get(3).getText(), ‘26/08/2020 *’, false)
WebUI.verifyMatch(columns_in_row.get(4).getText(), ‘Scheduling Needed’, false)
WebUI.verifyMatch(columns_in_row.get(5).getText(), ‘The Infusion Clinic’, false)
WebUI.verifyMatch(columns_in_row.get(6).getText(), ‘PPMS’, false)
break Loop;
}
}

@tim.hatcher As you found out, your variable column did not have a top limit set and was going over its limit.

I can only make assumption based on the information you are giving, however, do you have other conditions that are in your loop such as below: (note to remove the break from the loop)

if (celltext == "Patient4, Conductor") {
    WebUI.verifyMatch(columns_in_row.get(0).getText(), 'Patient4, Conductor', false)
    WebUI.verifyMatch(columns_in_row.get(1).getText(), '13/08/2020', false)
    WebUI.verifyMatch(columns_in_row.get(2).getText(), '24/08/2020', false)
    WebUI.verifyMatch(columns_in_row.get(3).getText(), '26/08/2020 .*', true)
    WebUI.verifyMatch(columns_in_row.get(4).getText(), 'Scheduling Needed', false)
    WebUI.verifyMatch(columns_in_row.get(5).getText(), '\\sThe Infusion Clinic\\s', true)
    WebUI.verifyMatch(columns_in_row.get(6).getText(), 'PPMS', false)
}
if (celltext == "Patient5, Actor") {
   WebUI.verifyMatch(columns_in_row.get(0).getText(), 'Patient5, Actor', false)
   WebUI.verifyMatch(columns_in_row.get(1).getText(), '14/08/2020', false)
   WebUI.verifyMatch(columns_in_row.get(2).getText(), '14/08/2020', false)
   WebUI.verifyMatch(columns_in_row.get(3).getText(), '26/08/2020 .*', true)
   WebUI.verifyMatch(columns_in_row.get(4).getText(), 'Scheduling Done', false)
   WebUI.verifyMatch(columns_in_row.get(5).getText(), '\\sThe Bachelor\\s', true)
   WebUI.verifyMatch(columns_in_row.get(6).getText(), 'RRSP', false)
}
etc. etc.

You can also implement this as a Case block:

No, no other conditions are in the loops. When I run the program, it looks like it is only getting the first row of the table. I have a println for the variable celltext, which then prints out “Conductor, Patient4” ten times. It looks like the loop is not advancing to the next row? When it drops into the loop, it should his the “If” statement if the celltext matches the name I am looking for and then run the verifymatch statements.

How about trying the below change?

List<WebElement> columns_in_row = rows_in_table.get(row).findElements(By.xpath('//mat-cell[@role="gridcell"]'))

I added your change. I think I see what is happening, though not sure how to explain it, much less fix it.

Here is the simplified code:

WebDriver driver = DriverFactory.getWebDriver();
WebElement myTable = driver.findElement(By.xpath(’//mat-table[@role=“grid”]’))

List rows_in_table = myTable.findElements(By.xpath(’//mat-row[@role=“row”]’))
‘To calculate no of rows In table’
int rows_count = rows_in_table.size()

Loop:
for (int row = 0; row < rows_count; row++) {
‘To locate columns(cells) of that specific row’
List columns_in_row = rows_in_table.get(row).findElements(By.xpath(’//mat-cell[@role=“gridcell”]’))

println(columns_in_row.get(0).getText())

}

This loop is looping through all the cells in a row BEFORE it drops to the next row. The println statement is printing the name of the patient in the first row until the loop ends. I am honestly not sure how to loop through a row, instead of going to the next cell, then determine if the patient name matches the one I am looking for, and then process that rows information.

Well, it isn’t pretty, but it works! Thanks again for all your help!

WebDriver driver = DriverFactory.getWebDriver();
WebElement myTable = driver.findElement(By.xpath(’//mat-table[@role=“grid”]’))

List cells_in_table = myTable.findElements(By.xpath(’//mat-cell[@role=“gridcell”]’))
‘To calculate no of rows In table’
int cell_count = cells_in_table.size()

Loop:
for (int cell = 0; cell < cell_count; cell++) {

String celltext = cells_in_table.get(cell).getText().trim();

if (celltext == “Patient4, Conductor”) {
WebUI.verifyMatch(cells_in_table.get(cell).getText(), ‘Patient4, Conductor’, false)
WebUI.verifyMatch(cells_in_table.get(cell+1).getText(), ‘13/08/2020’, false)
WebUI.verifyMatch(cells_in_table.get(cell+2).getText(), ‘24/08/2020’, false)
WebUI.verifyMatch(cells_in_table.get(cell+3).getText(), ‘26/08/2020 *’, false)
WebUI.verifyMatch(cells_in_table.get(cell+4).getText(), ‘Scheduling Needed’, false)
WebUI.verifyMatch(cells_in_table.get(cell+5).getText(), ‘The Infusion Clinic’, false)
WebUI.verifyMatch(cells_in_table.get(cell+6).getText(), ‘PPMS’, false)
cells_in_table.get(cell).click();
break Loop;
}
}