Skip to content

Commit 11c863a

Browse files
committed
Add JUnit test for starting and closing the IntelliJ for UI tests, perform some refactoring
Fixes #17 Signed-off-by: Zbynek Cervinka <[email protected]>
1 parent caafa47 commit 11c863a

File tree

17 files changed

+589
-160
lines changed

17 files changed

+589
-160
lines changed

.github/workflows/ci.yml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# This workflow will build a Java project with Gradle
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3+
4+
name: Java CI with Gradle
5+
6+
on:
7+
push:
8+
branches: [ main ]
9+
pull_request:
10+
branches: [ main ]
11+
12+
jobs:
13+
build-linux:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v2
18+
- name: Set up JDK 11
19+
uses: actions/setup-java@v1
20+
with:
21+
java-version: 11
22+
- name: Run integration tests
23+
run: |
24+
export DISPLAY=:99.0
25+
Xvfb -ac :99 -screen 0 1920x1080x16 &
26+
cd test-project
27+
chmod +x gradlew
28+
./gradlew clean test
29+
- uses: actions/upload-artifact@v1
30+
with:
31+
name: ${{ runner.os }}-test-reports
32+
path: test-project/build/reports/tests/test
33+
if: always()
34+
- name: Archiving screenshots
35+
uses: actions/upload-artifact@v2
36+
with:
37+
name: screenshots
38+
path: |
39+
test-project/build/screenshots/*
40+
41+
build-macos:
42+
runs-on: macos-latest
43+
44+
steps:
45+
- uses: actions/checkout@v2
46+
- name: Set up JDK 11
47+
uses: actions/setup-java@v1
48+
with:
49+
java-version: 11
50+
- name: Run integration tests
51+
run: |
52+
cd test-project
53+
chmod +x gradlew
54+
./gradlew clean test
55+
- uses: actions/upload-artifact@v1
56+
with:
57+
name: ${{ runner.os }}-test-reports
58+
path: test-project/build/reports/tests/test
59+
if: always()
60+
- name: Archiving screenshots
61+
uses: actions/upload-artifact@v2
62+
with:
63+
name: ${{ runner.os }}-screenshots
64+
path: |
65+
test-project/build/screenshots/*
66+
67+
build-windows:
68+
runs-on: windows-latest
69+
70+
steps:
71+
- uses: actions/checkout@v2
72+
- name: Set up JDK 11
73+
uses: actions/setup-java@v1
74+
with:
75+
java-version: 11
76+
- name: Run integration tests
77+
run: |
78+
cd test-project
79+
chmod +x gradlew.bat
80+
.\gradlew.bat clean test
81+
shell: powershell
82+
- uses: actions/upload-artifact@v1
83+
with:
84+
name: ${{ runner.os }}-test-reports
85+
path: test-project/build/reports/tests/test
86+
if: always()
87+
- name: Archiving screenshots
88+
uses: actions/upload-artifact@v2
89+
with:
90+
name: ${{ runner.os }}-screenshots
91+
path: |
92+
test-project/build/screenshots/*
93+

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,13 @@ public static void runIdeForUiTests() {
5757
public static void closeIde() {
5858
UITestRunner.closeIde();
5959
}
60-
```
60+
```
61+
62+
### Run JUnit tests to test this library
63+
64+
You can run JUnit tests contained in this repository to test this library by executing the following command:
65+
66+
```sh
67+
cd test-project
68+
./gradlew test
69+
```

build.gradle

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ plugins {
88
group 'com.redhat.devtools.intellij'
99
version projectVersion
1010

11-
apply plugin: 'maven'
12-
apply plugin: 'io.github.gradle-nexus.publish-plugin'
13-
1411
def remoteRobotVersion = '0.11.2'
1512
def fixturesVersion = '1.1.18'
1613

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
projectVersion=0.0.1
1+
projectVersion=0.0.2-SNAPSHOT
22
nexusUser=invalid
33
nexusPassword=invalid
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

src/main/java/com/redhat/devtools/intellij/commonUiTestLibrary/UITestRunner.java

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,22 @@
1111
package com.redhat.devtools.intellij.commonUiTestLibrary;
1212

1313
import com.intellij.remoterobot.RemoteRobot;
14-
import com.redhat.devtools.intellij.commonUiTestLibrary.utils.GlobalUtils;
15-
16-
import java.io.*;
14+
import com.redhat.devtools.intellij.commonUiTestLibrary.fixtures.dialogs.WelcomeFrameDialog;
15+
16+
import java.io.File;
17+
import java.io.IOException;
18+
import java.io.InputStream;
19+
import java.io.OutputStream;
20+
import java.io.FileOutputStream;
21+
import java.net.InetSocketAddress;
22+
import java.net.Socket;
23+
import java.net.SocketAddress;
1724
import java.nio.file.Files;
1825
import java.nio.file.Path;
1926
import java.nio.file.Paths;
27+
import java.time.Duration;
28+
29+
import static com.intellij.remoterobot.utils.RepeatUtilsKt.waitFor;
2030

2131
/**
2232
* Basic methods for starting and quiting the IntelliJ Idea IDE for UI tests
@@ -34,20 +44,21 @@ public static RemoteRobot runIde(String ideaVersion, int port) {
3444
String osName = System.getProperty("os.name").toLowerCase();
3545
ProcessBuilder pb;
3646
if (osName.contains("windows")) {
37-
pb = new ProcessBuilder("powershell.exe", "Start-Process", ".\\gradlew.bat", "-ArgumentList", "\"runIdeForUiTests -PideaVersion=" + ideaVersion + "\"", "-WindowStyle", "hidden");
47+
pb = new ProcessBuilder(".\\gradlew.bat", "runIdeForUiTests", "-PideaVersion=" + ideaVersion, "-Drobot-server.port=" + port);
3848
} else {
3949
pb = new ProcessBuilder("./gradlew", "runIdeForUiTests", "-PideaVersion=" + ideaVersion, "-Drobot-server.port=" + port);
4050
}
4151

4252
try {
4353
ideProcess = pb.start();
44-
GlobalUtils.waitUntilIntelliJStarts(port);
45-
robot = GlobalUtils.getRemoteRobotConnection(port);
54+
waitUntilIntelliJStarts(port);
55+
robot = getRemoteRobotConnection(port);
4656
} catch (IOException | InterruptedException e) {
4757
e.printStackTrace();
4858
}
4959

50-
GlobalUtils.clearTheWorkspace();
60+
WelcomeFrameDialog wfd = robot.find(WelcomeFrameDialog.class, Duration.ofSeconds(10));
61+
wfd.clearTheWorkspace();
5162
return robot;
5263
}
5364

@@ -56,7 +67,11 @@ public static RemoteRobot runIde(String ideaVersion) {
5667
}
5768

5869
public static void closeIde() {
59-
ideProcess.destroy();
70+
if (robot.isWin()) {
71+
robot.find(WelcomeFrameDialog.class, Duration.ofSeconds(10)).windowsCloseButton().click();
72+
} else {
73+
ideProcess.destroy();
74+
}
6075
}
6176

6277
public static RemoteRobot getRemoteRobotInstance() {
@@ -76,8 +91,7 @@ private static void makeSureAllTermsAndConditionsAreAccepted() {
7691
String acceptedDir = System.getProperty("user.home") + "/.local/share/JetBrains/consentOptions";
7792
createDirectoryHierarchy(acceptedDir);
7893
copyFileFromJarResourceDir(acceptedSourceLocation, acceptedDir + "/accepted");
79-
}
80-
else if (osName.contains("os x")) {
94+
} else if (osName.contains("os x")) {
8195
String plistSourceLocation = "com.apple.java.util.prefs.plist";
8296
String plistDir = System.getProperty("user.home") + "/Library/Preferences";
8397
copyFileFromJarResourceDir(plistSourceLocation, plistDir + "/com.apple.java.util.prefs.plist");
@@ -95,16 +109,15 @@ else if (osName.contains("os x")) {
95109
} catch (IOException | InterruptedException e) {
96110
e.printStackTrace();
97111
}
98-
}
99-
else if (osName.contains("windows")) {
112+
} else if (osName.contains("windows")) {
100113
String acceptedSourceLocation = "accepted";
101114
String acceptedDir = System.getProperty("user.home") + "\\AppData\\Roaming\\JetBrains\\consentOptions";
102115
createDirectoryHierarchy(acceptedDir);
103116
copyFileFromJarResourceDir(acceptedSourceLocation, acceptedDir + "\\accepted");
104117

105118
String registryPath = "HKCU:\\Software\\JavaSoft\\Prefs\\jetbrains\\privacy_policy";
106119
ProcessBuilder pb1 = new ProcessBuilder("powershell.exe", "New-Item", "-Path", registryPath, "-Force");
107-
ProcessBuilder pb2 = new ProcessBuilder("powershell.exe", "New-ItemProperty", "-Path", registryPath, "-Name", "accepted_version", "-Value", "\"2.1\"");
120+
ProcessBuilder pb2 = new ProcessBuilder("powershell.exe", "New-ItemProperty", "-Path", registryPath, "-Name", "accepted_version", "-Value", "'2.1'");
108121

109122
try {
110123
Process p1 = pb1.start();
@@ -117,6 +130,39 @@ else if (osName.contains("windows")) {
117130
}
118131
}
119132

133+
private static void waitUntilIntelliJStarts(int port) {
134+
waitFor(Duration.ofSeconds(600), Duration.ofSeconds(3), "The IntelliJ Idea did not start in 10 minutes.", () -> isIntelliJUIVisible(port));
135+
}
136+
137+
private static boolean isIntelliJUIVisible(int port) {
138+
return isHostOnIpAndPortAccessible("127.0.0.1", port);
139+
}
140+
141+
private static boolean isHostOnIpAndPortAccessible(String ip, int port) {
142+
SocketAddress sockaddr = new InetSocketAddress(ip, port);
143+
Socket socket = new Socket();
144+
145+
try {
146+
socket.connect(sockaddr, 10000);
147+
} catch (IOException IOException) {
148+
return false;
149+
}
150+
return true;
151+
}
152+
153+
public static RemoteRobot getRemoteRobotConnection(int port) throws InterruptedException {
154+
RemoteRobot remoteRobot = new RemoteRobot("http://127.0.0.1:" + port);
155+
for (int i = 0; i < 60; i++) {
156+
try {
157+
remoteRobot.find(WelcomeFrameDialog.class);
158+
} catch (Exception ex) {
159+
Thread.sleep(1000);
160+
}
161+
}
162+
163+
return remoteRobot;
164+
}
165+
120166
private static void createDirectoryHierarchy(String location) {
121167
Path path = Paths.get(location);
122168
try {

src/main/java/com/redhat/devtools/intellij/commonUiTestLibrary/fixtures/dialogs/WelcomeFrameDialog.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,20 @@
1616
import com.intellij.remoterobot.fixtures.ContainerFixture;
1717
import com.intellij.remoterobot.fixtures.DefaultXpath;
1818
import com.intellij.remoterobot.fixtures.FixtureName;
19+
import com.intellij.remoterobot.utils.WaitForConditionTimeoutException;
1920
import com.redhat.devtools.intellij.commonUiTestLibrary.fixtures.other.ActionLink;
21+
import com.redhat.devtools.intellij.commonUiTestLibrary.utils.TextHelper;
22+
import org.apache.commons.io.FileUtils;
2023
import org.jetbrains.annotations.NotNull;
2124

25+
import java.io.File;
26+
import java.io.IOException;
27+
import java.nio.file.Files;
28+
import java.nio.file.Paths;
29+
import java.time.Duration;
30+
2231
import static com.intellij.remoterobot.search.locators.Locators.byXpath;
32+
import static com.intellij.remoterobot.stepsProcessing.StepWorkerKt.step;
2333

2434
/**
2535
* Welcome to IntelliJ IDEA dialog fixture
@@ -44,4 +54,69 @@ public ComponentFixture importProjectLink() {
4454
public ComponentFixture ideErrorsIcon() {
4555
return find(ComponentFixture.class, byXpath("//div[@class='IdeErrorsIcon']"));
4656
}
57+
58+
public ComponentFixture windowsCloseButton() {
59+
return find(ComponentFixture.class, byXpath("//div[@accessiblename='Close' and @class='JButton']"));
60+
}
61+
62+
public void clearTheWorkspace() {
63+
step("Delete all the projects in the workspace", () -> {
64+
// delete all the projects' links from the 'Welcome to IntelliJ IDEA' dialog
65+
int numberOfLinks = getNumberOfProjectLinks();
66+
for (int i = 0; i < numberOfLinks; i++) {
67+
ComponentFixture cf = this.find(ComponentFixture.class, byXpath("//div[@accessiblename='Recent Projects' and @class='MyList']"));
68+
cf.runJs("const horizontal_offset = component.getWidth()-22;\n" +
69+
"robot.click(component, new Point(horizontal_offset, 22), MouseButton.LEFT_BUTTON, 1);");
70+
}
71+
72+
// delete all the files and folders in the IdeaProjects folder
73+
try {
74+
String pathToDirToMakeEmpty = System.getProperty("user.home") + File.separator + "IdeaProjects";
75+
boolean doesTheProjectDirExists = Files.exists(Paths.get(pathToDirToMakeEmpty));
76+
if (doesTheProjectDirExists) {
77+
FileUtils.cleanDirectory(new File(pathToDirToMakeEmpty));
78+
} else {
79+
Files.createDirectory(Paths.get(pathToDirToMakeEmpty));
80+
}
81+
} catch (IOException e) {
82+
e.printStackTrace();
83+
}
84+
});
85+
}
86+
87+
private int getNumberOfProjectLinks() {
88+
try {
89+
ComponentFixture cf = this.find(ComponentFixture.class, byXpath("//div[@accessiblename='Recent Projects' and @class='MyList']"));
90+
int numberOfProjectsLinks = cf.findAllText().size() / 2; // 2 items per 1 project link (project path and project name)
91+
return numberOfProjectsLinks;
92+
} catch (WaitForConditionTimeoutException e) {
93+
// the list with accessible name 'Recent Projects' is not available -> 0 links in the 'Welcome to IntelliJ IDEA' dialog
94+
return 0;
95+
}
96+
}
97+
98+
public void checkForExceptions(RemoteRobot robot) {
99+
step("Check for exceptions and other errors", () -> {
100+
try {
101+
this.ideErrorsIcon().click();
102+
} catch (WaitForConditionTimeoutException e) {
103+
e.printStackTrace();
104+
return;
105+
}
106+
107+
final IdeFatalErrorsDialog ideFatalErrorsDialogFixture = robot.find(IdeFatalErrorsDialog.class, Duration.ofSeconds(10));
108+
String exceptionNumberLabel = ideFatalErrorsDialogFixture.numberOfExcetionsJBLabel().findAllText().get(0).getText();
109+
int numberOfExceptions = Integer.parseInt(exceptionNumberLabel.substring(5));
110+
111+
for (int i = 0; i < numberOfExceptions; i++) {
112+
String exceptionStackTrace = TextHelper.listOfRemoteTextToString(ideFatalErrorsDialogFixture.exceptionDescriptionJTextArea().findAllText());
113+
114+
if (i + 1 < numberOfExceptions) {
115+
ideFatalErrorsDialogFixture.nextExceptionButton().click();
116+
}
117+
}
118+
119+
ideFatalErrorsDialogFixture.button("Clear all").click();
120+
});
121+
}
47122
}

0 commit comments

Comments
 (0)