FeaturesPluginsDocs & SupportCommunityPartners

Jellytools Frequently Asked Questions - NetBeans 3.6

Last update: January 27, 2003

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 Explorer Window 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:

  // gets tree from Filesystems tab of the Explorer Window
  JTreeOperator treeOperator = ExplorerOperator.invoke().repositoryTab().tree();
  // finds folder "jellytools" under filesystem "jellytools/src"
  FolderNode folderNode = new FolderNode(treeOperator, "jellytools/src|org|netbeans|jellytools");
  // selects the node
  folderNode.select();

  // finds child node under jellytools folder
  Node node = new Node(folderNode, "nodes|FolderNode");
  // selects the node
  node.select();

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();
  // or
  Node rootNode = new ExplorerOperator().repositoryTab().getRootNode();

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 distinguish 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 method nodes under class FolderNode located in above example:

  // finds parent node
  Node methodsNode = new Node(node, "Class FolderNode|Methods");
  // locate twelfth node under parent node
  Node newFromTemplateNode1 = new Node(methodsNode, 11);
  newFromTemplateNode1.select();
  // locate thirteenth node under parent node
  Node newFromTemplateNode2 = new Node(methodsNode, 12);
  newFromTemplateNode2.select();


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

A: It 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 retype 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 basic implementation which enables to set if 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("Explorer.*");
  new JFrameOperator("E.plorer.*");



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

A: Check if you run your test case by Internal Execution. Go to the Explorer window and show properties window of your test class. On the Execution tab select "Internal Execution" from Executor property's combo. UI test based on jelly can work only if it is executed in the same JVM as tested application because it allows to use all Java API for test purposes.



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 opened.



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 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 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 "Search Filesystems..." under Edit menu in NetBeans IDE, we need to call org.netbeans.jellytools.Bundle.getString("org.netbeans.modules.search.Bundle", "TEXT_ACTION_REPOSITORY_SEARCH"). 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 parameter -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.



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 debug test cases in IDE?

A: See step by step guide.



 
 
Companion
Projects:
MySQL Database Server   Open JDK: an Open SourceJDK   GlassFish Community: an Open Source Application Server    Mobile & Embedded Community    Open Solaris   java.net - The Source for Java Technology Collaboration   Virtual Box - full virtualizer  Open ESB - The Open Enterprise Service Bus Powered by