001 /*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2008-2017 the original author or authors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package griffon.javafx.test;
019
020 import griffon.core.ApplicationEvent;
021 import griffon.core.RunnableWithArgs;
022 import griffon.core.env.Environment;
023 import griffon.exceptions.GriffonException;
024 import griffon.javafx.JavaFXGriffonApplication;
025 import javafx.stage.Window;
026 import org.awaitility.Duration;
027 import org.codehaus.griffon.runtime.core.DefaultGriffonApplication;
028 import org.codehaus.griffon.runtime.javafx.TestJavaFXGriffonApplication;
029 import org.junit.rules.MethodRule;
030 import org.junit.runners.model.FrameworkMethod;
031 import org.junit.runners.model.Statement;
032 import org.testfx.api.FxToolkit;
033
034 import javax.annotation.Nonnull;
035 import javax.annotation.Nullable;
036 import java.util.concurrent.TimeoutException;
037
038 import static griffon.javafx.test.TestContext.getTestContext;
039 import static griffon.util.GriffonNameUtils.requireNonBlank;
040 import static java.util.Objects.requireNonNull;
041 import static java.util.concurrent.TimeUnit.SECONDS;
042 import static org.awaitility.Awaitility.await;
043
044 /**
045 * A JUnit Rule that starts an application for each test method.
046 *
047 * @author Andres Almiray
048 * @since 2.3.0
049 */
050 public class GriffonTestFXRule extends TestFX implements MethodRule {
051 protected String windowName;
052 protected Duration timeout;
053 protected String[] startupArgs;
054 protected Class<? extends TestJavaFXGriffonApplication> applicationClass;
055 protected JavaFXGriffonApplication application;
056
057 public GriffonTestFXRule(@Nonnull String windowName) {
058 this(TestJavaFXGriffonApplication.class, windowName, new Duration(10, SECONDS), DefaultGriffonApplication.EMPTY_ARGS);
059 }
060
061 public GriffonTestFXRule(@Nonnull String windowName, @Nonnull Duration timeout) {
062 this(TestJavaFXGriffonApplication.class, windowName, timeout, DefaultGriffonApplication.EMPTY_ARGS);
063 }
064
065 public GriffonTestFXRule(@Nonnull Class<? extends TestJavaFXGriffonApplication> applicationClass, @Nonnull String windowName) {
066 this(applicationClass, windowName, new Duration(10, SECONDS), DefaultGriffonApplication.EMPTY_ARGS);
067 }
068
069 public GriffonTestFXRule(@Nonnull Class<? extends TestJavaFXGriffonApplication> applicationClass, @Nonnull String windowName, @Nonnull Duration timeout) {
070 this(applicationClass, windowName, timeout, DefaultGriffonApplication.EMPTY_ARGS);
071 }
072
073 public GriffonTestFXRule(@Nonnull Class<? extends TestJavaFXGriffonApplication> applicationClass, @Nonnull String windowName, @Nonnull String[] startupArgs) {
074 this(applicationClass, windowName, new Duration(10, SECONDS), startupArgs);
075 }
076
077 public GriffonTestFXRule(@Nonnull Class<? extends TestJavaFXGriffonApplication> applicationClass, @Nonnull String windowName, @Nonnull Duration timeout, @Nonnull String[] startupArgs) {
078 this.applicationClass = requireNonNull(applicationClass, "Argument 'applicationClass' must not be null");
079 this.windowName = requireNonBlank(windowName, "Argument 'windowName' cannot be blank");
080 this.timeout = requireNonNull(timeout, "Argument 'timeout' cannot be blank");
081 requireNonNull(startupArgs, "Argument 'startupArgs' must not be null");
082 this.startupArgs = new String[startupArgs.length];
083 System.arraycopy(startupArgs, 0, this.startupArgs, 0, startupArgs.length);
084 if (!Environment.isSystemSet()) {
085 System.setProperty(Environment.KEY, Environment.TEST.getName());
086 }
087 }
088
089 @Override
090 public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
091 initialize(target);
092
093 return new Statement() {
094 @Override
095 public void evaluate() throws Throwable {
096 FxToolkit.registerPrimaryStage();
097
098 application = (JavaFXGriffonApplication) FxToolkit.setupApplication(applicationClass);
099 WindowShownHandler startingWindow = new WindowShownHandler(windowName);
100 application.getEventRouter().addEventListener(ApplicationEvent.WINDOW_SHOWN.getName(), startingWindow);
101 application.getInjector().injectMembers(target);
102
103 await().timeout(timeout).until(startingWindow::isShowing);
104
105 before(application, target);
106 try {
107 base.evaluate();
108 } finally {
109 after(application, target);
110 }
111 }
112 };
113 }
114
115 protected void initialize(Object target) {
116 getTestContext().setTestCase(target);
117 getTestContext().setWindowName(windowName);
118 }
119
120 protected void before(@Nonnull JavaFXGriffonApplication application, @Nonnull Object target) throws Throwable {
121
122 }
123
124 protected void after(@Nonnull JavaFXGriffonApplication application, @Nonnull Object target) throws TimeoutException {
125 if (application != null) {
126 application.shutdown();
127 try {
128 FxToolkit.cleanupApplication(application);
129 } catch (TimeoutException e) {
130 throw new GriffonException("An error occurred while shutting down the application", e);
131 } finally {
132 this.application = null;
133 }
134 }
135 }
136
137 @Nullable
138 public <W extends Window> W managedWindow(@Nonnull String name) {
139 return (W) application.getWindowManager().findWindow(name);
140 }
141
142 private static class WindowShownHandler implements RunnableWithArgs {
143 private final String windowName;
144 private boolean showing;
145
146 private WindowShownHandler(String windowName) {
147 this.windowName = windowName;
148 }
149
150 public boolean isShowing() {
151 return showing;
152 }
153
154 @Override
155 public void run(Object... args) {
156 if (args != null && args.length > 0 && args[0] instanceof CharSequence) {
157 showing = windowName.equals(String.valueOf(args[0]));
158 }
159 }
160 }
161 }
|