In another article, we demonstrated how to find table cells by header text in Qt applications. Here, we will show how to do the same thing in a Java AUT (Application Under Test).
Motivation
Finding table cells by header text leads to more readable tests. Furthermore, this is useful if the table columns are not always in a fixed order. With the AddressBook examples, it is possible to reorder the columns, in which case, test cases that refer directly to column numbers may be fragile.
Working with Swing JTable
At record-time, clicking on a table header results in an object being named in the Object Map, of type TableHeaderItemProxy
. Instances of this class contain a property called column
. This property will change if the table column is reordered. This makes it easy to identify columns by header text. You can see something like the image below from the Squish Spy by picking on one of the table headers and inspecting its properties in the Properties view.

The Object Map entries for TableHeaderItemProxy
look something like this:
surname_TableHeaderItemProxy = {"caption": "Surname", "type": "com.froglogic.squish.awt.TableHeaderItemProxy"}
phone_TableHeaderItemProxy = {"caption": "Phone", "type": "com.froglogic.squish.awt.TableHeaderItemProxy"}
Since the caption
property was set to something meaningful for these objects, the caption
gets picked up and used as part of the symbolic as well as the real names of each TableHeaderItemProxy
. These object map entries will work even if the columns are reordered.
However, when recording interactions with the table cells, these TableHeaderItemProxy
objects are not used. Instead, we see calls to mouseClick()
on the values returned by waitForObjectItem(names.JTable, "x/y")
, where the x,y values are fragile.
Given a header text, how can we obtain the column number? With the column
property and the scripted Object Map, we can write a helper function that looks like this:
def columnNumber(columnText):
columnHeaderViewName = {"caption": columnText, "type": "com.froglogic.squish.awt.TableHeaderItemProxy"}
return waitForObject(columnHeaderViewName).column
Next, we can write a function called tableCell()
, which uses this helper function and returns the desired cell, using waitForObjectItem()
.
def tableCell(columnName, rowNumber):
colNum = columnNumber(columnName)
return waitForObjectItem({"type": "javax.swing.JTable", "visible": True}, "{}/{}".format(rowNumber, colNum))
Here is an example test case that tests the functions against the Swing AddressBook example AUT.
def main():
startApplication("AddressBookSwing.jar")
activateItem(waitForObjectItem(names.address_Book_JMenuBar, "File"))
activateItem(waitForObjectItem(names.file_JMenu, "Open…"))
doubleClick(waitForObjectItem(names.open_JList, "MyAddresses.adr"), 78, 5, 0, Button.Button1)
# some interactions where columns may be reordered...
someTableCell = tableCell("Surname", 4)
test.compare(someTableCell.text, "Boardus")
Working with SWT Table
In SWT, mouse move events on the TableHeader
objects are not visible in the SWT event queue. This means the picker can’t pick them, and Squish can’t record interactions like drag and drop on them either. However, you can record a mouseClick() on them to add them to the Object Map, and with the use of Application Objects and tree navigation, it is always possible to find and inspect these objects in question.
The SWTTable
has a columnorder
property that can be used to determine the current order of the columns, in case they were reordered. To map from column text to current column number, we first need an array of column texts in the original order. This helper function below, getOriginalOrder()
, generates that, and should be called once after the Table
is showing all of its columns in the original order.
originalColumns = []
def getOriginalOrder():
global originalColumns
originalColumns = []
table = waitForObject({"type": "org.eclipse.swt.widgets.Table"})
for i in range(0, table.getColumnCount()):
tc = table.getColumn(i)
originalColumns.append(tc.text)
Now we can implement SWT versions of columnNumber()
andtableCell()
that work like their Swing counterparts:
def columnNumber(columnName):
global originalColumns
origidx = originalColumns.index(columnName)
table = waitForObject({"type": "org.eclipse.swt.widgets.Table"})
return table.getColumnOrder().at(origidx)
def tableCell(columnName, rowNumber):
colNum = columnNumber(columnName)
return waitForObjectItem({"type": "org.eclipse.swt.widgets.Table", visible": True}, "{}/{}".format(rowNumber, colNum))
Conclusion
In the situation where columns are not in a fixed order (or even if they are fixed), using “named columns” can improve readability and stability in your test cases. This article gives you some ideas on how to achieve this in tests against your Java AUT.
The post Finding Table Cells by Header Text in Java Applications appeared first on froglogic.