Headless UI Testing with TestFX and JavaFX 8

JavaFX is a great UI toolkit. TestFX is a great library for testing the user interfaces written in JavaFX. Writing graphical tests with TestFX is simple and fast, but one challenge remains when you build your software using a headless build machine: how can you perform your UI tests in headless mode during your build?

Luckily, JavaFX 8 Update 20 will contain Monocle, which should allow us to run these headless tests.

First analysis using the latest beta of JDK 8u20 indicates that these tests are feasible, but require some changes in the TestFX library. We used a simple standalone JavaFX application for which we wrote a basic TestFX test class. We ran this test using the following command line options:

-Dglass.platform=Monocle
-Dmonocle.platform=Headless
-Dprism.order=sw

Unfortunately, this was not enough to make the test work. So we took a deeper look at the inner workings of TestFX and found that a working solution required the following changes:

  1. refactor a part of the TestFX code such that different implementations of the org.loadui.testfx.framework.robot.ScreenRobot interface can be used. This allowed us to make test use an other robot implementation, in this case an adapter for MonocleRobot. The current TestFX implementation relies on java.awt.Robot, which uses the system event queue to move the system cursor. This, of course, does not integrate with Monocle in headless mode.
  2. implement a ScreenRobot adapter for MonocleRobot. MonocleRobot is in internal package and thus not available via public API. In order to obtain an instance of this class, we had to call:
    Platform.runLater(new Runnable() {
       @Override
       public void run() {
          robot = com.sun.glass.ui.Application.GetApplication().createRobot();
       }
    });
    

This setup gave us a green test eventually. :-)

A Combined LineChart and TableView Widget in JavaFX

(enlarge to see more details)

This video shows a widget for displaying three characteristics (velocity vs. distance) in a LineChart node and a tabbed TableView node. The two nodes provide different views on the same data.

The widget comes with the following features:

  • hovering over a data point in the chart will show a popup with the x and y values.
  • selecting a data point in the chart will select the corresponding data item in the table view and vice versa.
  • when a data item was edited in the table view, the chart will update immediately.
  • three colour pickers allow for changing the line colours in the chart.
  • import and export data from sources like CSV, Excel, HDF5 (to be done).

These features were implemented using JavaFX bindings, events, animations, and CSS styling.

A Graph Editor in JavaFX

Another thing we’ve been working on is going to see the light of day soon: a graph editor for JavaFX. The current beta version provides the following main features:

  • create draggable, resizable nodes and connections between them
  • add multiple input or output connectors to a node
  • create joints inside a connection
  • add custom skins for nodes, connections, connectors, and joints
  • enhanced user experience through comprehensive styling during drag-and-drop actions

Internally, we use an EMF model to represent the UI objects and their state. The model is in sync with the UI at all times.

Here’s a short video of our current development version:

Using FXForm2 with EMF Models

Based on these considerations from July, we gave FXForm2 a shot for generating forms from EMF models. It worked quite smoothly after we wrote the factories that defined how the custom data types used in our models should be displayed.

We found a few things that are worth noting:

  1. Using Java Bean Validation
    In order to validate our EMF models using the Java Bean Validation API (JSR-303) that comes with FXForm2, we wrote wrapper classes for those model elements that we wanted to add constraints to. We decided to not touch the generated code.
  2. Using another validation implementationFXForm2 can use any implementation of JSR-303. Using the Hibernate implementation is suggested on the FXForm2 website, but we found it easy to supply our own implementation based on EMF’s validation features such as the Diagnostician class.
  3. Validation philosophies
    When you enter an invalid value into a field, FXForm2 won’t update the corresponding model attribute. The value you see in the form differs from the value in the model. The model thus always has a valid state.EMF validation typically works in a different way: you start the validation operation only after all model values were set. This allows for invalid states of the model.
  4. Dynamic beans
    An open issue
    seems to be (as least for us) the handling of a String-to-String Map attribute inside an EMF bean class that stores user-supplied key-value pairs which should be displayed as regular attributes of the bean. Antoine suggested a solution based on a custom control (with a factory and a skin), but it comes with a different visual appearance for the user-defined attributes. This is work in progress.