/**
* JFXtrasGuiTest.java
*
* Copyright (c) 2011-2016, JFXtras
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the organization nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jfxtras.test;
import java.util.Locale;
import java.util.Set;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.testfx.api.FxRobot;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.stage.Popup;
import javafx.stage.Stage;
import javafx.stage.Window;
/**
*
* @author Tom Eugelink
*/
abstract public class JFXtrasGuiTest extends org.testfx.framework.junit.ApplicationTest {
@Rule public TestName testName = new TestName();
// TODO: let's implement this as a rule so we can keep using the @Before
@Before
public void before() throws Throwable {
System.out.println("========================================================================\n" + this.getClass().getSimpleName() + "." + testName.getMethodName());
// default we're in US locale: keep (re)setting this for each test
Locale.setDefault(Locale.US);
// catch any exception during rendering
Thread.currentThread().setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
Assert.fail("This should not occur\n" + e);
}
});
// small delay to get things going
TestUtil.waitForPaintPulse();
}
@After
public void after() {
// this is required, otherwise a popup from a previous test may influence the active test
forceCloseAllPopups();
}
@Override
public void start(Stage stage) throws Exception {
this.stage = stage;
Scene scene = new Scene(getRootNode());
stage.setScene(scene);
stage.show();
}
protected Stage stage;
/**
* Override public void start(Stage stage) throws Exception
* @return
*/
@Deprecated
protected Parent getRootNode() {
if (1 == 1) {
throw new IllegalStateException("This method should not be called");
}
return null;
}
/**
* Click with a qualifier pressed
* @param matcher
* @param keyCode
* @param keyCodes
*/
public FxRobot clickOn(String matcher, KeyCode keyCode, KeyCode... keyCodes) {
press(keyCode);
for (int i = 0; i < keyCodes.length; i++) {
press(keyCodes[i]);
}
clickOn(matcher);
for (int i = keyCodes.length - 1; i >=0 ; i--) {
release(keyCodes[i]);
}
return release(keyCode);
}
protected void assertPopupIsNotVisible(Node ownedBy) {
TestUtil.waitForPaintPulse();
for (Window w : listWindows() ) {
if (w instanceof Popup) {
Popup lPopup = (Popup)w;
if (ownedBy.equals(lPopup.getOwnerNode())) {
throw new IllegalStateException("Popup is visible (and should not be), owner = " + lPopup.getOwnerNode());
}
}
}
}
protected void assertPopupIsVisible(Node ownedBy) {
TestUtil.waitForPaintPulse();
for (Window w : listWindows() ) {
if (w instanceof Popup) {
Popup lPopup = (Popup)w;
if (ownedBy.equals(lPopup.getOwnerNode())) {
return;
}
}
}
throw new IllegalStateException("Popup is not visible (and should be)");
}
protected void forceCloseAllPopups() {
TestUtil.waitForPaintPulse();
for (Window w : listWindows() ) {
if (w instanceof Popup) {
Popup lPopup = (Popup)w;
System.out.println("force closing popup: " + lPopup);
TestUtil.runThenWaitForPaintPulse( () -> {
lPopup.hide();
});
}
}
}
protected void clear(Node textField) {
clickOn(textField);
push(KeyCode.CONTROL, KeyCode.A);
push(KeyCode.DELETE);
}
protected void assertNotFind(String string) {
if (find(string) != null) {
Assert.fail("Expected not to find: " + string);
}
}
protected void assertNotVisible(String string) {
Node lNode = find(string);
if (lNode.isVisible()) {
Assert.fail("Should not have found '" + string + "', but did anyway");
}
}
protected void assertFind(String string) {
if (find(string) == null) {
Assert.fail("Not found: " + string);
}
}
protected <T extends Node> T find(String matcher) {
Set<Node> lNodes = lookup(matcher).queryAll();
if (lNodes.isEmpty()) {
return null;
}
return (T)lNodes.iterator().next();
}
/**
* Use clickOn
*/
@Deprecated
protected void click(String matcher) {
clickOn(matcher);
}
/**
* Use clickOn
*/
public void click(String matcher, KeyCode keyCode, KeyCode... keyCodes) {
clickOn(matcher, keyCode, keyCodes);
}
/**
* Use moveTo
*/
@Deprecated
protected void move(String matcher) {
moveTo(matcher);
}
/**
* Use write
*/
@Deprecated
protected void type(String text) {
write(text);
}
}