For example, for the page below, there is a ListView to display the rows. In each row the user can input a value into "v" and click the submit button. Then the total value of the rows will be displayed at the end of the page:
<html> <body> <table> <tr wicket:id="eachRow"> <td> <form wicket:id="f"> <input wicket:id="v" type="text"> <input wicket:id="ok" type="submit"> </form> </td> </tr> </table> <span wicket:id="container"> <span wicket:id="total">333</span>. </span> </body> </html>
To locate, say, the "total" <span>, use a locator wicket=//total with Selenium, meaning to search deep any level into the document root element (<html>) for an HTML element with wicket:id="total":
@Test public class PageExtractedByWicketIdsTest { public void testWicketLocator() { WicketSelenium ws = WebPageTestContext.getWicketSelenium(); ws.openBookmarkablePage(...); ... assert ws.getText(new ByWicketIdPath("//total")).equals("0"); } }
If you use wicket=/total instead, it will only search the immediate children of the <html> element, which will not work here as the <span> is many levels deep inside <html>.
How to input something into, say, the "v" text field in the first row (<tr>)? First, you locate the first <tr> with wicket=//eachRow. As there are many rows, it is better to explicitly write wicket=//eachRow[0]. Then you can search inside the <tr> for "v" with wicket=//eachRow[0]//v. It is similar for the other rows:
@Test public class PageExtractedByWicketIdsTest { public void testWicketLocator() { WicketSelenium ws = WebPageTestContext.getWicketSelenium(); ws.openBookmarkablePage(...); assert ws.getValue(new ByWicketIdPath("//eachRow[0]//v")).equals("3"); assert ws.getValue(new ByWicketIdPath("//eachRow[1]//v")).equals("2"); assert ws.getValue(new ByWicketIdPath("//eachRow[2]//v")).equals("8"); assert ws.getText(new ByWicketIdPath("//total")).equals("13"); WebElement v1 = ws.findWicketElement("//eachRow[1]//v"); v1.clear(); // clear the existing value first v1.sendKeys("5"); // input "5" WebElement ok = ws.findWicketElement("//eachRow[1]//ok"); ok.click(); ws.waitUntilAjaxDone(); assert ws.getText(new ByWicketIdPath("//total")).equals("16"); } }
When you specify an index like //eachRow[index], the search is done in a breadth first manner. It means that even if you have embedded loops like:
<html> <body> <table> <tr wicket:id="eachRow"> <td> <table> <tr wicket:id="eachRow"> <td>...</td> </tr> </table> </td> </tr> </table> </body> </html>
Conceptually they will be numbered like below. Therefore, it is very easy to locate, say, the 2nd row with //eachRow[2]. It will work no matter how many sub-rows there are in the 0th or 1st row. To locate, say, the 0th row in the 2nd row, use //eachRow[2]//eachRow[0].
<html> <body> <table> <tr> <== //eachRow[0] <td> <table> <tr> <td>...</td> </tr> <tr> <td>...</td> </tr> ... </table> </td> </tr> <tr> <== //eachRow[1] <td> <table> <tr> <td>...</td> </tr> <tr> <td>...</td> </tr> ... </table> </td> </tr> <tr> <== //eachRow[2] <td> <table> <tr> <td>...</td> </tr> <tr> <td>...</td> </tr> ... </table> </td> </tr> </table> </body> </html>