I have a problem with TestFX, and running in headless mode on my desktop PC with openjfx-monocle.
Everything was working fine in my first "hobby project" but now when doing this at work I ran into some problems with the main menu that we have.
So the main menu is built up of a MenuBar, which contains Menus and those contains menuItems. Link to image below.
The problem I ran into was when I wanted to open an About dialog, from the main window. This is done by clicking in the MenuBar on the Menu that say 'Help', which displays a dropdown list of menuItems and for the Help Menu we only have the 'About' option right now.
So to the actual problem. I get the error when trying to click on the 'About' MenuItem... so the 'Help' Menu is clickable.
The error I get is:
org.testfx.api.FxRobotException: the query "About" returned no nodes.
at org.testfx.api.FxRobot.queryVisibleNode(FxRobot.java:1107) at
org.testfx.api.FxRobot.pointOfVisibleNode(FxRobot.java:1076) at
org.testfx.api.FxRobot.clickOn(FxRobot.java:750) at
org.testfx.api.FxRobot.clickOn(FxRobot.java:60) at
se.compenayname.testfx.pages.AboutPage.openAboutDialogFromMain(AboutPage.java:46)
Now whats strange to me is that it works great for the next test that gets executed. So if I would create lets say an empty test, or a test which just does an assert for 1+1 = 2 and set it to run first then all tests would pass. - But I dont want to do that, something smells funny and I want to know what I am doing wrong.
Now are there anyone who have had this/similar problems before? or anyone that can help me out, and hopefully just point out some silly newbie misstakes that I've done and send me on my way :)
Additional information that you might need: OS: Windows 7. Editor: Eclipse. Gradle version: 3.3. JDK : 8u121.
The TestFX and Monocle dependencies in the build.gradle file are:
testCompile "org.testfx:testfx-core:4.0.+",
"org.testfx:testfx-junit:4.0.+"
testRuntime "org.testfx:openjfx-monocle:1.8.0_20"
I am note sure if anything else is needed, but I'll give this a try and post this. Apologies beforehand if I am missing something, or if I am unclear in any way.
The code I am running can be seen below.
public class AboutDialogTests extends TestFXBase{
private AboutPage aboutPage;
@Before
public void before() throws Exception {
aboutPage = new AboutPage(this);
}
@Test
public void verifyCopyrightText(){
aboutPage.openAboutDialogFromMain();
FxAssert.verifyThat(AboutDialogFXIDs.COPYRIGHTLABEL, (Label copyrightLabel) -> {
String text = copyrightLabel.getText();
return text.equals("Copyright © 1995-2017. CompanyName AB. All rights reserved.");
});
}
@Test
public void verifyCopyrightText2(){
aboutPage.openAboutDialogFromMain();
FxAssert.verifyThat(AboutDialogFXIDs.COPYRIGHTLABEL, (Label copyrightLabel) -> {
String text = copyrightLabel.getText();
return text.equals("Copyright © 1995-2017. CompanyName AB. All rights reserved.");
});
}
}
Here is my simple TestFXBase class:
public class TestFXBase extends ApplicationTest{
private Stage primaryStage;
/**
* Am always running in headless mode at the moment.
*/
static{
System.setProperty("java.awt.headless", "true");
System.setProperty("testfx.robot", "glass");
System.setProperty("testfx.headless", "true");
System.setProperty("prism.order", "sw");
System.setProperty("prism.text", "t2k");
}
@Override
public void start(Stage stage) throws Exception {
this.primaryStage = stage;
primaryStage.show();
}
@Before
public void beforeEachTest() throws Exception{
/*
* The following FxToolkit lines allow for indirectly performing
* ApplicationTest.launch(Main.class); and registering the primary stage
* in order to allow running multiple @Test in a single file
*/
FxToolkit.registerPrimaryStage();
// specifying which class to start the application with.
FxToolkit.setupApplication(Main.class);
}
/**
* Release any keys and mousebuttons that may be stuck so that it wont influence other tests.
* @throws TimeoutException
*/
@After
public void afterEachTest() throws TimeoutException{
FxToolkit.hideStage();
release(new KeyCode[]{});
release(new MouseButton[]{});
}
public Stage getPrimaryStage() {
return primaryStage;
}
}
And here is the AboutPage class:
public class AboutPage{
private final TestFXBase base;
public AboutPage(TestFXBase fxBase) {
this.base = fxBase;
}
/**
* Navigate through the main menu and open the 'About' dialog.
*/
public void openAboutDialogFromMain() {
base.clickOn("Help").clickOn("About", Motion.VERTICAL_FIRST, MouseButton.PRIMARY);
// The lines below does not work at all when trying to click on a menu / menuitem.
//base.clickOn(MainMenuFXIDs.MAINMENUHELP);
//base.clickOn(MainMenuFXIDs.HELPMENUITEMABOUT);
}
public void closeAboutDialog() {
base.clickOn(AboutDialogFXIDs.CLOSEBUTTON);
}
}