How do you test dialogs, file save and open on TestFX?

4,152 views
Skip to first unread message

Ryan Gilera

unread,
Nov 22, 2014, 9:12:05 AM11/22/14
to testfx-...@googlegroups.com
Hi,

I am currently using TestFX 4.0.0-SNAPSHOT for my tests. I have a menu that can open and save json file FILE>OPEN and FILE>SAVE. How do direct the mouse click and move to the filechooser window? How do you also deal with dialogs, close window and click buttons on them? I am using ControlsFX 8.20.8. 

Here is the test class I am working on.
https://github.com/Daytron/Flipit-Map-Creator/blob/master/src/test/java/com/github/daytron/flipit/map/creator/MainAppTest.java

Is there an example I can look into?

Benjamin Gudehus

unread,
Nov 22, 2014, 9:52:57 AM11/22/14
to Ryan Gilera, testfx-...@googlegroups.com
Hi!

If the file chooser window is the operation system's native dialog,
then TestFX can not retrieve the coordinates of the elements within
the dialog, i.e. can not click on them. There are two possible
solutions (not yet implemented): (1, simple) change the "file choser
dialog open code" to directly accept file paths when testing with
TestFX, (2, hard, unreliable) hard-code every coordinate within the
file chooser window into the test cases.

If ControlsFX provides a file chooser dialog that uses JavaFX nodes,
then TestFX can click on the nodes using CSS selectors. ControlsFX's
source code should give a hint what selectors we need.

----

Example pseudo code for solution 1 would look like:

File file = null;
if (isTestMode()) {
file = openSimpleFilePathDialog();
} else {
file = openNativeFileDialog();
}

Testcode:
setTestMode(true);
click("#open-file-button");
click(".file-path-textfield").write("/home/user/fixtures/enterprise-data.xml");

I can imagine to include such a functionality in the future.

--Benjamin


On 11/22/14, Ryan Gilera <ryang...@gmail.com> wrote:
> Hi,
>
> I am currently using TestFX 4.0.0-SNAPSHOT for my tests. I have a menu that
>
> can open and save json file FILE>OPEN and FILE>SAVE. How do direct the
> mouse click and move to the filechooser window? How do you also deal with
> dialogs, close window and click buttons on them? I am using ControlsFX
> 8.20.8 <http://fxexperience.com/controlsfx/>.
>
> Here is the test class I am working on.
> https://github.com/Daytron/Flipit-Map-Creator/blob/master/src/test/java/com/github/daytron/flipit/map/creator/MainAppTest.java
>
> Is there an example I can look into?
>
> --
> You received this message because you are subscribed to the Google Groups
> "TestFX" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to testfx-discus...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

Ryan Gilera

unread,
Nov 22, 2014, 2:22:26 PM11/22/14
to testfx-...@googlegroups.com
Thanks for replying.

I am using the JavaFX's file chooser. The ControlFX's dialogs are for other functions such as confirmation and warning dialogs. How do I get css id for the JavaFX Filechooser? Is that possible?

Ryan Gilera

unread,
Nov 22, 2014, 2:23:36 PM11/22/14
to testfx-...@googlegroups.com
It's showSaveDialog() and showOpenDialog().

Benjamin Gudehus

unread,
Nov 22, 2014, 8:27:56 PM11/22/14
to Ryan Gilera, testfx-...@googlegroups.com
Here is a SSCCE (Short, Self Contained, Correct Example):

public class FileChooserOpenDialog {
public static void main(String[] args) throws Exception {
FxLifecycle.registerPrimaryStage();
FxLifecycle.setupStage(stage -> {
new FileChooser().showOpenDialog(stage);
});
}
}

TestFX will not be able to determine the screen coordinates of the UI
elements, since FileChooser uses native dialogs, i.e. no JavaFX
dialogs.

You'll have to replace the FileChooser with a custom one, when you run
the tests. showOpenDialog() returns a File (or null), so you'll need
to find a way to set this return value from your test code.





On 11/22/14, Ryan Gilera <ryang...@gmail.com> wrote:
> It's showSaveDialog() and showOpenDialog().

Ryan Gilera

unread,
Nov 25, 2014, 9:41:42 AM11/25/14
to testfx-...@googlegroups.com, ryang...@gmail.com
Thanks for the reply.

I decided to bypass filechooser and call a public method that saves and open a map.

I tried implementing this on my test class but return an IllegalStateException exception: not on FX Application thread. 

Here's the full log:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.github.daytron.flipit.map.creator.UITest
Exception in thread "main" java.lang.IllegalStateException: Not on FX application thread; currentThread = main
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
at javafx.scene.shape.Shape.impl_markDirty(Shape.java:942)
at javafx.scene.Node.impl_geomChanged(Node.java:3784)
at javafx.scene.text.Text.impl_geomChanged(Text.java:763)
at javafx.scene.text.Text.needsTextLayout(Text.java:194)
at javafx.scene.text.Text.needsFullTextLayout(Text.java:189)
at javafx.scene.text.Text.access$200(Text.java:96)
at javafx.scene.text.Text$2.invalidated(Text.java:386)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:109)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:143)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.scene.text.Text.setText(Text.java:367)
at com.sun.javafx.scene.control.skin.TextAreaSkin.lambda$new$231(TextAreaSkin.java:571)
at com.sun.javafx.scene.control.skin.TextAreaSkin$$Lambda$300/398350427.invalidated(Unknown Source)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.scene.control.TextInputControl$TextProperty.fireValueChangedEvent(TextInputControl.java:1123)
at javafx.scene.control.TextInputControl$TextProperty.markInvalid(TextInputControl.java:1127)
at javafx.scene.control.TextInputControl$TextProperty.invalidate(TextInputControl.java:1066)
at javafx.scene.control.TextInputControl$TextProperty.access$1300(TextInputControl.java:1038)
at javafx.scene.control.TextInputControl.lambda$new$163(TextInputControl.java:134)
at javafx.scene.control.TextInputControl$$Lambda$91/417404495.invalidated(Unknown Source)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.scene.control.TextArea$TextAreaContent.insert(TextArea.java:208)
at javafx.scene.control.TextInputControl$TextProperty.doSet(TextInputControl.java:1136)
at javafx.scene.control.TextInputControl$TextProperty.set(TextInputControl.java:1061)
at javafx.scene.control.TextInputControl.setText(TextInputControl.java:282)
at com.github.daytron.flipit.map.creator.model.LogManager.addNewLogMessage(LogManager.java:96)
at com.github.daytron.flipit.map.creator.model.MapManager.saveFile(MapManager.java:79)
at com.github.daytron.flipit.map.creator.controller.ViewController.saveMap(ViewController.java:1046)
at com.github.daytron.flipit.map.creator.UITest.generateMapThenSaveThenOpenTest(UITest.java:506)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Exception in thread "main" java.lang.IllegalStateException: Not on FX application thread; currentThread = main
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
at javafx.scene.shape.Shape.impl_markDirty(Shape.java:942)
at javafx.scene.Node$6.invalidated(Node.java:1224)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:112)
at javafx.beans.property.DoublePropertyBase.access$000(DoublePropertyBase.java:52)
at javafx.beans.property.DoublePropertyBase$Listener.invalidated(DoublePropertyBase.java:262)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.binding.DoubleBinding.invalidate(DoubleBinding.java:222)
at com.sun.javafx.binding.BindingHelperObserver.invalidated(BindingHelperObserver.java:51)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.binding.BooleanBinding.invalidate(BooleanBinding.java:176)
at com.sun.javafx.binding.BindingHelperObserver.invalidated(BindingHelperObserver.java:51)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:176)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:142)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:146)
at javafx.scene.control.TextInputControl.selectRange(TextInputControl.java:899)
at javafx.scene.control.TextInputControl$TextProperty.doSet(TextInputControl.java:1138)
at javafx.scene.control.TextInputControl$TextProperty.set(TextInputControl.java:1061)
at javafx.scene.control.TextInputControl.setText(TextInputControl.java:282)
at com.github.daytron.flipit.map.creator.model.LogManager.addNewLogMessage(LogManager.java:96)
at com.github.daytron.flipit.map.creator.model.MapManager.saveFile(MapManager.java:79)
at com.github.daytron.flipit.map.creator.controller.ViewController.saveMap(ViewController.java:1046)
at com.github.daytron.flipit.map.creator.UITest.generateMapThenSaveThenOpenTest(UITest.java:506)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Exception in thread "main" java.lang.IllegalStateException: Not on FX application thread; currentThread = main
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
at javafx.scene.Node.impl_transformsChanged(Node.java:4502)
at javafx.scene.Node$11.invalidated(Node.java:2523)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:112)
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
at javafx.scene.Node.setLayoutY(Node.java:2510)
at com.sun.javafx.scene.control.skin.ScrollPaneSkin.updatePosY(ScrollPaneSkin.java:1041)
at com.sun.javafx.scene.control.skin.ScrollPaneSkin.lambda$initialize$432(ScrollPaneSkin.java:322)
at com.sun.javafx.scene.control.skin.ScrollPaneSkin$$Lambda$303/1111768540.invalidated(Unknown Source)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.DoublePropertyBase.fireValueChangedEvent(DoublePropertyBase.java:106)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:113)
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
at javafx.scene.control.ScrollBar.setValue(ScrollBar.java:151)
at com.sun.javafx.scene.control.skin.ScrollPaneSkin.handleControlPropertyChanged(ScrollPaneSkin.java:619)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$60(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$190/1964395741.call(Unknown Source)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.DoublePropertyBase.fireValueChangedEvent(DoublePropertyBase.java:106)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:113)
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
at javafx.scene.control.ScrollPane.setVvalue(ScrollPane.java:263)
at com.sun.javafx.scene.control.skin.TextAreaSkin.lambda$new$228(TextAreaSkin.java:532)
at com.sun.javafx.scene.control.skin.TextAreaSkin$$Lambda$298/503735499.changed(Unknown Source)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.DoublePropertyBase.fireValueChangedEvent(DoublePropertyBase.java:106)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:113)
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
at javafx.beans.property.DoubleProperty.setValue(DoubleProperty.java:75)
at javafx.scene.control.TextArea.setScrollTop(TextArea.java:590)
at javafx.scene.control.TextArea.textUpdated(TextArea.java:460)
at javafx.scene.control.TextInputControl$TextProperty.doSet(TextInputControl.java:1139)
at javafx.scene.control.TextInputControl$TextProperty.set(TextInputControl.java:1061)
at javafx.scene.control.TextInputControl.setText(TextInputControl.java:282)
at com.github.daytron.flipit.map.creator.model.LogManager.addNewLogMessage(LogManager.java:96)
at com.github.daytron.flipit.map.creator.model.MapManager.saveFile(MapManager.java:79)
at com.github.daytron.flipit.map.creator.controller.ViewController.saveMap(ViewController.java:1046)
at com.github.daytron.flipit.map.creator.UITest.generateMapThenSaveThenOpenTest(UITest.java:506)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Exception in thread "main" java.lang.IllegalStateException: Not on FX application thread; currentThread = main
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
at javafx.scene.Node.impl_transformsChanged(Node.java:4502)
at javafx.scene.Node$NodeTransformation$3.invalidated(Node.java:5605)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:112)
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
at javafx.css.StyleableDoubleProperty.set(StyleableDoubleProperty.java:82)
at javafx.scene.Node.setTranslateY(Node.java:5050)
at com.sun.javafx.scene.control.skin.ScrollBarSkin.positionThumb(ScrollBarSkin.java:498)
at com.sun.javafx.scene.control.skin.ScrollBarSkin.handleControlPropertyChanged(ScrollBarSkin.java:380)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$60(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$190/1964395741.call(Unknown Source)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.DoublePropertyBase.fireValueChangedEvent(DoublePropertyBase.java:106)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:113)
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
at javafx.scene.control.ScrollBar.setValue(ScrollBar.java:151)
at com.sun.javafx.scene.control.skin.ScrollPaneSkin.handleControlPropertyChanged(ScrollPaneSkin.java:619)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$60(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$190/1964395741.call(Unknown Source)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.DoublePropertyBase.fireValueChangedEvent(DoublePropertyBase.java:106)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:113)
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
at javafx.scene.control.ScrollPane.setVvalue(ScrollPane.java:263)
at com.sun.javafx.scene.control.skin.TextAreaSkin.lambda$new$228(TextAreaSkin.java:532)
at com.sun.javafx.scene.control.skin.TextAreaSkin$$Lambda$298/503735499.changed(Unknown Source)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.DoublePropertyBase.fireValueChangedEvent(DoublePropertyBase.java:106)
at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:113)
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
at javafx.beans.property.DoubleProperty.setValue(DoubleProperty.java:75)
at javafx.scene.control.TextArea.setScrollTop(TextArea.java:590)
at javafx.scene.control.TextArea.textUpdated(TextArea.java:460)
at javafx.scene.control.TextInputControl$TextProperty.doSet(TextInputControl.java:1139)
at javafx.scene.control.TextInputControl$TextProperty.set(TextInputControl.java:1061)
at javafx.scene.control.TextInputControl.setText(TextInputControl.java:282)
at com.github.daytron.flipit.map.creator.model.LogManager.addNewLogMessage(LogManager.java:96)
at com.github.daytron.flipit.map.creator.model.MapManager.saveFile(MapManager.java:79)
at com.github.daytron.flipit.map.creator.controller.ViewController.saveMap(ViewController.java:1046)
at com.github.daytron.flipit.map.creator.UITest.generateMapThenSaveThenOpenTest(UITest.java:506)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Tests run: 7, Failures: 0, Errors: 1, Skipped: 6, Time elapsed: 6.526 sec <<< FAILURE! - in com.github.daytron.flipit.map.creator.UITest
generateMapThenSaveThenOpenTest(com.github.daytron.flipit.map.creator.UITest)  Time elapsed: 6.139 sec  <<< ERROR!
java.lang.IllegalStateException: Not on FX application thread; currentThread = main
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Node.snapshot(Node.java:1903)
at com.github.daytron.flipit.map.creator.model.MapManager.saveFile(MapManager.java:86)
at com.github.daytron.flipit.map.creator.controller.ViewController.saveMap(ViewController.java:1046)
at com.github.daytron.flipit.map.creator.UITest.generateMapThenSaveThenOpenTest(UITest.java:506)


Results :

Tests in error: 
  UITest.generateMapThenSaveThenOpenTest:506 » IllegalState Not on FX applicatio...

Tests run: 7, Failures: 0, Errors: 1, Skipped: 6

------------------------------------------------------------------------
BUILD FAILURE
------------------------------------------------------------------------
Total time: 7.705s
Finished at: Tue Nov 25 14:34:25 GMT 2014
Final Memory: 6M/114M 



My test method works something like this:

@Test
public void testScenario1() {
     // Do initial user interaction
     
// Prepare a File object to save and open
        File file = new File(fileToSave);

        // Save the map
        Date date7 = null;
        if (this.app.getView().verifyFileToSave(file)) {
            if (this.app.getView().saveMap(file)) {
                date7 = new Date();
            } else {
                Assert.fail("can't save file");
                return;
            }
        } else {
            Assert.fail("can't verify file to save");
            return;
        }

        sleep(10, SECONDS);

        // Open the map
        Date date8 = null;
        if (this.app.getView().verifyFileToOpen(file)) {
            if (this.app.getView().openMap(file)) {
                date8 = new Date();
            } else {
                Assert.fail("can't open file");
                return;
            }
        } else {
            Assert.fail("can't verify file to open");
            return;
        }

       // Rest of the code (date format, logs, assertions)




Benjamin Gudehus

unread,
Nov 25, 2014, 9:53:11 AM11/25/14
to Ryan Gilera, testfx-...@googlegroups.com
Seems that this.app.getView() throws this exception. JavaFX nodes need
to be changed or attached within the JavaFX thread.

For more details please consult the (excellent) Javadocs of JavaFX.
Here is a relevant excerpt from the Node class:

| Node objects may be constructed and modified on any thread as long they are
| not yet attached to a {@link Scene}. An application must attach nodes to a
| Scene, and modify nodes that are already attached to a Scene, on the JavaFX
| Application Thread.

You could try to use FxLifecycle.setup() at the beginning of the test
method which runs the supplied Runnable/Callable within the JavaFX
thread:

// NOTE: Please replace Object with the correct type.
Object view = FxLifecycle.setup(() -> {
return this.app.getView();
});

There is also `at javafx.scene.Node.snapshot(Node.java:1903)`, but I
can't spot any usage of Node#snapshot() anywhere.

Ryan Gilera

unread,
Nov 26, 2014, 6:16:39 AM11/26/14
to testfx-...@googlegroups.com, ryang...@gmail.com
I did add the FXLifecycle.setup() inside the test method on the very first and it's still failing on the same exception as before.

I tried testing it on a very hacky way by adding a button in the program that executes all saving and opening file inside the main source code.
When I click that button I created on the test method, it works well. It seems that calling a view's method inside a test method cause this exception. Is the test class suppose to run inside the JavaFX thread? Here is the full test class excluding other test methods:

public class UITest extends FxRobotImpl {

    private MainApp app;
    public static Stage primaryStage;
    
    
    
    
    public UITest() {
    }

    @BeforeClass
    public static void setUpClass() {
        try {
            // Start the Toolkit and block until the primary Stage was retrieved.
            primaryStage = FxLifecycle.registerPrimaryStage();
        } catch (TimeoutException ex) {
            Logger.getLogger(UITest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @AfterClass
    public static void tearDownClass() {
    }

    @Before
    public void setUp() {
        try {
            // Construct the Application and call start() with the primary Stage.
            this.app = (MainApp) FxLifecycle.setupApplication(MainApp.class);
            

            // Wait for the primary Stage to be shown by start().
            RunWaitUtils.waitFor(5, TimeUnit.SECONDS, primaryStage.showingProperty());
            
            
        } catch (TimeoutException ex) {
            Logger.getLogger(UITest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @After
    public void tearDown() {
    }

/**
     * Test events: 1. click generate button 2. click on title field 3. type
     * "eye of the world" in the field 4. press ENTER key 5. click player 1
     * button 6.
     */
    @Test
    public void generateMapThenSaveThenOpenTest() {
        ViewController view;
        try {
            //assertTrue(Platform.isFxApplicationThread());

            view = FxLifecycle.setup(() -> {
                return this.app.getView();
            });
        } catch (TimeoutException ex) {
            Logger.getLogger(UITest.class.getName()).log(Level.SEVERE, null, ex);
            return;
        }
        
        String fileToSave = "Map010.json";

        clickOn("#generate_map_btn");
        Date date = new Date();
        sleep(1, SECONDS);

        clickOn("#title_field").write("eye of the world").push(KeyCode.ENTER);
        Date date2 = new Date();

        clickOn("#p1_start_btn");
        Date date3 = new Date();

        moveBy(-400.00, -200.00).clickOn();
        Date date4 = new Date();

        clickOn("#p2_start_btn");
        Date date5 = new Date();

        moveBy(-350.00, -400.00).clickOn();
        Date date6 = new Date();


        // Click test button
        clickOn("#testbtn");
        Date date7 = new Date();
        

        SimpleDateFormat df = new SimpleDateFormat("hh:mm");
        String timeFormat = df.format(date);
        String timeFormat2 = df.format(date2);
        String timeFormat3 = df.format(date3);
        String timeFormat4 = df.format(date4);
        String timeFormat5 = df.format(date5);
        String timeFormat6 = df.format(date6);
        String timeFormat7 = df.format(date7);

        StringBuilder outputLog = new StringBuilder();

        // clickOn("#generate_map_btn");
        outputLog.append(GlobalSettings.LOG_SEPARATOR);
        outputLog.append("[").append(timeFormat).append("] ");
        outputLog.append(GlobalSettings.LOG_NEW_MAP);
        outputLog.append("10 columns & 10 rows");

        // clickOn("#title_field").write("eye of the world").push(KeyCode.ENTER);
        outputLog.append("\n").append(GlobalSettings.LOG_SEPARATOR);
        outputLog.append("[").append(timeFormat2).append("] ");
        outputLog.append(GlobalSettings.LOG_TITLE_SET);
        outputLog.append("Title: Eye Of The World 10x10 is set.");

        // clickOn("#p1_start_btn");
        outputLog.append("\n").append(GlobalSettings.LOG_SEPARATOR);
        outputLog.append("[").append(timeFormat3).append("] ");
        outputLog.append(GlobalSettings.LOG_PLAYER1_ON);

        // moveBy(-400.00, -200.00).clickOn();
        outputLog.append("\n").append(GlobalSettings.LOG_SEPARATOR);
        outputLog.append("[").append(timeFormat4).append("] ");
        outputLog.append(GlobalSettings.LOG_TILE_SET);
        outputLog.append("Player 1 start position is now set to [8,4]");

        // clickOn("#p2_start_btn");
        outputLog.append("\n").append(GlobalSettings.LOG_SEPARATOR);
        outputLog.append("[").append(timeFormat5).append("] ");
        outputLog.append(GlobalSettings.LOG_PLAYER2_ON);

        // moveBy(-350.00, -400.00).clickOn();
        outputLog.append("\n").append(GlobalSettings.LOG_SEPARATOR);
        outputLog.append("[").append(timeFormat6).append("] ");
        outputLog.append(GlobalSettings.LOG_TILE_SET);
        outputLog.append("Player 2 start position is now set to [8,1]");

        // Save the map
        outputLog.append("\n").append(GlobalSettings.LOG_SEPARATOR);
        outputLog.append("[").append(timeFormat7).append("] ");
        outputLog.append(GlobalSettings.LOG_SAVE_MAP);
        outputLog.append("File is successfully saved at ").append(fileToSave);

        // Open the map
        outputLog.append("\n").append(GlobalSettings.LOG_SEPARATOR);
        outputLog.append("[").append(timeFormat7).append("] ");
        outputLog.append(GlobalSettings.LOG_OPEN_MAP);
        outputLog.append("10 columns & 10 rows\nMap file opened: ");
        outputLog.append(fileToSave);

        Assertions.verifyThat("#logArea",
                Commons.hasText(outputLog.toString()));
        Assertions.verifyThat("#title_field", Commons.hasText("Eye Of The World"));
        assertTrue(this.app.getView().isThereAMapVisible());
    }

}

Ryan Gilera

unread,
Nov 26, 2014, 6:20:33 AM11/26/14
to testfx-...@googlegroups.com
I also initially try to disable and hide the test button at first and re-enable and show when testing. When I call this simple view's method   in the test method to enable the button, it also causes not on JavaFXThread.

Ryan Gilera

unread,
Nov 26, 2014, 11:44:32 AM11/26/14
to testfx-...@googlegroups.com
I found a workaround to manage the Filechooser. There's no need for extra methods and a button. Please disregard previous posts. Thanks.

Jinghong Li

unread,
Feb 24, 2017, 2:48:46 PM2/24/17
to TestFX
May I ask what is workaround? Thanks,

Ryan Gilera

unread,
Mar 2, 2017, 2:01:06 AM3/2/17
to TestFX
Hi,

Since when a dialog opens it automatically focus on that window, I just used keyboard shortcuts to trigger certain behaviours.

Please see
https://github.com/Daytron/Flipit-Map-Creator/blob/master/src/test/java/com/github/daytron/flipit/map/creator/FileMapTest.java

Benjamin Gudehus

unread,
Mar 2, 2017, 10:58:27 AM3/2/17
to Ryan Gilera, TestFX
Hi Ryan,

nice solution to use keyboard inputs for system-controlled dialogs.

--Benjamin

--
You received this message because you are subscribed to the Google Groups "TestFX" group.
To unsubscribe from this group and stop receiving emails from it, send an email to testfx-discuss+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages