JellyToolsFAQ

Contents


Q: How to invoke a popup or main menu item? (Actions)

A: The recommended way how to invoke popup or main menu is through an Action or ActionNoBlock instance. Jellytools include bunch of predefined actions. They can be found in package org.netbeans.jellytools.actions and they are descendants either of Action for non blocking operations or of ActionNoBlock for operations which may block further execution by a modal dialog showing.
An action can be performed in "main menu", "popup", "shortcut" or "API" modes. By default it is performed in the first available mode because not every action is defined for all four modes. An example of usage can be:

        // performs in default mode
new CopyAction().perform();
// performs in "menu" mode
new CopyAction().performMenu();

It also possible to specify a node or component on which an action will be performed:

        // selects node first and then performs on it
new FindAction().perform(myNode);
// focuses component first and then performs action in "popup" mode
new FindAction().performPopup(myComponentOperator);

If an action is not predefined, you can create and use your own action.

        // invokes main menu item "Edit|Copy"
new Action("Edit|Copy", null).perform();
// invokes popup menu item "Copy" on given node
new Action(null, "Copy").perform(myNode);

// invokes main menu item "Edit|Find" (first selects given node)
new ActionNoBlock("Edit|Find", null).perform(myFolderNode);
// invoke popup menu item "Find" on given component
new ActionNoBlock(null, "Find").perform(myEditorOperator);

Additional details about actions can be found at the Writing Jelly Test Guide.

Q: What are nodes good for?

A: Nodes should help to easier testing of JTree's. The most frequent usage in IDE is in the Projects, Files or Services views but nodes can be used in any component which includes a JTree instance. Nodes are also used as parameters for action's performing.
In package org.netbeans.jellytools.nodes there can be found predefined specialized nodes for common objects in IDE. You can use them with combination of generic node instances as you like. Simple example looks like this:

        // finds "Source Packages" node under "My Project" in Projects view
SourcePackagesNode sourceNode = new SourcePackagesNode("My Project");
// the above stands for this line which uses generic Node class
//Node sourceNode = new Node(new ProjectsTabOperator().tree(), "My Project|Source Packages");
// finds sub node under given source packages node
Node node = new Node(sourceNode, "org.netbeans.jellytools.nodes|Node.java");
// get a property of the node
System.out.println(node.getText());
// perform an action on node
new OpenAction().performAPI(node);

Items in a node path are separated by "|" character and searching (exact match, case sensitivity) is driven by current string comparator. Root node must not be included in search path. To get root node instance you need to supply empty search path or use a getter method:

        Node rootNode = new Node(treeOperator, "").select();

Additional details about nodes can be found at the Writing Jelly Test Guide.

Q: How to distinguish nodes with the same display name?

A: Nodes with the same display name can be distinguished by their index under parent node. If the index is not permanent, it can be computed with help of parentNode.getChildren() method. Following example enables to access sixth or seventh node under parent node:

       // finds parent node
       Node parentNode = new Node(node, "My Parent");
       // locate sixth node under parent node
       Node node6 = new Node(parentNode, 5);
       node6.select();
       // locate seventh node under parent node
       Node node7 = new Node(parentNode, 6);
       node7.select();

Q: How to wait for a new nodes when JTree is re-generated after it is added? (tree re-generation)

A: If you use org.netbeans.jellytools.Node class, it is guaranteed that all nodes are ready before an attempt to access them. But it still might happen that you need to find a node but its tree is re-created after this node is added. In that case this code doesn't work:

        Node subChildNode = new Node(tree, "parent|child|subChild");

First you have to wait for presence of required node and then you can locate it in the tree hierarchy:

        try {
new Waiter(new Waitable() {
public Object actionProduced(Object parent) {
return new Node((Node)parent, "child").isChildPresent("subChild") ? Boolean.TRUE: null;
}
public String getDescription() {
return("Sub child present under child");
}
}).waitAction(parent);
} catch (InterruptedException e) {
throw new JemmyException("Interrupted.", e);
}
Node subChildNode = new Node(tree, "parent|child|subChild");

Q: How to separate menu items or tree nodes in paths parameters?

A: The default separator of menu items and tree node is "|" character.

Q: How to get instance of component from an operator?

A: In case you need to obtain instance of component from an operator, use method getSource() and cast to an appropriate class:

        JTree jTree = (JTree)treeOperator.getSource();

Q: How to change matching criteria? (String comparator)

A: By default all string comparison is done case insensitively and not exactly (substring match). To change criteria you need to set a new comparator. Comparator is an implementation of interface Operator.StringComparator. Operator.DefaultStringComparator is a basic implementation which enables to define whether substring match is used and case sensitivity. To set comparator for all forthcoming operations use static method setDefaultStringComparator(). Be careful. It has to be called before any operator is created. In other words, only newly created operators will use new comparator:

        // create exactly (full match) and case sensitively comparing comparator
Operator.DefaultStringComparator comparator = new Operator.DefaultStringComparator(true, true);
// store previously used comparator
Operator.StringComparator oldComparator = Operator.getDefaultStringComparator();
// set new comparator
Operator.setDefaultStringComparator(comparator);

// here every newly created operator will use new comparator
//....

// restore previous comparator
Operator.setDefaultStringComparator(oldComparator);

To set comparator only for a particular operator instance, you need to use method setComparator(). Once you have set comparator for operator instance, comparator is also propagated into newly created operators where this operator is supplied as parameter in a constructor.

        // set comparator for this instance
anOperator.setComparator(comparator);
// also this operator instance will have the same comparator set
JButtonOperator jButtonOperator = new JButtonOperator(anOperator);

In Jemmy documentation you can learn more about operators environment.

Q: Is it possible to use regular expressions?

A: Yes, it is! You only need to set org.netbeans.jemmy.util.RegExComparator as default and then you are able to use all valid regular expression patterns (see java.util.regex.Pattern javadoc for instance):

        RegExComparator regExComparator = new RegExComparator();
Operator.setDefaultStringComparator(regExComparator);

new JFrameOperator("NetBeans.*");
new JFrameOperator("Net.eans.*");

Q: My test doesn't find any component in IDE.

A: Check if your test runs in NetBeans Runtime Container. UI tests based on jelly can only work if they are executed in the same JVM as tested application because it allows to use all Java API for test purposes. More about this topic is here.

Q: Why use no block methods?

A: There exist so called "no block" methods. They have to be used when a modal dialog is opened as the result of an action. If we don't use "no block" method, test execution will be blocked until modal dialog is closed.

Q: Is it possible to redirect or turn output messages off?

A: Majority of messages is produced by Jemmy on which jelly is built. Jemmy uses three different outputs. To the trace output is sent as much information as it is known. To the error output only error messages. The golden output contains only time and environment independent messages which can be used for golden files test techniques. There exist JemmyProperties.setCurrentOutput() methods that enable to redirect these messages to specified PrintWriters. For example, JemmyProperties.setCurrentOutput(new TestOut(System.in, myOutPrintWriter, myErrPrintWriter, myGoldenPrintWriter));. As default all output is sent to standard output.
In order to suppress some kind of output messages you can use null as the destination of messages. To disable all output and error messages you need to call JemmyProperties.setCurrentOutput(TestOut.getNullOutput());.

Q: What is relation between jemmy and jelly?

A: Jemmy is a library which allows you to create automated tests of Java GUI application. It is NOT dependent on NetBeans IDE. Jelly is based on Jemmy and it is a library of components helping to write GUI tests of NetBeans IDE.

Q: How to detect a test failure?

A: A test case should consist of pairs of action and verification. It is possible to omit verification, if the next action depends on result of previous action. Actually, verification in that case is hidden because we are waiting for some object to make next action on it. If specified time expires, waiting fails and some JemmyException (extends RuntimeException) is thrown. This exception can be caught in our test case or it is propagated to a test harness in which the test case runs.
We can also throw exception ourselves, if we detect some unexpected result of an action. Or instead of exception we can use harness specific methods to signal a failure.
Golden files technique is also a possibility. You collect output to a specified file and at the end you compare its content to reference file. If files differ, test fails. This approach is supported usually by harness.

Q: How to localize test cases?

A: To identify components, jemmy and jelly use mainly window's titles, button's label and other strings bound with searched component. It is good practice to collect such strings in Bundle.properties files to enable their later localization. We can benefit from such approach and use strings directly from bundles. If there are not hard coded strings in our test cases, they will work on every locale to which tested product is translated. For example to get localized string for menu item "Copy" under Edit menu in NetBeans IDE, we need to call Bundle.getStringTrimmed("org.openide.actions.Bundle", "Copy"). We have to know location of Bundle.properties file in java hierarchy and key of searched string. NetBeans IDE contains support for easier investigation of string source. If you run IDE with parameters -nosplash -J-Dorg.openide.util.NbBundle.DEBUG=true, every string in IDE is followed by ordinal number of bundle file and line number of the key within that file. By the ordinal number you can seek bundle file origin in console output. Once you know path to bundle, you need to find this file within IDE sources or in IDE's jar files, open it and look at given line.
You can also use 'Resource bundle lookup' feature from jemmysupport module.

Q: What is the robot mode?

A: Robot mode is the mode of jelly in which GUI actions are done through java.awt.Robot. The Robot class generates native system input events. It is closer to user input but it is more fragile for debugging end execution.

Q: How to execute test cases in IDE?

A: Simply open test class in editor and use Run File (Shift+F6) or Test File (Ctrl+F6) action.

Q: How to debug test cases in IDE?

A: Simply open test class in editor and use Debug File (Ctrl+Shift+F5) or Debug Test File (Ctrl+Shift+F6) action.

Q: How to fix "Couldn't execl robot child process: Permission denied"?

A: On Unix it can happen that test fails because of "Couldn't execl robot child process: Permission denied" error when initialization of Robot. To resolve this issue you have to repair file permissions as stated in this contribution http://zzlinux.blogspot.com/2004/12/couldnt-execl-robot-child-process.html:

"execl" is a system call, So, the api was trying to run a native application to assume the controls of the keyboard and mouse. When jvm tries to create a child process to execute this function, it receive the message from OS (linux): "Permission Denied". Search for two files on directory jre/lib/i386: awt_robot and awt_robot_g. Then use "chmod x" on both files as root and the Robots will be created without error messages.

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo