Search through Grid and Click Empty Div

Trying to loop through a grid and find the cell, which is a div, for the row / column:
PL-Planning documentation
Duration

What’s wrong with keyword? How does one do this?
– I tried quite a few times to upload more images but I keep getting errors.

String planning = 'PL-Planning documentation'

String duration = 'Duration'

CustomKeywords.'reusableComponents.webTable.ClickElementPropertyByTextIdentifierAndColName'('grid1', planning, duration)
@Keyword
	public void ClickElementPropertyByTextIdentifierAndColName(String tableCalssName, String RowTextIdentifier, String ColumnName){

		int columnIndex = 0;

		WebUI.verifyTextPresent(RowTextIdentifier, false, FailureHandling.OPTIONAL)

		// driver obj.
		WebDriver driver = DriverFactory.getWebDriver()

		//locate table'
		WebElement Table = driver.findElement(By.className(tableCalssName.trim()))


		//To locate rows of table it will Capture all the rows available in the table '
		List<WebElement> Rows = Table.findElements(By.tagName('span'))

		//print row counts
		println('No. of rows: ' + Rows.size())

		////Loop will execute for all the rows of the table'
		table: for (int i = 0; i < Rows.size(); i++) {

			//To locate columns(cells) of that specific row'
			List<WebElement> Cols = Rows.get(i).findElements(By.tagName('span'))

			// for each column in a row
			for (int j = 0; j < Cols.size(); j++) {

				println (Cols.get(j).getText())

				if (Cols.get(j).getText().equalsIgnoreCase(ColumnName)) {

					columnIndex = j;
				}

				//Verifying the expected text in the each cell'

				if (Cols.get(j).getText().equalsIgnoreCase(RowTextIdentifier)) {

					// click on link in a row if row name matches
					Cols.get(columnIndex).findElement(By.tagName('div')).click()

					break table
				}
			}
		}
	}

Grid Image

Row HTML

We may not be able to assist too much because we can’t see beneath your div of “slick-cell 12 r2…”, however, you may be able to achieve a web-table-like list by using the list of divs. I assume you want the third div, so I collect elements down to that level. You will have to get the specific element you want from that level down to the “span” you want (I assume).

// driver obj.
WebDriver driver = DriverFactory.getWebDriver()

//locate rows 
List<WebElement> rows = driver.findElements(By.xpath('//div[contains(@class,"ui-widget-content slick-row")]/div[3]'))

//print row counts
println('No. of rows: ' + rows.size())

////Loop will execute for all the rows of the table'
table: 
for (int i = 0; i < rows.size(); i++) {

So I would read down to a desired row and then down to the div? I don’t quite understand how this works versus a table. Thanks!

Row and Target HTML

Column HTML

Maybe it’s just my limited view of what you have shown, but I don’t see the table tag. And with the table tag, there may be a thead and tbody tag, which I also don’t see. I just see a LOT of div tags. That’s why I referred to it as table-like. You can still collect the web elements into a List and move through them as rows and columns. The only difference is how you collect the elements.

So reviewing your images, I see that I am down too low to start. But you perhaps can use the idea to collect the “Rows” and then move to the “Columns”.

Just curious, is any part of the cell’s id tag stable? Can you just collect the grid’s Schedule_Duration cells?

List<WebElement> rows = driver.findElements(By.xpath('//div[contains(@id,"SCHEDULE_DURATION")]'))

No, you’re right. There aren’t any table tags; it’s a grid with a ton of divs.

Also, the row with the text I need to find is in a different pane than the cell I need to select. So the div for the row is nested under the slick pane left and the cell is nested under the slick pane right.

And, alas, no the cell tag is not stable. The tag changes when you select the row, and becomes and input when you double click.

FWIW, I have learned the program has a lot of deprecated code so if this can’t be done easily… I’m not shocked.

This is definitely doable. As you’ve stated, you essentially have 2 problems to solve:

1.) Find the index of the column with a given column name.
2.) Find the index of the row with some text.

Once you have these, you can target the cell you want with the row/column indices.

Lets try to tackle these individually:

1.) Find the index of the column with a given column name:

You need to do 2 things to solve this problem. First, get a list of the column names, and second, get the index of a column with a given name. I would probably put these in their own Custom Keywords, as there are probably other times where you’d want to use them:

@Keyword
public List<String> getColumnNames() {
    WebDriver driver = DriverFactory.getWebDriver();
    List<WebElement> elements = driver.findElements(By.xpath("//div[contains(@class, 'slick-headerrow')]//span[contains(@class, 'slick-column-name')]"));
    List<String> columnNames = new ArrayList<String>();
    for (WebElement element : elements) {
        columnNames.add(element.getAttribute("textContent"));
    }
    return columnNames;
}

@Keyword
public int getColumnIndex(String columnName) {
    return getColumnNames.indexOf(columnName) + 1;
}

2.) Find the index of the row with some text.

For this one, the standard approach is to loop through all rows visible in the table, checking if the row contains some text, and finding its index. From this you have the row index you want, then you can check the value of the cell in this row and the column index you found in part 1 above. Again, you could have separate keywords here, one to find the index of a row with some text, and another to click a cell based on a row/column index:

@Keyword
public int getRowIndex(String rowTextIdentifier) {
    WebDriver driver = DriverFactory.getWebDriver();
    List<WebElement> elements = driver.findElements(By.xpath("//div[contains(@class, 'slick-row')]"));
    for(int i = 1; i <= elements.size(); i++) {
        if(elements.getAttribute("textContent").contains(rowTextIdentifier)) {
            return i;
        }
    }
    // return -1 if text isn't found:
    return -1;
}

@Keyword
public void clickCell(int rowIndex, int columnIndex) {
    WebDriver driver = DriverFactory.getWebDriver();
    WebElement cell = driver.findElement(By.xpath("((//div[contains(@class, 'slick-row')])[" + rowIndex + "]//div[contains(@class, 'slick-cell')])[" + columnIndex + "]"));
    cell.click();
}

Putting it all together:

In your script, you can now do this:

int rowIndex = getRowIndex("PL-Planning documentation");
int columnIndex = getColumnIndex("Duration");
clickCell(rowIndex, columnIndex);

I’m not expecting everything above to work on the first try, we will likely need to make adjustments, but the general approach should hopefully be a little clearer now. Let me know how it goes :slight_smile: