New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(refactor) Extract robot and service classes from GuiTest. #39
Conversation
I spend a lot of time and prototyped a refactored version. The pull description was updated accordingly. There will be I also changed the interface of the Example fx.drag("#nodeA").moveTo(nodeB).dropTo("NodeC")
fx.drag("#nodeA").moveBy(200, 50).sleep(2, TimeUnit.SECONDS).drop()
fx.drag("#nodeA").dropBy(200, 50) Example Bounds nodeBounds = fx.locator.nodeBounds(fx.node("#nodeA")) |
Rename ScreenController to framework.ScreenRobot. Rename FXScreenController to framework.ScreenRobotImpl.
Refactor TestFxApp, setupStage() and showNodeInStage().
I made some good progress on public class PointLocator {
public PointQuery pointFor(Bounds bounds) {}
public PointQuery pointFor(Point2D point) {}
public PointQuery pointFor(Node node) {}
public PointQuery pointFor(Scene scene) {}
public PointQuery pointFor(Window window) {}
}
public class BoundsLocator {
public Bounds screenBoundsFor(Node node) {}
public Bounds screenBoundsFor(Bounds boundsInScene, Scene scene) {}
public Bounds screenBoundsFor(Scene scene) {}
public Bounds screenBoundsFor(Window window) {}
public Bounds sceneBoundsFor(Node node) {}
public Bounds sceneBoundsVisibleFor(Node node) {}
private Bounds getSceneBounds(Scene scene) {}
private Bounds intersectBounds(Bounds a, Bounds b) {}
} |
Refactor PointLocator and pointFor() in GuiTest.
Will TestFX still be usable the same way, or do existing tests have to be modified? |
@Philipp91 There will be some minor changes to the tests necessary, you'll mostly need to rename methods. My refactorings currently didn't change the tests that are included in TestFX, and they pass for every single commit. The minimal feature set of TestFX will be the same. |
Changes to test classes. Before: public class MyTest extends GuiTest {
@Override
protected Parent getRootNode() { /*...*/ }
} After: public class MyTest extends StageRobotTest {
public Scene setupScene(Parent sceneRootNode) {
return SceneBuilder.create().width(600).height(400)
.root(sceneRootNode).build();
}
public Parent setupSceneRoot() { /*...*/ }
} Of course it is possible to write |
Changes to test methods. Before: click("#nodeA");
click(offset("#nodeA", 200, 50)); // offset() returns OffsetTarget.
pos(Pos.BOTTOM_RIGHT).click("#nodeB")
click("#nodeC", MouseButton.PRIMARY) After: click("#nodeA"); // no change.
click(offset("#nodeA", 200, 50)); // offset() returns Point2D and is typed.
pos(Pos.BOTTOM_RIGHT).click("#nodeB") // no change.
click("#nodeC", MouseButton.PRIMARY) // no change. Before: move(0, 0)
move("#nodeA")
move(predicate)
moveBy(200, 50) After: moveTo(0, 0)
moveTo("#nodeA") // moveTo() is internally typed now.
moveTo(predicate) // moveTo() is internally typed now.
moveBy(200, 50) // no change. Before: drag("#nodeA").via(nodeB).to("NodeC")
drag("#nodeA").by(200, 50).sleep(2, TimeUnit.SECONDS).drop()
drag("#nodeA").to(200, 50) After: drag("#nodeA").moveTo(nodeB).dropTo("NodeC")
drag("#nodeA").moveBy(200, 50).sleep(2, TimeUnit.SECONDS).drop()
drag("#nodeA").dropBy(200, 50) Before: find("#nodeA")
find("#nodeA", "#parentNode")
findAll(".classA") After: node("#nodeA")
node("#nodeA", "#parentNode") // WIP: parentObject should be typed.
nodes(".classA") Before: pointFor("#nodeA") // returns Point2D.
pointFor(new Point2D(50, 50))
pointFor(node)
pointFor(scene)
pointFor(window)
pointFor(query)
pointFor(matcher)
pointFor(predicate) After: pointFor("#nodeA") // returns PointQuery and is typed.
pointFor(new Point2D(50, 50))
pointFor(node)
pointFor(scene)
pointFor(window)
pointFor(query)
pointFor(matcher)
pointFor(predicate) |
By the way, I'm going to write a compatibility class. It would be great if you can run your test suites with these changes as soon this pull request is ready; no changes in test classes needed. |
Okay thank you. #39 (comment) And is it really necessary to implement setupScene in every test class? And why does the new implementation use the deprecated SceneBuilder? |
I had an abstract
Good point. I'll provide a default implementation for this. You can write your own abstract Test class, that implements a default |
Okay, that sounds good. For the application that I use TestFX for, it would also be pretty useful if one could customize the implementation of the javafx.application.Application (need to use a custom one here that connects to CDI). If you find a clever way to integrate that as well, it would be nice to have. |
I already thought about this problem, but didn't find a solution so far. The modularization will be one step towards solving this problem; should be easier to experiment with solutions. |
Hi! I've looked through the code so far and it looks solid. I'll focus on writing some tests. |
I was a bit unhappy with the flexibility of the the Notice: The launch process with There is an Within every test class is an abstract method called // Runs in JavaFX Application Thread.
abstract public void setupStages(Stage primaryStage); |
Create AppRobotTest.
So, I'm going to resolve all conflicts as merged now. Some of the commits (8d8bec7...72377b5) are integrated, some of them are not. I'll integrate them in the next couple of days. |
Conflicts: pom.xml src/main/java/org/loadui/testfx/FXScreenController.java src/main/java/org/loadui/testfx/GuiTest.java src/main/java/org/loadui/testfx/ScreenController.java src/main/java/org/loadui/testfx/controls/TextInputControls.java src/main/java/org/loadui/testfx/controls/impl/HasLabelStringMatcher.java src/main/java/org/loadui/testfx/utils/FXTestUtils.java src/test/java/org/loadui/testfx/TextInputControlsTest.java src/test/java/org/loadui/testfx/VisibilityTest.java
This is my work-in-progress which extracts
robot
andservice
classes fromorg.loadui.testfx.GuiTest
. It is an experiment to see if a modular approach is better than the current monolithic approach.Framework:
framework.FxRobotImpl
that implements allrobot
interfaces (is-aKeyboardRobot
,MouseRobot
,ClickRobot
, ...) and containsservice
classes (has-aNodeFinder
,ScreenLocator
,ScreenCapturer
, ...).framework.ScreenRobotImpl
fromFxScreenController
.framework.junit.StageRobotTest
fromGuiTest
that inheritsframework.FxRobot
and implementsservice.SceneProvider
.Createframework.FxRobotConfig
to configure timeouts and pauses.Robots:
robot.KeyboardRobot
withpress
andrelease
methods.robot.MouseRobot
withpress
andrelease
methods.robot.ClickRobot
withclick
,rightClick
anddoubleClick
methods.robot.DragRobot
withdrag
,drop
,dropTo
anddropBy
methods.robot.MoveRobot
withmoveTo
andmoveBy
methods.robot.ScrollRobot
withscroll
,scrollUp
andscrollDown
methods.robot.SleepRobot
withsleep
method.robot.TypeRobot
withtype
anderase
methods.Services:
service.stage.StageApplication
withTestFxApp
functionality.service.stage.StageRetriever
withsetupStage
andshowNodeInStage
methods.service.stage.SceneProvider
withgetRootNode
methods.service.locator.PointLocator
withpointFor
andpointForBounds
methods.service.locator.BoundsLocator
withsceneBoundsToScreenBounds
method.service.finder.NodeFinder
with staticfind
,findAll
,findAllRecursively
,exists
,labelExists
andselectorExists
methods.service.finder.WindowFinder
withgetWindows
,getWindowByIndex
andfindStageByTitle
methods.service.capturer.ScreenCapturer
withcaptureScreenshot
method.Miscellanous:
waitUntil()
functionality.target()
, and statictargetWindow()
andlastSeenWindow
functionality.pos()
andnodePosition
functionality.offset()
andOffsetTarget
functionality withPointQuery
.