Skip to content

Experimental headless #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Feb 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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-<version>.jar -m robot.run tests.robot
```
Expand Down Expand Up @@ -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.
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
```
4 changes: 3 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@
<excludes>
<exclude>not-ready</exclude>
</excludes>
<nonCriticalTags>
<nonCriticalTag>monocle-issue</nonCriticalTag>
</nonCriticalTags>
<logLevel>TRACE:INFO</logLevel>
<dryrun>false</dryrun>
<variables>
Expand Down Expand Up @@ -369,7 +372,6 @@
<groupId>org.testfx</groupId>
<artifactId>openjfx-monocle</artifactId>
<version>8u76-b04</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.robotframework</groupId>
Expand Down
36 changes: 31 additions & 5 deletions src/main/java/JavaFXLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

/**
Expand Down
33 changes: 19 additions & 14 deletions src/main/java/javafxlibrary/keywords/Keywords/KeyboardRobot.java
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/javafxlibrary/utils/HelperFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions src/main/java/javafxlibrary/utils/TestFxAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/libdoc-documentation.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 ===
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/libdoc-init-documentation.txt
Original file line number Diff line number Diff line change
@@ -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``.
1 change: 1 addition & 0 deletions src/test/robotframework/acceptance/ScrollRobotTest.robot
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/test/robotframework/acceptance/ScrollRobotTest2.robot
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -19,13 +20,15 @@ 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
Wait Until Keyword Succeeds 3 sec 250ms Text Value Should Be JavaFXLibrary

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
Expand Down
1 change: 1 addition & 0 deletions src/test/robotframework/acceptance/WindowLookupTest.robot
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions src/test/robotframework/resource.robot
Original file line number Diff line number Diff line change
@@ -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
Expand Down