Currently I'm digging into issues with TextField and default/cancel button. While testing a presumed fix with TestFX, I ran into a difference in event dispatch (?) that make the test fail while the application appears to be working.
Below is a very simplified version:
- just a simple ui, consisting of a textField inside a box, used in both Application/Test
- the textField has a (key-) handler that fires an actionEvent when a is pressed
- the textField has a action handler that consumes the actionEvent
- the (key-) handler checks whether the action was consumed (here: simple log, in real context the (key-) event must be consumed if the action is consumed)
The crucial part of the fix is to create the actionEvent with the textField as both source and target (to prevent copying the event into a new instance during dispatch):
ActionEvent action = new ActionEvent(field, field);
When running the app, this seems to be enough to make it work. When running the test, fails - the event is copied to another instance such that the event that was consumed is a different instance than the one that's passed around in the dispatch (can be seen only during debugging). Couldn't nail the exact point where/why that happens.
The question: is that difference expected, and if so why/where? Or what I'm doing wrong (a far from zero probability)?
To reproduce
- run app, press a: note the log stating that the fired actionEvent is consumed
- run test, note the log stating that the fired actionEvent is not consumed
The code:
public class ActionApp extends Application {
// create a simple ui - static because must be same for ActionTest
public static Parent createContent() {
TextField field = new TextField();
// some handler to fire an actionEvent
field.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
if (e.getCode() == KeyCode.A) {
ActionEvent action = new ActionEvent(field, field);
field.fireEvent(action);
LOG.info("action/consumed? " + action + action.isConsumed());
}
});
// another handler to consume the fired action
field.addEventHandler(ActionEvent.ACTION, e -> {
e.consume();
LOG.info("action received " + e + e.isConsumed());
});
VBox actionUI = new VBox(field);
return actionUI;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(ActionApp.class.getName());
}
The test:
public class ActionTest extends ApplicationTest {
/**
* Does not really test anything, just to see the output.
*/
@Test
public void testConsumeA() {
// sanity: focused to receive the key
verifyThat(".text-field", NodeMatchers.isFocused());
press(KeyCode.A);
}
@Override
public void start(Stage stage) {
Parent root = ActionApp.createContent();
Scene scene = new Scene(root, 100, 100);
stage.setScene(scene);
stage.show();
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(ActionTest.class.getName());
}
My environment is fx11 and TestFX from Oct 2018 on win10. FYI: Opened an issue in testFX