LogoRRR uses TestFX to run integration tests against its JavaFX user interface. These tests give confidence that core workflows survive new features, refactorings, and dependency updates — and they catch regressions that unit tests simply cannot see.
Why now
After 20+ releases, LogoRRR had grown complex enough that manual testing alone was no longer sufficient. The codebase needed a safety net. TestFX makes it possible to drive the actual application window — clicking buttons, opening files, inspecting UI state — from JUnit test methods.
The decision of when to invest in end-to-end tests is always a trade-off. Early in a project, UIs change too fast for tests to keep up. But once the core flows stabilise, tests become an accelerant rather than a burden. That inflection point arrived with 24.3.0.
Implementation
Scala’s concise syntax lends itself naturally to building a small test DSL. Each atomic action — open a file, click the close button, assert the tab pane is empty — becomes a readable building block:
@Test def openAndCloseTab(): Unit = {
checkForEmptyTabPane()
openFile(path)
checkForNonEmptyTabPane()
clickOn(lookup(UiNodes.LogFileHeaderTabs).query[StackPane](), MouseButton.SECONDARY)
waitAndClickVisibleItem(CloseTabMenuItem.uiNode(fileId))
checkForEmptyTabPane()
}
Writing frontend tests forced improvements to the production code too. A new Service layer was added to abstract file I/O and external process calls — changes that improved the architecture independently of any test benefit.
What the tests caught
- Application shutdown behaviour — resources that were never properly cleaned up became obvious under test
- Test isolation — each test must set up and tear down its own state, which exposed several subtle assumptions about shared UI state
- Performance baseline — keeping an eye on test execution time prevents slow accumulation of sluggish tests
Header photo by Sora Shimazaki on Pexels.
