From 94e81e5e08abadce17af40c3d46dc000beb3db07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Kristoffer=20Tveit?= Date: Thu, 15 Apr 2021 14:17:46 +0000 Subject: [PATCH] Add test templates --- .gitlab-ci.yml | 33 ++- pom.xml | 32 ++- src/main/java/app/Main.java | 4 +- src/main/java/app/MainController.java | 10 + .../app/controllers/EditorController.java | 32 +-- .../app/controllers/FiletreeController.java | 27 +- src/main/java/app/events/Event.java | 2 +- .../java/app/service/LanguageOperations.java | 2 +- src/main/resources/fxml/Main.fxml | 3 +- src/test/java/app/FxTestTemplate.java | 44 ++++ src/test/java/app/MainTest.java | 76 +++++- .../app/controllers/EditorControllerTest.java | 238 ++++++++++++++++++ .../events/FileSaveStateChangedEventTest.java | 18 ++ .../app/testing/ControllerTestTemplate.java | 5 + .../java/app/testing/EventTestTemplate.java | 25 ++ src/test/java/app/testing/FxTestTemplate.java | 56 +++++ src/test/resources/testfile.txt | 3 + 17 files changed, 570 insertions(+), 40 deletions(-) create mode 100644 src/test/java/app/FxTestTemplate.java create mode 100644 src/test/java/app/controllers/EditorControllerTest.java create mode 100644 src/test/java/app/events/FileSaveStateChangedEventTest.java create mode 100644 src/test/java/app/testing/ControllerTestTemplate.java create mode 100644 src/test/java/app/testing/EventTestTemplate.java create mode 100644 src/test/java/app/testing/FxTestTemplate.java create mode 100644 src/test/resources/testfile.txt diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1199c67..7311676 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,15 +3,33 @@ # and # https://gitlab.stud.idi.ntnu.no/tdt4140-staff/examples/-/blob/master/.gitlab-ci.yml -image: maven:3.6.3-openjdk-15 +image: maven:3-openjdk-15-slim variables: + # This will suppress any download for dependencies and plugins or upload messages which would clutter the console log. # `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work. - MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true" + MAVEN_OPTS: " \ + -Dhttps.protocols=TLSv1.2 \ + -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository \ + -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN \ + -Dorg.slf4j.simpleLogger.showDateTime=true \ + -Djava.awt.headless=true" + # As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used # when running from the command line. - MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version" + MAVEN_CLI_OPTS: " \ + --batch-mode \ + --errors \ + --fail-at-end \ + --show-version \ + -Dprism.verbose=true \ + -Dtestfx.robot=glass \ + -Dtestfx.headless=true \ + -Dglass.platform=Monocle \ + -Dprism.order=sw \ + -Dprism.text=t2k \ + -Dtestfx.setup.timeout=60000" # Cache downloaded dependencies and plugins between builds. # To keep cache across branches add 'key: "$CI_JOB_NAME"' @@ -38,6 +56,8 @@ unittest: stage: test needs: [build] script: + - "apt update" + - "apt install -y openjfx" - "mvn package $MAVEN_CLI_OPTS" artifacts: paths: @@ -46,12 +66,15 @@ unittest: reports: junit: - target/surefire-reports/TEST-*.xml - - target/failsafe-reports/TEST-*.xml + # TODO: Separate unit tests and integration tests + # - target/failsafe-reports/TEST-*.xml generate-coverage: stage: docs script: - - 'mvn clean jacoco:prepare-agent test jacoco:report' + - "apt update" + - "apt install -y openjfx" + - 'mvn clean jacoco:prepare-agent test $MAVEN_CLI_OPTS jacoco:report' - 'cat target/site/jacoco/index.html' coverage: '/Total.*?([0-9]{1,3})%/' artifacts: diff --git a/pom.xml b/pom.xml index 9f82b77..0250a57 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,6 @@ 3.2.0-01 - org.junit.jupiter @@ -65,6 +64,36 @@ test + + + org.hamcrest + hamcrest + 2.1 + test + + + + + org.testfx + openjfx-monocle + jdk-12.0.1+2 + test + + + + + org.mockito + mockito-inline + 3.8.0 + test + + + org.mockito + mockito-junit-jupiter + 2.23.0 + test + + org.apache.maven.plugins @@ -133,7 +162,6 @@ - diff --git a/src/main/java/app/Main.java b/src/main/java/app/Main.java index 7c161aa..ec43f2d 100644 --- a/src/main/java/app/Main.java +++ b/src/main/java/app/Main.java @@ -35,7 +35,8 @@ public class Main extends Application { */ private void setupWindow(Stage window) { window.setTitle(TITLE); - window.getIcons().add(new Image(getClass().getResourceAsStream(ICON_PATH))); + if (window.getIcons().isEmpty()) + window.getIcons().add(new Image(getClass().getResourceAsStream(ICON_PATH))); } /** @@ -53,6 +54,7 @@ public class Main extends Application { */ private void createScene() { this.scene = new Scene(fxmlRoot); + this.scene.setUserData(this.fxmlLoader); Model.setScene(scene); } diff --git a/src/main/java/app/MainController.java b/src/main/java/app/MainController.java index 428f83e..ed6b470 100644 --- a/src/main/java/app/MainController.java +++ b/src/main/java/app/MainController.java @@ -66,6 +66,16 @@ public class MainController implements Initializable { return hostServices; } + //TODO: Document + public List getInnerControllers() { + return List.of( + editorController, + filetreeController, + modelineController, + menubarController + ); + } + /** * Set a reference to the global Host Services API * diff --git a/src/main/java/app/controllers/EditorController.java b/src/main/java/app/controllers/EditorController.java index 61981b4..28e1b4c 100644 --- a/src/main/java/app/controllers/EditorController.java +++ b/src/main/java/app/controllers/EditorController.java @@ -66,6 +66,11 @@ public class EditorController implements Initializable, Controller, FileManageme this.eventBus.register(this); } + // TODO: document + public CodeArea getEditor() { + return editor; + } + /** * Applies highlighting to the editor. * @@ -146,21 +151,20 @@ public class EditorController implements Initializable, Controller, FileManageme * @throws FileNotFoundException */ public void setEditorContent(String filePath) { - if (filePath == null) { - editor.clear(); - editor.appendText("// New File"); - return; - } + // if (filePath == null) { + // editor.clear(); + // editor.appendText("// New File"); + // return; + // } try (Scanner sc = new Scanner(new File(filePath))) { - if (filePath.endsWith(".java") || filePath.endsWith(".md")) { + // if (filePath.endsWith(".java") || filePath.endsWith(".md")) { editor.clear(); while (sc.hasNextLine()) { - editor.appendText(sc.nextLine()); - editor.appendText("\n"); + editor.appendText(sc.nextLine() + "\n"); } - } else { - throw new FileNotFoundException(); - } + // } else { + // throw new FileNotFoundException(); + // } } catch (FileNotFoundException ex) { Alert error = new Alert(AlertType.ERROR); @@ -208,8 +212,8 @@ public class EditorController implements Initializable, Controller, FileManageme * Updates Code Area (read from file) whenever the FileSelected is changed */ @Subscribe - private void handle(FileSelectedEvent event) { - this.setEditorContent(event.getPath()); + public void handle(FileSelectedEvent event) { + this.setEditorContent(event.getPath()); } /** @@ -226,7 +230,7 @@ public class EditorController implements Initializable, Controller, FileManageme } @Subscribe - private void handle(ToggleCommentEvent event) { + public void handle(ToggleCommentEvent event) { this.toggleComment(); } diff --git a/src/main/java/app/controllers/FiletreeController.java b/src/main/java/app/controllers/FiletreeController.java index 0452544..68184d3 100644 --- a/src/main/java/app/controllers/FiletreeController.java +++ b/src/main/java/app/controllers/FiletreeController.java @@ -9,6 +9,7 @@ import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import java.io.File; +import java.io.IOException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -124,12 +125,26 @@ public class FiletreeController implements Initializable, Controller { String name = file.getName(); String ext = (name.substring(file.getName().lastIndexOf(".") + 1, file.getName().length())); - if ("java".equals(ext)) - createExtension(name, java, parent); - else if ("md".equals(ext)) - createExtension(name, md, parent); - else - createExtension(name, placeholder, parent); + try { + createExtension(name, getIconForFile(file), parent); + } catch (Exception e) { + System.err.println("ICON NOT FOUND: " + file.getPath()); + } + + // if ("java".equals(ext)) + // createExtension(name, java, parent); + // else if ("md".equals(ext)) + // createExtension(name, md, parent); + // else + // createExtension(name, placeholder, parent); + } + + private Image getIconForFile(File file) throws IOException { + String mimeType = Files.probeContentType(file.toPath()).replace('/', '-'); + String iconPath = (mimeType != null) + ? "/graphics/filetreeicons/" + mimeType + ".png" + : "/graphics/filetreeicons/file.png"; + return new Image(getClass().getResourceAsStream(iconPath)); } private void createExtension(String name, Image image, CheckBoxTreeItem parent) { diff --git a/src/main/java/app/events/Event.java b/src/main/java/app/events/Event.java index 2438df1..836c2df 100644 --- a/src/main/java/app/events/Event.java +++ b/src/main/java/app/events/Event.java @@ -3,4 +3,4 @@ package app.events; /** * Base class for any type of event of the eventbus */ -abstract class Event {} +public abstract class Event {} diff --git a/src/main/java/app/service/LanguageOperations.java b/src/main/java/app/service/LanguageOperations.java index 32c22cd..c3e2343 100644 --- a/src/main/java/app/service/LanguageOperations.java +++ b/src/main/java/app/service/LanguageOperations.java @@ -13,7 +13,7 @@ import app.model.ProgrammingLanguage; * Common static operations that can be executed on any class * that implements {@link app.model.ProgrammingLanguage ProgrammingLanguage} */ -public class LanguageOperations { +public final class LanguageOperations { /** * Use a matcher to find the styleclass of the next match diff --git a/src/main/resources/fxml/Main.fxml b/src/main/resources/fxml/Main.fxml index d7bc4ff..a8fadb9 100644 --- a/src/main/resources/fxml/Main.fxml +++ b/src/main/resources/fxml/Main.fxml @@ -10,7 +10,8 @@ prefHeight="400" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" - fx:controller="app.MainController"> + fx:controller="app.MainController" + fx:id="root"> diff --git a/src/test/java/app/FxTestTemplate.java b/src/test/java/app/FxTestTemplate.java new file mode 100644 index 0000000..13886ee --- /dev/null +++ b/src/test/java/app/FxTestTemplate.java @@ -0,0 +1,44 @@ +package app; + +import javafx.scene.Node; +import javafx.stage.Stage; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.testfx.api.FxToolkit; +import org.testfx.framework.junit5.ApplicationTest; +import org.testfx.util.WaitForAsyncUtils; + +import java.util.concurrent.TimeoutException; + +public class FxTestTemplate extends ApplicationTest { + + private Stage stage; + + @BeforeEach + public void runAppToTests() throws Exception { + FxToolkit.registerPrimaryStage(); + FxToolkit.setupApplication(Main::new); + FxToolkit.showStage(); + WaitForAsyncUtils.waitForFxEvents(100); + } + + @AfterEach + public void stopApp() throws TimeoutException { + FxToolkit.cleanupStages(); + } + + @Override + public void start(Stage primaryStage){ + this.stage = primaryStage; + primaryStage.toFront(); + } + + public Stage getStage() { + return stage; + } + + public T find(final String query) { + /** TestFX provides many operations to retrieve elements from the loaded GUI. */ + return lookup(query).query(); + } +} \ No newline at end of file diff --git a/src/test/java/app/MainTest.java b/src/test/java/app/MainTest.java index 9d0e293..1030f64 100644 --- a/src/test/java/app/MainTest.java +++ b/src/test/java/app/MainTest.java @@ -1,16 +1,74 @@ package app; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.IOException; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.annotation.Testable; -public class MainTest { +import app.controllers.*; - @Test - @DisplayName("Temp Test") - public void tempTest() { - assertEquals(1, 1); - } - -} +import java.util.List; +import java.util.stream.Collectors; + +import javafx.scene.layout.BorderPane; + +import app.testing.FxTestTemplate; + + +@Testable +public class MainTest extends FxTestTemplate { + + @Test + @DisplayName("Check that the stage title is correct") + public void should_have_stage_title() { + assertEquals("Banana Editor", this.getStage().getTitle()); + } + + @Test + @Order(1) + @DisplayName("Check that the stage has an icon") + public void should_have_stage_icon() { + assertEquals(1, this.getStage().getIcons().size()); + } + + + @Test + @Order(2) + @DisplayName("Check that the root element is present") + public void should_have_root() { + BorderPane app = (BorderPane) find("#root"); + assertNotNull(app); + } + + @Test + @Order(3) + @DisplayName("Check that all subcontrollers are present") + public void should_have_subcontrollers() { + this + .getMainController() + .getInnerControllers() + .forEach((Controller controller) -> assertNotNull(controller)); + } + + @Test + @DisplayName("Check that the scene is correct") + public void should_have_scene() throws IOException { + assertNotNull(this.getStage().getScene()); + } + + @Test + @DisplayName("Check that the CSS is set") + public void should_have_css() { + List expectedCSS = + List.of("/styling/themes/monokai.css", "/styling/languages/java.css") + .stream() + .map(p -> getClass().getResource(p).toExternalForm()) + .collect(Collectors.toList()); + assertEquals(expectedCSS, this.getStage().getScene().getStylesheets()); + } +} \ No newline at end of file diff --git a/src/test/java/app/controllers/EditorControllerTest.java b/src/test/java/app/controllers/EditorControllerTest.java new file mode 100644 index 0000000..aaaf10e --- /dev/null +++ b/src/test/java/app/controllers/EditorControllerTest.java @@ -0,0 +1,238 @@ +package app.controllers; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.stream.Collectors; + +import org.fxmisc.richtext.CodeArea; +import org.fxmisc.richtext.model.StyleSpans; + +import com.google.common.eventbus.EventBus; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import app.testing.FxTestTemplate; +import app.model.Model; +import app.model.ProgrammingLanguage; +import app.service.LanguageOperations; +import app.events.CopyEvent; +import app.events.CutEvent; +import app.events.FileSelectedEvent; +import app.events.LanguageChangedEvent; +import app.events.PasteEvent; +import app.events.RedoEvent; +import app.events.ToggleCommentEvent; +import app.events.ToggleWrapTextEvent; +import app.events.UndoEvent; + +@ExtendWith(MockitoExtension.class) +public class EditorControllerTest extends FxTestTemplate { + + + @Captor + private ArgumentCaptor captor; + + @Mock + private CodeArea editor; + + private EventBus eventBus; + + @InjectMocks + private EditorController controller; + + private String mockContent = """ + class HelloWorld { + private String message = "Hello world"; + + public String getMessage() { + return message; + } + } + """; + + private String mockLine = "private String message = \"Hello world\";"; + + @BeforeEach + public void insertEventBus() { + this.eventBus = new EventBus(); + this.controller.setEventBus(eventBus); + } + + @Test + @DisplayName("Test handling of FileSelectedEvent with a real file") + public void testFileSelectedEventWithRealFile() throws IOException { + + String resourcePath = "/testfile.txt"; + String filePath = getClass().getResource(resourcePath).getPath(); + File file = new File(filePath); + List content = + Files.readAllLines(file.toPath()) + .stream() + .map(s -> s + "\n") + .collect(Collectors.toList()); + + eventBus.post(new FileSelectedEvent(filePath)); + verify(editor, times(content.size())).appendText(captor.capture()); + + assertEquals(content, captor.getAllValues()); + } + + @Test + @DisplayName("Test handling of FileSelectedEvent with a file that doesn't exist") + public void testFileSelectedEventWithUnrealFile() throws IOException { + + String brokenFilePath = "/doesNotExist.txt"; + eventBus.post(new FileSelectedEvent(brokenFilePath)); + + verify(editor, never()).clear(); + } + + @Test + @DisplayName("Test handling of LanguageChangedEvent") + public void testLanguageChangedEvent(){ + + when(editor.getText()).thenReturn(mockContent); + + try (MockedStatic mocked = mockStatic(LanguageOperations.class)) { + mocked.when(() -> LanguageOperations.syntaxHighlight(anyString(), any())) + .thenReturn(StyleSpans.singleton(null, 0)); + + eventBus.post(new LanguageChangedEvent("markdown")); + mocked.verify(() -> LanguageOperations.syntaxHighlight(anyString(), any())); + } + } + + @Test + @DisplayName("Test handling of ToggleCommentEvent when not selected") + public void testToggleCommentEventNotSelect(){ + + ProgrammingLanguage lang = mock(ProgrammingLanguage.class); + when(editor.getSelectedText()).thenReturn(""); + when(editor.getText(anyInt())).thenReturn(mockLine); + + try (MockedStatic mocked = mockStatic(Model.class)) { + mocked.when(() -> Model.getLanguage()).thenReturn(lang); + + when(lang.isCommentedLine(anyString())).thenReturn(false); + eventBus.post(new ToggleCommentEvent()); + verify(lang).commentLine(anyString()); + + when(lang.isCommentedLine(anyString())).thenReturn(true); + eventBus.post(new ToggleCommentEvent()); + verify(lang).unCommentLine(anyString()); + } + } + + @Test + @DisplayName("Test handling of ToggleCommentEvent when selected") + public void testToggleCommentEventSelect(){ + + ProgrammingLanguage lang = mock(ProgrammingLanguage.class); + when(editor.getSelectedText()).thenReturn("Selected Text"); + + try (MockedStatic mocked = mockStatic(Model.class)) { + mocked.when(() -> Model.getLanguage()).thenReturn(lang); + + when(lang.isCommentedSelection(anyString())).thenReturn(false); + eventBus.post(new ToggleCommentEvent()); + verify(lang).commentSelection(anyString()); + + when(lang.isCommentedSelection(anyString())).thenReturn(true); + eventBus.post(new ToggleCommentEvent()); + verify(lang).unCommentSelection(anyString()); + } + } + + @Test + @DisplayName("Test handling of ToggleWrapTextEvent") + public void testToggleWrapTextEvent(){ + eventBus.post(new ToggleWrapTextEvent(true)); + verify(editor).setWrapText(true); + eventBus.post(new ToggleWrapTextEvent(false)); + verify(editor).setWrapText(false); + } + + @Test + @DisplayName("Test handling of UndoEvent") + public void testUndoEvent(){ + when(editor.isFocused()).thenReturn(true); + eventBus.post(new UndoEvent()); + verify(editor, times(1)).undo(); + + when(editor.isFocused()).thenReturn(false); + eventBus.post(new UndoEvent()); + // Should not have been called one more time + verify(editor, times(1)).undo(); + } + + @Test + @DisplayName("Test handling of RedoEvent") + public void testRedoEvent(){ + when(editor.isFocused()).thenReturn(true); + eventBus.post(new RedoEvent()); + verify(editor, times(1)).redo(); + + when(editor.isFocused()).thenReturn(false); + eventBus.post(new RedoEvent()); + verify(editor, times(1)).redo(); + } + + @Test + @DisplayName("Test handling of CopyEvent") + public void testCopyEvent(){ + when(editor.isFocused()).thenReturn(true); + eventBus.post(new CopyEvent()); + verify(editor, times(1)).copy(); + + when(editor.isFocused()).thenReturn(false); + eventBus.post(new CopyEvent()); + verify(editor, times(1)).copy(); + } + + @Test + @DisplayName("Test handling of CutEvent") + public void testCutEvent(){ + when(editor.isFocused()).thenReturn(true); + eventBus.post(new CutEvent()); + verify(editor, times(1)).cut(); + + when(editor.isFocused()).thenReturn(false); + eventBus.post(new CutEvent()); + verify(editor, times(1)).cut(); + } + + @Test + @DisplayName("Test handling of PasteEvent") + public void testPasteEvent(){ + when(editor.isFocused()).thenReturn(true); + eventBus.post(new PasteEvent()); + verify(editor, times(1)).paste(); + + when(editor.isFocused()).thenReturn(false); + eventBus.post(new PasteEvent()); + verify(editor, times(1)).paste(); + } +} \ No newline at end of file diff --git a/src/test/java/app/events/FileSaveStateChangedEventTest.java b/src/test/java/app/events/FileSaveStateChangedEventTest.java new file mode 100644 index 0000000..cdb9ff1 --- /dev/null +++ b/src/test/java/app/events/FileSaveStateChangedEventTest.java @@ -0,0 +1,18 @@ +package app.events; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import app.model.Model; +import app.testing.EventTestTemplate; + +public class FileSaveStateChangedEventTest extends EventTestTemplate { + + @Test + @DisplayName("Check that model gets changed on constructor") + public void checkModel() { + new FileSaveStateChangedEvent(true); + this.mockModel.verify(() -> Model.setFileIsSaved(true)); + } + +} diff --git a/src/test/java/app/testing/ControllerTestTemplate.java b/src/test/java/app/testing/ControllerTestTemplate.java new file mode 100644 index 0000000..1c8a021 --- /dev/null +++ b/src/test/java/app/testing/ControllerTestTemplate.java @@ -0,0 +1,5 @@ +package app.testing; + +public class ControllerTestTemplate extends FxTestTemplate { + +} \ No newline at end of file diff --git a/src/test/java/app/testing/EventTestTemplate.java b/src/test/java/app/testing/EventTestTemplate.java new file mode 100644 index 0000000..01a1985 --- /dev/null +++ b/src/test/java/app/testing/EventTestTemplate.java @@ -0,0 +1,25 @@ +package app.testing; + +import static org.mockito.Mockito.mockStatic; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.MockedStatic; + +import app.model.Model; + +public class EventTestTemplate extends FxTestTemplate { + + public MockedStatic mockModel; + + @BeforeEach + public void openModel() { + mockModel = mockStatic(Model.class); + } + + @AfterEach + public void closeModel() { + mockModel.close(); + } + +} diff --git a/src/test/java/app/testing/FxTestTemplate.java b/src/test/java/app/testing/FxTestTemplate.java new file mode 100644 index 0000000..e024a8d --- /dev/null +++ b/src/test/java/app/testing/FxTestTemplate.java @@ -0,0 +1,56 @@ +package app.testing; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.stage.Stage; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.testfx.api.FxToolkit; +import org.testfx.framework.junit5.ApplicationTest; +import org.testfx.util.WaitForAsyncUtils; + +import java.util.concurrent.TimeoutException; + +import app.Main; +import app.MainController; + +public class FxTestTemplate extends ApplicationTest { + + private Stage stage; + private Application application; + + @BeforeEach + public void runAppToTests() throws Exception { + FxToolkit.registerPrimaryStage(); + this.application = FxToolkit.setupApplication(Main::new); + + FxToolkit.showStage(); + WaitForAsyncUtils.waitForFxEvents(100); + } + + @AfterEach + public void stopApp() throws TimeoutException { + FxToolkit.cleanupStages(); + FxToolkit.cleanupApplication(this.application); + } + + @Override + public void start(Stage primaryStage){ + this.stage = primaryStage; + primaryStage.toFront(); + } + + public Stage getStage() { + return stage; + } + + public MainController getMainController() { + return ((FXMLLoader) this.stage.getScene().getUserData()).getController(); + } + + public T find(final String query) { + /** TestFX provides many operations to retrieve elements from the loaded GUI. */ + return lookup(query).query(); + } +} \ No newline at end of file diff --git a/src/test/resources/testfile.txt b/src/test/resources/testfile.txt new file mode 100644 index 0000000..2528c5e --- /dev/null +++ b/src/test/resources/testfile.txt @@ -0,0 +1,3 @@ +public class testfile { + +}