Skip to content

Commit c59f7d9

Browse files
authored
Introduce fixtures & tests, config update
1 parent 7bdf832 commit c59f7d9

File tree

30 files changed

+1912
-264
lines changed

30 files changed

+1912
-264
lines changed

.github/workflows/ci.yml

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ jobs:
2222
- name: Run integration tests
2323
run: |
2424
export DISPLAY=:99.0
25-
Xvfb -ac :99 -screen 0 1920x1080x16 &
25+
Xvfb -ac :99 -screen 0 1920x1080x24 &
2626
cd test-project
2727
chmod +x gradlew
28-
./gradlew clean test
29-
- uses: actions/upload-artifact@v1
28+
./gradlew clean test --warning-mode none
29+
- uses: actions/upload-artifact@v2
3030
with:
3131
name: ${{ runner.os }}-test-reports
3232
path: test-project/build/reports/tests/test
3333
if: always()
3434
- name: Archiving screenshots
3535
uses: actions/upload-artifact@v2
3636
with:
37-
name: screenshots
38-
path: |
39-
test-project/build/screenshots/*
37+
name: ${{ runner.os }}-screenshots
38+
path: test-project/build/screenshots/*
39+
if: always()
4040

4141
build-macos:
4242
runs-on: macos-latest
@@ -51,8 +51,8 @@ jobs:
5151
run: |
5252
cd test-project
5353
chmod +x gradlew
54-
./gradlew clean test
55-
- uses: actions/upload-artifact@v1
54+
./gradlew clean test --warning-mode none
55+
- uses: actions/upload-artifact@v2
5656
with:
5757
name: ${{ runner.os }}-test-reports
5858
path: test-project/build/reports/tests/test
@@ -61,8 +61,8 @@ jobs:
6161
uses: actions/upload-artifact@v2
6262
with:
6363
name: ${{ runner.os }}-screenshots
64-
path: |
65-
test-project/build/screenshots/*
64+
path: test-project/build/screenshots/*
65+
if: always()
6666

6767
build-windows:
6868
runs-on: windows-latest
@@ -77,9 +77,9 @@ jobs:
7777
run: |
7878
cd test-project
7979
chmod +x gradlew.bat
80-
.\gradlew.bat clean test
80+
.\gradlew.bat clean test --warning-mode none
8181
shell: powershell
82-
- uses: actions/upload-artifact@v1
82+
- uses: actions/upload-artifact@v2
8383
with:
8484
name: ${{ runner.os }}-test-reports
8585
path: test-project/build/reports/tests/test
@@ -88,6 +88,5 @@ jobs:
8888
uses: actions/upload-artifact@v2
8989
with:
9090
name: ${{ runner.os }}-screenshots
91-
path: |
92-
test-project/build/screenshots/*
93-
91+
path: test-project/build/screenshots/*
92+
if: always()

build.gradle

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

11-
def remoteRobotVersion = '0.11.2'
12-
def fixturesVersion = '1.1.18'
11+
def remoteRobotVersion = '0.11.6'
1312

1413
repositories {
1514
mavenLocal()
@@ -26,7 +25,7 @@ dependencies {
2625
api 'org.junit.jupiter:junit-jupiter-api:5.3.1'
2726
api 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
2827
api "com.intellij.remoterobot:remote-robot:$remoteRobotVersion"
29-
api "com.intellij.remoterobot:remote-fixtures:$fixturesVersion"
28+
api "com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion"
3029
}
3130

3231
java {

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

Lines changed: 92 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
package com.redhat.devtools.intellij.commonUiTestLibrary;
1212

1313
import com.intellij.remoterobot.RemoteRobot;
14-
import com.redhat.devtools.intellij.commonUiTestLibrary.fixtures.dialogs.WelcomeFrameDialog;
14+
import com.intellij.remoterobot.fixtures.ComponentFixture;
15+
import com.intellij.remoterobot.utils.WaitForConditionTimeoutException;
16+
import com.redhat.devtools.intellij.commonUiTestLibrary.fixtures.dialogs.FlatWelcomeFrame;
1517

1618
import java.io.File;
1719
import java.io.IOException;
@@ -26,6 +28,7 @@
2628
import java.nio.file.Paths;
2729
import java.time.Duration;
2830

31+
import static com.intellij.remoterobot.search.locators.Locators.byXpath;
2932
import static com.intellij.remoterobot.utils.RepeatUtilsKt.waitFor;
3033

3134
/**
@@ -35,47 +38,117 @@
3538
*/
3639
public class UITestRunner {
3740
private static final int defaultPort = 8580;
38-
private static RemoteRobot robot = null;
41+
private static RemoteRobot remoteRobot = null;
3942
private static Process ideProcess;
40-
41-
public static RemoteRobot runIde(String ideaVersion, int port) {
43+
private static IdeaVersion ideaVersion;
44+
45+
/**
46+
* Start the given version of IntelliJ Idea listening on the given port
47+
*
48+
* @param ideaVersion version of the IntelliJ Idea to start
49+
* @param port port number on which will the IntelliJ Idea be listening
50+
*/
51+
public static RemoteRobot runIde(IdeaVersion ideaVersion, int port) {
52+
UITestRunner.ideaVersion = ideaVersion;
4253
makeSureAllTermsAndConditionsAreAccepted();
4354

4455
String osName = System.getProperty("os.name").toLowerCase();
45-
ProcessBuilder pb;
46-
if (osName.contains("windows")) {
47-
pb = new ProcessBuilder(".\\gradlew.bat", "runIdeForUiTests", "-PideaVersion=" + ideaVersion, "-Drobot-server.port=" + port);
48-
} else {
49-
pb = new ProcessBuilder("./gradlew", "runIdeForUiTests", "-PideaVersion=" + ideaVersion, "-Drobot-server.port=" + port);
50-
}
56+
String fileExtension = osName.contains("windows") ? ".bat" : "";
57+
ProcessBuilder pb = new ProcessBuilder("." + File.separator + "gradlew" + fileExtension, "runIdeForUiTests", "-PideaVersion=" + ideaVersion.toString(), "-Drobot-server.port=" + port);
5158

5259
try {
5360
ideProcess = pb.start();
5461
waitUntilIntelliJStarts(port);
55-
robot = getRemoteRobotConnection(port);
62+
remoteRobot = getRemoteRobotConnection(port);
5663
} catch (IOException | InterruptedException e) {
5764
e.printStackTrace();
5865
}
5966

60-
WelcomeFrameDialog wfd = robot.find(WelcomeFrameDialog.class, Duration.ofSeconds(10));
61-
wfd.clearTheWorkspace();
62-
return robot;
67+
FlatWelcomeFrame flatWelcomeFrame = remoteRobot.find(FlatWelcomeFrame.class, Duration.ofSeconds(10));
68+
flatWelcomeFrame.clearWorkspace();
69+
return remoteRobot;
6370
}
6471

65-
public static RemoteRobot runIde(String ideaVersion) {
72+
/**
73+
* Start the given version of IntelliJ Idea listening on the default port
74+
*
75+
* @param ideaVersion version of the IntelliJ Idea to start
76+
*/
77+
public static RemoteRobot runIde(IdeaVersion ideaVersion) {
6678
return runIde(ideaVersion, defaultPort);
6779
}
6880

81+
/**
82+
* Close the IntelliJ Idea IDE from the 'Welcome to IntelliJ IDEA' dialog
83+
*/
6984
public static void closeIde() {
70-
if (robot.isWin()) {
71-
robot.find(WelcomeFrameDialog.class, Duration.ofSeconds(10)).windowsCloseButton().click();
85+
if (remoteRobot.isWin()) {
86+
ComponentFixture windowsCloseButton = remoteRobot.find(ComponentFixture.class, byXpath("//div[@accessiblename='Close' and @class='JButton']"), Duration.ofSeconds(10));
87+
windowsCloseButton.click();
7288
} else {
7389
ideProcess.destroy();
7490
}
7591
}
7692

77-
public static RemoteRobot getRemoteRobotInstance() {
78-
return robot;
93+
/**
94+
* Return the integer representation of the currently running IntelliJ Idea version
95+
*
96+
* @return version of the currently running IntelliJ Idea
97+
*/
98+
public static IdeaVersion getIdeaVersion() {
99+
return ideaVersion;
100+
}
101+
102+
/**
103+
* Return the reference to the Remote Robot instance
104+
*
105+
* @return reference to the Remote Robot instance
106+
*/
107+
public static RemoteRobot getRemoteRobot() {
108+
return remoteRobot;
109+
}
110+
111+
/**
112+
* Create an instance of the RemoteRobot listening on the given port
113+
*
114+
* @param port port number
115+
* @return instance of the RemoteRobot
116+
*/
117+
public static RemoteRobot getRemoteRobotConnection(int port) throws InterruptedException {
118+
RemoteRobot remoteRobot = new RemoteRobot("http://127.0.0.1:" + port);
119+
for (int i = 0; i < 60; i++) {
120+
try {
121+
remoteRobot.find(FlatWelcomeFrame.class);
122+
} catch (WaitForConditionTimeoutException e) {
123+
Thread.sleep(1000);
124+
}
125+
}
126+
127+
return remoteRobot;
128+
}
129+
130+
/**
131+
* Enumeration for supported versions of the IntelliJ Idea
132+
*/
133+
public enum IdeaVersion {
134+
V_2020_2("IC-2020.2"),
135+
V_2020_3("IC-2020.3");
136+
137+
final private String ideaVersionStringRepresentation;
138+
139+
IdeaVersion(String ideaVersionStringRepresentation) {
140+
this.ideaVersionStringRepresentation = ideaVersionStringRepresentation;
141+
}
142+
143+
@Override
144+
public String toString() {
145+
return ideaVersionStringRepresentation;
146+
}
147+
148+
public int toInt() {
149+
String ideaVersion = this.ideaVersionStringRepresentation.substring(3).replace(".", "");
150+
return Integer.parseInt(ideaVersion);
151+
}
79152
}
80153

81154
private static void makeSureAllTermsAndConditionsAreAccepted() {
@@ -150,19 +223,6 @@ private static boolean isHostOnIpAndPortAccessible(String ip, int port) {
150223
return true;
151224
}
152225

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-
166226
private static void createDirectoryHierarchy(String location) {
167227
Path path = Paths.get(location);
168228
try {
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2021 Red Hat, Inc.
3+
* Distributed under license by Red Hat, Inc. All rights reserved.
4+
* This program is made available under the terms of the
5+
* Eclipse Public License v2.0 which accompanies this distribution,
6+
* and is available at https://www.eclipse.org/legal/epl-v20.html
7+
*
8+
* Contributors:
9+
* Red Hat, Inc. - initial API and implementation
10+
******************************************************************************/
11+
package com.redhat.devtools.intellij.commonUiTestLibrary.fixtures.dialogs;
12+
13+
import com.intellij.remoterobot.RemoteRobot;
14+
import com.intellij.remoterobot.data.RemoteComponent;
15+
import com.intellij.remoterobot.fixtures.*;
16+
import com.intellij.remoterobot.utils.WaitForConditionTimeoutException;
17+
import com.redhat.devtools.intellij.commonUiTestLibrary.UITestRunner;
18+
import com.redhat.devtools.intellij.commonUiTestLibrary.fixtures.dialogs.errors.IdeFatalErrorsDialog;
19+
import org.apache.commons.io.FileUtils;
20+
import org.jetbrains.annotations.NotNull;
21+
22+
import java.io.File;
23+
import java.io.IOException;
24+
import java.nio.file.Files;
25+
import java.nio.file.Paths;
26+
import java.time.Duration;
27+
28+
import static com.intellij.remoterobot.search.locators.Locators.byXpath;
29+
import static com.intellij.remoterobot.utils.UtilsKt.hasAnyComponent;
30+
import static com.redhat.devtools.intellij.commonUiTestLibrary.UITestRunner.getIdeaVersion;
31+
32+
/**
33+
* Welcome to IntelliJ IDEA dialog fixture
34+
*
35+
36+
*/
37+
@DefaultXpath(by = "FlatWelcomeFrame type", xpath = "//div[@class='FlatWelcomeFrame']")
38+
@FixtureName(name = "Welcome To IntelliJ IDEA Dialog")
39+
public class FlatWelcomeFrame extends CommonContainerFixture {
40+
private UITestRunner.IdeaVersion intelliJVersion;
41+
42+
public FlatWelcomeFrame(@NotNull RemoteRobot remoteRobot, @NotNull RemoteComponent remoteComponent) {
43+
super(remoteRobot, remoteComponent);
44+
this.intelliJVersion = getIdeaVersion();
45+
}
46+
47+
/**
48+
* Click on the 'New Project' link
49+
*/
50+
public void createNewProject() {
51+
// Code for IntelliJ Idea 2020.3 or newer
52+
if (intelliJVersion.toInt() >= 20203) {
53+
welcomeFrameLink("New Project").click();
54+
}
55+
// Code for IntelliJ Idea 2020.2 or earlier
56+
else {
57+
actionLink("New Project").click();
58+
}
59+
}
60+
61+
/**
62+
* Clear the workspace by deleting the content of the IdeaProjects folder and clearing all the projects' links in the 'Welcome to IntelliJ IDEA' dialog
63+
*/
64+
public void clearWorkspace() {
65+
// delete all the projects' links from the 'Welcome to IntelliJ IDEA' dialog
66+
int numberOfLinks = getNumberOfProjectLinks();
67+
for (int i = 0; i < numberOfLinks; i++) {
68+
ComponentFixture recentProjectsList = find(ComponentFixture.class, byXpath("//div[@accessiblename='Recent Projects' and @class='MyList']"), Duration.ofSeconds(10));
69+
recentProjectsList.runJs("const horizontal_offset = component.getWidth()-22;\n" +
70+
"robot.click(component, new Point(horizontal_offset, 22), MouseButton.LEFT_BUTTON, 1);");
71+
// Code for IntelliJ Idea 2020.3 or newer
72+
if (intelliJVersion.toInt() >= 20203) {
73+
JPopupMenuFixture contextMenu = find(JPopupMenuFixture.class, JPopupMenuFixture.Companion.byType(), Duration.ofSeconds(10));
74+
contextMenu.select("Remove from Recent Projects");
75+
}
76+
}
77+
78+
// delete all the files and folders in the IdeaProjects folder
79+
try {
80+
String pathToDirToMakeEmpty = System.getProperty("user.home") + File.separator + "IdeaProjects";
81+
boolean doesProjectDirExists = Files.exists(Paths.get(pathToDirToMakeEmpty));
82+
if (doesProjectDirExists) {
83+
FileUtils.cleanDirectory(new File(pathToDirToMakeEmpty));
84+
} else {
85+
Files.createDirectory(Paths.get(pathToDirToMakeEmpty));
86+
}
87+
} catch (IOException e) {
88+
e.printStackTrace();
89+
}
90+
}
91+
92+
/**
93+
* Clear all exceptions
94+
*/
95+
public void clearExceptions() {
96+
try {
97+
ideErrorsIcon().click();
98+
} catch (WaitForConditionTimeoutException e) {
99+
e.printStackTrace();
100+
return;
101+
}
102+
103+
IdeFatalErrorsDialog ideFatalErrorsDialog = find(IdeFatalErrorsDialog.class, Duration.ofSeconds(10));
104+
ideFatalErrorsDialog.clearAll();
105+
}
106+
107+
// Works for IntelliJ Idea 2020.3+
108+
private ComponentFixture welcomeFrameLink(String text) {
109+
if (hasAnyComponent(this, byXpath("//div[@class='NewRecentProjectPanel']"))) {
110+
return find(ComponentFixture.class, byXpath("//div[@class='JBOptionButton' and @text='" + text + "']"));
111+
}
112+
return find(ComponentFixture.class, byXpath("//div[@class='NonOpaquePanel'][./div[@text='" + text + "']]//div[@class='JButton']"));
113+
}
114+
115+
private int getNumberOfProjectLinks() {
116+
try {
117+
ComponentFixture recentProjectsList = find(ComponentFixture.class, byXpath("//div[@accessiblename='Recent Projects' and @class='MyList']"), Duration.ofSeconds(10));
118+
int numberOfProjectsLinks = recentProjectsList.findAllText().size() / 2; // 2 items per 1 project link (project path and project name)
119+
return numberOfProjectsLinks;
120+
} catch (WaitForConditionTimeoutException e) {
121+
// the list with accessible name 'Recent Projects' is not available -> 0 links in the 'Welcome to IntelliJ IDEA' dialog
122+
return 0;
123+
}
124+
}
125+
126+
private ComponentFixture ideErrorsIcon() {
127+
return find(ComponentFixture.class, byXpath("//div[@class='IdeErrorsIcon']"), Duration.ofSeconds(10));
128+
}
129+
}

0 commit comments

Comments
 (0)