All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.testfx.api.FxToolkit Maven / Gradle / Ivy

/*
 * Copyright 2013-2014 SmartBear Software
 * Copyright 2014-2019 The TestFX Contributors
 *
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the
 * European Commission - subsequent versions of the EUPL (the "Licence"); You may
 * not use this work except in compliance with the Licence.
 *
 * You may obtain a copy of the Licence at:
 * http://ec.europa.eu/idabc/eupl.html
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the Licence for the
 * specific language governing permissions and limitations under the Licence.
 */
package org.testfx.api;

import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.Window;

import org.testfx.toolkit.ApplicationLauncher;
import org.testfx.toolkit.ApplicationService;
import org.testfx.toolkit.ToolkitService;
import org.testfx.toolkit.impl.ApplicationLauncherImpl;
import org.testfx.toolkit.impl.ApplicationServiceImpl;
import org.testfx.toolkit.impl.ToolkitServiceImpl;

import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.testfx.internal.JavaVersionAdapter.getWindows;
import static org.testfx.util.WaitForAsyncUtils.waitFor;
import static org.testfx.util.WaitForAsyncUtils.waitForFxEvents;

/**
 * Responsible for setup and cleanup of JavaFX fixtures that need the JavaFX thread.
 * 

*

Overview

*

* This class methods cover three different kinds of fixtures: *

    *
  1. Container fixtures, which are registered as {@code registeredStage}.
  2. *
  3. Content fixtures, which are attached to the registered {@code registeredStage}.
  4. *
  5. Individual fixtures, which do not require a {@code registeredStage}.
  6. *
* Additionally it keeps an internal context. *

*

1. Container Fixtures

*

* They can be registered as {@code registeredStage} and provide a top-level container, i.e. * {@link Stage}s. *

* The primary stage can be registered as {@code registeredStage} using {@link #registerPrimaryStage}. * This call is mandatory before any other JavaFX fixture can be created. *

* Other stages can be registered as {@code registeredStage} using {@link #registerStage * registerStage(Supplier<Stage>)}. *

*

2. Content Fixtures

*

* They can be attached to the {@code registeredStage}. *

* Either constructed by calling an {@link Application#start Application.start()}, by * supplying {@link Scene}s, {@link Parent}s, or by consuming a {@link Stage}. *

* Use: {@link #setupStage setupStage(Consumer<Stage>)}, * {@link #setupApplication setupApplication(Class<? extends Application>)}, * {@link #setupScene setupScene(Supplier<Scene>)} or * {@link #setupSceneRoot setupSceneRoot(Supplier<Parent>)} *

*

3. Individual Fixtures

*

* To setup individual Stages, Scenes or Nodes use {@link #setupFixture(Runnable)} and * {@link #setupFixture(Callable)}. *

*

Internal Context

*

* Is internally responsible for handle the registered Stage for attachments, * handle timeouts, provide the Application for the Toolkit launch and execute the setup * in the JavaFX thread. The primary Stage is constructed by the platform. */ public final class FxToolkit { private static final ApplicationLauncher APP_LAUNCHER = new ApplicationLauncherImpl(); private static final ApplicationService APP_SERVICE = new ApplicationServiceImpl(); private static final FxToolkitContext CONTEXT = new FxToolkitContext(); private static final ToolkitService SERVICE = new ToolkitServiceImpl(APP_LAUNCHER, APP_SERVICE); private FxToolkit() {} /** * Sets up the {@link org.testfx.toolkit.PrimaryStageApplication} to use in tests, prevents it from shutting * down when the last window is closed, and returns the {@link Stage} from {@link Application#start(Stage)}. * * @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getLaunchTimeoutInMillis()} */ public static Stage registerPrimaryStage() throws TimeoutException { Stage primaryStage = waitFor(CONTEXT.getLaunchTimeoutInMillis(), MILLISECONDS, SERVICE.setupPrimaryStage(CONTEXT.getPrimaryStageFuture(), CONTEXT.getApplicationClass(), CONTEXT.getApplicationArgs())); CONTEXT.setRegisteredStage(primaryStage); Platform.setImplicitExit(false); return primaryStage; } /** * Runs the stageSupplier on the {@code JavaFX Application Thread}, registers the supplied stage, * and returns that stage. * * @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()} */ public static Stage registerStage(Supplier stageSupplier) throws TimeoutException { Stage stage = setupFixture(stageSupplier::get); CONTEXT.setRegisteredStage(stage); return stage; } /** * Sets up the registered stage by passing it into the given {@code stageConsumer} on the * {@code JavaFX Application Thread} and returns the stage once finished. * * @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()} */ public static Stage setupStage(Consumer stageConsumer) throws TimeoutException { return waitForSetup(SERVICE.setupStage(CONTEXT.getRegisteredStage(), stageConsumer)); } /** * Sets up the given application with its given arguments and returns that application once finished. * * @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()} */ public static Application setupApplication(Class applicationClass, String... applicationArgs) throws TimeoutException { return waitForSetup(SERVICE.setupApplication(CONTEXT::getRegisteredStage, applicationClass, applicationArgs)); } /** * Sets up the supplied application and returns that application once finished. * * @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()} */ public static Application setupApplication(Supplier applicationSupplier) throws TimeoutException { return waitForSetup(SERVICE.setupApplication(CONTEXT::getRegisteredStage, applicationSupplier)); } /** * Performs the clean up of the application. This is done by calling * {@link ToolkitService#cleanupApplication(Application)} (which usually * calls the {@code stop} method of the application). * * @param application the application to clean up * @throws TimeoutException if cleanup is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()} * or the FX Application Thread is not running */ public static void cleanupApplication(Application application) throws TimeoutException { if (isFXApplicationThreadRunning()) { waitForSetup(SERVICE.cleanupApplication(application)); } else { throw new TimeoutException("FX Application Thread not running"); } } /** * Runs the {@code sceneSupplier} on the {@code JavaFX Application Thread}, sets the registered stage's scene to the * supplied scene, and returns the supplied scene once finished. * * @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()} */ public static Scene setupScene(Supplier sceneSupplier) throws TimeoutException { return waitForSetup(SERVICE.setupScene(CONTEXT.getRegisteredStage(), sceneSupplier)); } /** * Runs the {@code sceneRootSupplier} on the {@code JavaFX Application Thread}, sets the registered stage's scene's * root node to the supplied root node, and returns the supplied root node once finished. */ public static Parent setupSceneRoot(Supplier sceneRootSupplier) throws TimeoutException { return waitForSetup(SERVICE.setupSceneRoot(CONTEXT.getRegisteredStage(), sceneRootSupplier)); } /** * Runs the given {@code runnable} on the {@code JavaFX Application Thread} and returns once finished. */ public static void setupFixture(Runnable runnable) throws TimeoutException { waitForSetup(SERVICE.setupFixture(runnable)); } /** * Runs the given {@code callable} on the {@code JavaFX Application Thread} and returns once finished. */ public static T setupFixture(Callable callable) throws TimeoutException { return waitForSetup(SERVICE.setupFixture(callable)); } /** * Runs on the {@code JavaFX Application Thread}: Shows the registered stage via {@link Stage#show()}, * moves it to the front via {@link Stage#toFront()}, and returns once finished. */ public static void showStage() throws TimeoutException { setupStage(stage -> { stage.show(); stage.toBack(); stage.toFront(); }); } /** * Runs on the {@code JavaFX Application Thread}: Hides the registered stage via {@link Stage#hide()} * and returns once finished. */ public static void hideStage() throws TimeoutException { setupStage(Window::hide); } /** * Runs on the {@code JavaFX Application Thread}: Hides all windows returned from * {@link org.testfx.internal.JavaVersionAdapter#getWindows()} and returns once finished. */ public static void cleanupStages() throws TimeoutException { setupFixture(() -> getWindows().forEach(Window::hide)); } /** * Returns the internal context. */ public static FxToolkitContext toolkitContext() { return CONTEXT; } /** * Waits for the given future to be set before returning or times out after * {@link FxToolkitContext#getSetupTimeoutInMillis()} is reached. */ private static T waitForSetup(Future future) throws TimeoutException { T ret = waitFor(CONTEXT.getSetupTimeoutInMillis(), MILLISECONDS, future); waitForFxEvents(); return ret; } /** * Detects if the JavaFx Application Thread is currently running. * @return {@literal true} if the FX Application Thread is running, false otherwise */ public static boolean isFXApplicationThreadRunning() { Set threads = Thread.getAllStackTraces().keySet(); for (Thread thread : threads) { if (thread.getName().equals("JavaFX Application Thread")) { return true; } } return false; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy