Abbreviated component paths in wicket tester

Wicket tester combined with Mockito is fantastic for unit testing your web application. However, developing the tests is harder than it should be because you have to refer to components by their path rather than their id.

For example, to clock the OK button on a page, I need something like:

tester.executeAjaxEvent(“border:form:pagetitlecontainer:ok”. “onclick”);

i.e. instead of “ok”, I must refer to the button by its full path “border:form:pagetitlecontainer:ok”. This seems tedious – if I know that I only have one component on the page with the id “ok”, why can’t I just use “ok”. Wicket tester should notice that the component is not available and traverse the component hierarchy for it. If its ambiguous then it can complain, but if not, then it should be OK.

To get around this limitation, we override the getComponentFromLastRenderedPage method of the WicketTester class as follows:

[sourcecode language=”java”]
@Override
public Component getComponentFromLastRenderedPage(final String path) {
// first check if we can find the component with the specified path – if not, check if its an abbreviated path
String fullPath = lookupPath(getLastRenderedPage(), path);
if (fullPath == null)
return null;

return super.getComponentFromLastRenderedPage(fullPath);
}

public String lookupPath(final MarkupContainer markupContainer, final String path) {
// try to look it up directly
if (markupContainer.get(path) != null)
return path;

// if that fails, traverse the component hierarchy looking for it
final List candidates = new ArrayList();
markupContainer.visitChildren(new IVisitor() {
private static final long serialVersionUID = 1L;

Set visited = new HashSet();

@Override
public Object component(Component c) {
if (!visited.contains(c)) {
visited.add(c);

if (c.getId().equals(path))
candidates.add(c);
}
return IVisitor.CONTINUE_TRAVERSAL;
}
});
// if its unambiguous, then return the full path
if (candidates.isEmpty()) {
fail(“path: ‘” + path + “‘ not found for ” +
Classes.simpleName(markupContainer.getClass()));
return null;
} else if (candidates.size() == 1) {
String pathToContainer = markupContainer.getPath();
String pathToComponent = candidates.get(0).getPath();
return pathToComponent.replaceFirst(pathToContainer + “:”, “”);
} else {
String message = “path: ‘” + path + “‘ is ambiguous for ” + Classes.simpleName(markupContainer.getClass()) + “. Possible candidates are: “;
for (Component c : candidates) {
message += “[” + c.getPath() + “]”;
}
fail(message);
return null;
}
}
[/sourcecode]

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.