diff --git a/BUILD.md b/BUILD.md index defb0d8..7265cc9 100644 --- a/BUILD.md +++ b/BUILD.md @@ -16,8 +16,8 @@ JavaFXLibrary uses Apache Maven as a build tool. are being used by both JavaFXLibrary and the AUT. It's not uncommon that a specific version is needed for AUT and another version of the same dependency is required for JavaFXLibrary(e.g. TestFX dependency for Google Guava). Not always are these dependencies backwards compatible and therefore JavaFXLibrary has adopted Apache Maven Shade Plugin to cope with this issue. - Currently the package com.google.common has been renamed in JavaFXLibrary as shaded.com.google.common to avoid version - mismatches with Google Guava dependencies. See https://maven.apache.org/plugins/maven-shade-plugin/ for more info. + Currently the package com.google.common has been renamed in JavaFXLibrary as shaded.com.google.common and org.apache.commons as shaded.org.apache.commons to avoid version + mismatches with dependencies in AUT and internally. See https://maven.apache.org/plugins/maven-shade-plugin/ for more info. ## Releasing diff --git a/README.md b/README.md index 9d5acd1..0128a0d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ JavaFXLibrary works with both Jython (local and remote use) and Python (remote o JavaFXLibrary is tested to work with Robot Framework 3.0.2 or later. ## Keyword documentation -See keyword [documentation](https://eficode.github.io/JavaFXLibrary/javafxlibrary.html). +See keyword [documentation](https://repo1.maven.org/maven2/org/robotframework/javafxlibrary/0.5.2/javafxlibrary-0.5.2.html). + +For editors (IDEs) keyword documentation can be obtained from [here](https://repo1.maven.org/maven2/org/robotframework/javafxlibrary/0.5.2/javafxlibrary-0.5.2.xml). ## Taking the library into use ### As a local library @@ -17,7 +19,7 @@ See keyword [documentation](https://eficode.github.io/JavaFXLibrary/javafxlibrar *** Settings *** Library JavaFXLibrary ``` -3. Add library jar to Jython [module search path](http://robotframework.org/robotframework/3.0b1/RobotFrameworkUserGuide.html#configuring-where-to-search-libraries-and-other-extensions) and run your tests: +3. Add library jar to Jython [module search path](http://robotframework.org/robotframework/3.0.4/RobotFrameworkUserGuide.html#configuring-where-to-search-libraries-and-other-extensions) and run your tests: ``` jython -J-cp javafxlibrary-.jar -m robot.run tests.robot ``` @@ -70,4 +72,29 @@ Library's acceptance test suite can be used as a JavaFXLibrary demo. Running the Executing _test.sh_ runs the acceptance suite twice: first using JavaFXLibrary as a local Robot Framework library on Jython, and after that using the library in remote mode executing the same tests on python version of Robot Framework. -If you want the suite to run only once, you can define which type of library to use by including **local** or **remote** as an argument. For example command `test.sh remote` will execute the suite only in remote mode. \ No newline at end of file +If you want the suite to run only once, you can define which type of library to use by including **local** or **remote** as an argument. For example command `test.sh remote` will execute the suite only in remote mode. + +## Experimental: Headless support +Library supports headless operation utilizing [Monocle](https://wiki.openjdk.java.net/display/OpenJFX/Monocle). The support for this is still at experimental level. + +### Main issues with headless function +* Scrolling doesn't work same way as with screen + * "Tick" (amount of scrolling) is much smaller in headless than normally + * Vertical (left/right) scrolling is not working +* Separate app windows' can't be closed (unless app offers that functionality itself) +* Swing applications can't be tested in headless mode. + +### Enabling headless mode +Headless mode can be enabled by setting first library initialization to "True". + +Locally: +``` +*** Settings *** +Library JavaFXLibrary ${True} +``` + +Remote: +``` +*** Settings *** +Library Remote http://127.0.0.1:8270 ${True} WITH NAME JavaFXLibrary +``` \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5125fef..ce5cfcb 100644 --- a/pom.xml +++ b/pom.xml @@ -255,6 +255,9 @@ not-ready + + monocle-issue + TRACE:INFO false @@ -369,7 +372,6 @@ org.testfx openjfx-monocle 8u76-b04 - test org.robotframework diff --git a/src/main/java/JavaFXLibrary.java b/src/main/java/JavaFXLibrary.java index c80b415..984259d 100644 --- a/src/main/java/JavaFXLibrary.java +++ b/src/main/java/JavaFXLibrary.java @@ -31,6 +31,7 @@ import javafxlibrary.keywords.AdditionalKeywords.RunOnFailure; import javafxlibrary.utils.HelperFunctions; import javafxlibrary.utils.RobotLog; +import javafxlibrary.utils.TestFxAdapter; import javafxlibrary.utils.TestListener; import org.apache.commons.io.FileUtils; import org.python.google.common.base.Throwables; @@ -58,12 +59,24 @@ public class JavaFXLibrary extends AnnotationLibrary { }}; public JavaFXLibrary() { + this(false); + } + + public JavaFXLibrary(boolean headless) { super(includePatterns); deleteScreenshotsFrom("report-images/imagecomparison"); - //v4.0.15-alpha sets default robot as glass, which breaks rolling - //Forcing usage of awt robot as previous versions - System.setProperty("testfx.robot", "awt"); - } + if (headless) { + System.setProperty("testfx.robot", "glass"); + System.setProperty("testfx.headless", "true"); + System.setProperty("prism.order", "sw"); + System.setProperty("prism.text", "t2k"); + TestFxAdapter.isHeadless = true; + } else { + //v4.0.15-alpha sets default robot as glass, which breaks rolling + //Forcing usage of awt robot as previous versions + System.setProperty("testfx.robot", "awt"); + } + } @Autowired protected RunOnFailure runOnFailure; @@ -136,8 +149,21 @@ public String getKeywordDocumentation(String keywordName) { e.printStackTrace(); return "IOException occured while reading the documentation file!"; } + } else if (keywordName.equals("__init__")) { + try { + return FileUtils.readFileToString(new File("./src/main/java/libdoc-init-documentation.txt"), "utf-8"); + } catch (IOException e) { + e.printStackTrace(); + return "IOException occured while reading the init documentation file!"; + } + } else { + try { + return super.getKeywordDocumentation(keywordName); + } + catch (Exception e) { + return keywordName; + } } - return super.getKeywordDocumentation(keywordName); } /** diff --git a/src/main/java/javafxlibrary/keywords/Keywords/KeyboardRobot.java b/src/main/java/javafxlibrary/keywords/Keywords/KeyboardRobot.java index 828a277..eb31498 100644 --- a/src/main/java/javafxlibrary/keywords/Keywords/KeyboardRobot.java +++ b/src/main/java/javafxlibrary/keywords/Keywords/KeyboardRobot.java @@ -183,20 +183,25 @@ public FxRobotInterface write(String text) { + "| Write Fast | Robot Framework | \n") @ArgumentNames({ "text" }) public void writeFast(String text) { - try { - Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); - StringSelection testData = new StringSelection(text); - c.setContents(testData, testData); - - if(isMac()) - robot.push(KeyCode.META, KeyCode.V).sleep(100); - else - robot.push(KeyCode.CONTROL, KeyCode.V).sleep(100); - } catch (Exception e) { - if(e instanceof JavaFXLibraryNonFatalException) - throw e; - throw new JavaFXLibraryNonFatalException("Unable to write text using copy/paste method.", e); - } + if (TestFxAdapter.isHeadless) { + RobotLog.info("Fast write not working in headless mode. Writing text normally"); + this.write(text); + } else { + try { + Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); + StringSelection testData = new StringSelection(text); + c.setContents(testData, testData); + + if(isMac()) + robot.push(KeyCode.META, KeyCode.V).sleep(100); + else + robot.push(KeyCode.CONTROL, KeyCode.V).sleep(100); + } catch (Exception e) { + if(e instanceof JavaFXLibraryNonFatalException) + throw e; + throw new JavaFXLibraryNonFatalException("Unable to write text using copy/paste method.", e); + } + } } @RobotKeyword("Writes a given text characters one after the other to given locator.\n\n" diff --git a/src/main/java/javafxlibrary/utils/HelperFunctions.java b/src/main/java/javafxlibrary/utils/HelperFunctions.java index 509be25..04e4983 100644 --- a/src/main/java/javafxlibrary/utils/HelperFunctions.java +++ b/src/main/java/javafxlibrary/utils/HelperFunctions.java @@ -29,6 +29,7 @@ import javafx.stage.Window; import javafxlibrary.exceptions.JavaFXLibraryNonFatalException; import javafxlibrary.exceptions.JavaFXLibraryTimeoutException; +import javafxlibrary.keywords.AdditionalKeywords.ConvenienceKeywords; import javafxlibrary.matchers.ProgressBarMatchers; import javafxlibrary.utils.finder.Finder; import org.apache.commons.lang3.StringUtils; @@ -438,13 +439,22 @@ public static void checkClickLocation(Object object) { } RobotLog.trace("Target location checks out OK, it is within active window"); } + + public static void verifyClickLocationOnFront(Object object) { + try { + new ConvenienceKeywords().bringStageToFront((Stage) objectToNode(object).getScene().getWindow()); + } catch (Exception e) { + RobotLog.trace("Node's window wasn't castable to Stage. Tried with object: "+object); + } + } public static Object checkClickTarget(Object target) { try { - if (target instanceof String || target instanceof Node) + if (target instanceof String || target instanceof Node) { target = waitUntilEnabled(waitUntilVisible(target, waitUntilTimeout), waitUntilTimeout); - + verifyClickLocationOnFront(target); + } checkClickLocation(target); return target; diff --git a/src/main/java/javafxlibrary/utils/TestFxAdapter.java b/src/main/java/javafxlibrary/utils/TestFxAdapter.java index 9d79ce7..3fd7b45 100644 --- a/src/main/java/javafxlibrary/utils/TestFxAdapter.java +++ b/src/main/java/javafxlibrary/utils/TestFxAdapter.java @@ -28,6 +28,7 @@ public class TestFxAdapter { + public static boolean isHeadless = false; // current robot instance in use protected static FxRobotInterface robot; public static void setRobot(FxRobotInterface robot) { diff --git a/src/main/java/libdoc-documentation.txt b/src/main/java/libdoc-documentation.txt index 20d20f0..d46f063 100644 --- a/src/main/java/libdoc-documentation.txt +++ b/src/main/java/libdoc-documentation.txt @@ -21,6 +21,9 @@ First, the JavaFXLibrary needs to be taken into use in the settings table. | *Settings* | *Value* | | Library | JavaFXLibrary | +Experimental headless mode can be activated at the import time by setting first argument to ${True} +| *Settings* | *Value* | +| Library | JavaFXLibrary | ${True} | === 2.2 Usage in remote mode(Jython & Python) === When using the test library in remote mode, the library needs to be started at the remote end first. This can be done as follows: @@ -40,7 +43,9 @@ Multiple JavaFXLibraries in remote mode: | Library | Remote | ip_address:8270 | WITH NAME | my_application | | Library | Remote | ip_address:8271 | WITH NAME | my_other_application | - +Experimental headless mode can be activated in remote mode at the import time by setting first argument to ${True} +| *Settings* | *Value* | +| Library | Remote | http://localhost:8270 | ${True} | WITH NAME | JavaFXLibrary | == 3. Locating JavaFX Nodes == === 3.1 Locator syntax === diff --git a/src/main/java/libdoc-init-documentation.txt b/src/main/java/libdoc-init-documentation.txt new file mode 100644 index 0000000..9c67516 --- /dev/null +++ b/src/main/java/libdoc-init-documentation.txt @@ -0,0 +1,3 @@ +JavaFXLibrary can be imported with one optional arguments. + +- ``headless``: Determines if tests will be run in headless mode using [https://wiki.openjdk.java.net/display/OpenJFX/Monocle|Monocle]. Default value is ``false``. diff --git a/src/test/robotframework/acceptance/ScrollRobotTest.robot b/src/test/robotframework/acceptance/ScrollRobotTest.robot index f84cc8d..8ed56ed 100644 --- a/src/test/robotframework/acceptance/ScrollRobotTest.robot +++ b/src/test/robotframework/acceptance/ScrollRobotTest.robot @@ -69,6 +69,7 @@ Scroll Right *** Keywords *** Setup all tests Import JavaFXLibrary + Run Keyword If ${headless} Set Tags monocle-issue Launch Javafx Application ${TEST_APPLICATION} Set Screenshot Directory ${OUTPUT_DIR}${/}report-images Set Variables diff --git a/src/test/robotframework/acceptance/ScrollRobotTest2.robot b/src/test/robotframework/acceptance/ScrollRobotTest2.robot index abe7f4c..6f046e8 100644 --- a/src/test/robotframework/acceptance/ScrollRobotTest2.robot +++ b/src/test/robotframework/acceptance/ScrollRobotTest2.robot @@ -13,23 +13,27 @@ ${TEST_APPLICATION} javafxlibrary.testapps.TestScrollRobot2 *** Test Cases *** Scroll down [Tags] smoke demo-set + Verify String Should Not Match id=verticalScrollLocation max Scroll Vertically DOWN 50 Verify String id=verticalScrollLocation max Scroll up [Tags] smoke demo-set + Verify String Should Not Match id=verticalScrollLocation min Scroll Vertically UP 50 Verify String id=verticalScrollLocation min Scroll right [Tags] smoke demo-set Skip Test On Linux + Verify String Should Not Match id=horizontalScrollLocation max Scroll Horizontally RIGHT 50 Verify String id=horizontalScrollLocation max Scroll left [Tags] smoke demo-set Skip Test On Linux + Verify String Should Not Match id=horizontalScrollLocation min Scroll Horizontally LEFT 50 Verify String id=horizontalScrollLocation min @@ -41,24 +45,28 @@ Scroll down once Scroll up once [Tags] smoke + Verify String Should Not Match id=verticalScrollLocation min Scroll Vertically UP 1 Verify String id=verticalScrollLocation min Scroll Right Once [Tags] smoke Skip Test On Linux + Verify String id=horizontalScrollLocation min Scroll Horizontally RIGHT 1 Verify String Should Not Match id=horizontalScrollLocation min Scroll Left Once [Tags] smoke Skip Test On Linux + Verify String Should Not Match id=horizontalScrollLocation min Scroll Horizontally LEFT 1 Verify String id=horizontalScrollLocation min *** Keywords *** Setup all tests Import JavaFXLibrary + Run Keyword If ${headless} Set Tags monocle-issue Launch Javafx Application ${TEST_APPLICATION} Set Screenshot Directory ${OUTPUT_DIR}${/}report-images Move To id=scrollPane diff --git a/src/test/robotframework/acceptance/SwingApplicationWrapperTest.robot b/src/test/robotframework/acceptance/SwingApplicationWrapperTest.robot index 430e053..1043cfa 100644 --- a/src/test/robotframework/acceptance/SwingApplicationWrapperTest.robot +++ b/src/test/robotframework/acceptance/SwingApplicationWrapperTest.robot @@ -9,6 +9,7 @@ Test Teardown Teardown Test Case *** Testcases *** Swing Embedded JavaFX Click Test [Tags] smoke demo-set + Run Keyword If ${headless} Set Tags monocle-issue Launch Swing Application javafxlibrary.testapps.SwingApplication Wait Until Keyword Succeeds 15 sec 250ms Find css=.button failIfNotFound=True ${colors} Create List 0xdc143cff 0x00fa9aff 0xee82eeff 0xffff00ff 0x00ffffff @@ -19,6 +20,7 @@ Swing Embedded JavaFX Click Test Swing Embedded JavaFX Type Test [Tags] smoke + Run Keyword If ${headless} Set Tags monocle-issue Launch Swing Application javafxlibrary.testapps.SwingApplication Wait Until Keyword Succeeds 15 sec 250ms Find id=textField failIfNotFound=True Write To id=textField JavaFXLibrary @@ -26,6 +28,7 @@ Swing Embedded JavaFX Type Test Launch Swing Application Using External Wrapper Class [Tags] smoke + Run Keyword If ${headless} Set Tags monocle-issue Launch Javafx Application javafxlibrary.testapps.SwingApplicationWrapper Wait Until Keyword Succeeds 15 sec 250ms Find id=textField failIfNotFound=True Write To id=textField JavaFXLibrary diff --git a/src/test/robotframework/acceptance/WindowLookupTest.robot b/src/test/robotframework/acceptance/WindowLookupTest.robot index a0fb5fd..271a7f9 100644 --- a/src/test/robotframework/acceptance/WindowLookupTest.robot +++ b/src/test/robotframework/acceptance/WindowLookupTest.robot @@ -91,6 +91,7 @@ Bring Stage To Front # Keyword is located in TypeRobot Close Current Window [Tags] smoke set-todo + Run Keyword If ${headless} Set Tags monocle-issue ${START} List Windows Activate window @{START}[0] Close Current Window diff --git a/src/test/robotframework/resource.robot b/src/test/robotframework/resource.robot index bff1e77..754f8d3 100644 --- a/src/test/robotframework/resource.robot +++ b/src/test/robotframework/resource.robot @@ -1,10 +1,11 @@ *** Variables *** ${appJar} javafxlibrary-*-tests.jar +${headless} ${False} *** Keywords *** Import JavaFXLibrary - Run Keyword If sys.platform.startswith('java') Import Library JavaFXLibrary - ... ELSE Import Library Remote http://javafxcompile:8270 WITH NAME RemoteJavaFXLibrary + Run Keyword If sys.platform.startswith('java') Import Library JavaFXLibrary ${headless} + ... ELSE Import Library Remote http://javafxcompile:8270 ${headless} WITH NAME RemoteJavaFXLibrary Set To Classpath ${appJar} Disable Embedded Image Logging For Negative Tests