Skip to content

Commit 28e6636

Browse files
authored
IntelliJ plugin UI smoke tests
1 parent 1cdc000 commit 28e6636

22 files changed

+1029
-0
lines changed

utbot-intellij/build.gradle.kts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ intellij {
6868
SettingsTemplateHelper.proceed(project)
6969
}
7070

71+
val remoteRobotVersion = "0.11.16"
72+
7173
tasks {
7274
compileKotlin {
7375
kotlinOptions {
@@ -93,6 +95,36 @@ tasks {
9395
untilBuild.set("222.*")
9496
version.set(semVer)
9597
}
98+
99+
runIdeForUiTests {
100+
jvmArgs("-Xmx2048m", "-Didea.is.internal=true", "-Didea.ui.debug.mode=true")
101+
102+
systemProperty("robot-server.port", "8082") // default port 8580
103+
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
104+
systemProperty("jb.privacy.policy.text", "<!--999.999-->")
105+
systemProperty("jb.consents.confirmation.enabled", "false")
106+
systemProperty("idea.trust.all.projects", "true")
107+
systemProperty("ide.mac.file.chooser.native", "false")
108+
systemProperty("jbScreenMenuBar.enabled", "false")
109+
systemProperty("apple.laf.useScreenMenuBar", "false")
110+
systemProperty("ide.show.tips.on.startup.default.value", "false")
111+
}
112+
113+
downloadRobotServerPlugin {
114+
version.set(remoteRobotVersion)
115+
}
116+
117+
test {
118+
description = "Runs UI integration tests."
119+
useJUnitPlatform {
120+
exclude("/org/utbot/**") //Comment this line to run the tests locally
121+
}
122+
}
123+
}
124+
125+
repositories {
126+
maven("https://jitpack.io")
127+
maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies")
96128
}
97129

98130
dependencies {
@@ -124,4 +156,15 @@ dependencies {
124156
}
125157

126158
implementation(project(":utbot-android-studio"))
159+
160+
testImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion")
161+
testImplementation("com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion")
162+
163+
testImplementation("org.assertj:assertj-core:3.11.1")
164+
165+
// Logging Network Calls
166+
testImplementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
167+
168+
// Video Recording
169+
implementation("com.automation-remarks:video-recorder-junit5:2.0")
127170
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.utbot.data
2+
3+
enum class IdeaBuildSystem (val system: String) {
4+
5+
INTELLIJ("IntelliJ"),
6+
GRADLE("Gradle")
7+
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.utbot.data
2+
3+
enum class JDKVersion (val namePart: String, val number: Int) {
4+
5+
JDK_1_8(namePart = "-1.8", 8),
6+
JDK_11(namePart = "-11", 11);
7+
8+
override fun toString() = namePart
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.utbot.data
2+
3+
import java.time.LocalDateTime
4+
import java.time.format.DateTimeFormatter
5+
6+
val TEST_RUN_NUMBER = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))
7+
val DEFAULT_TEST_GENERATION_TIMEOUT = 60L
8+
val NEW_PROJECT_NAME_START = "Aut_${TEST_RUN_NUMBER}_"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.utbot.dialogs
2+
3+
import com.intellij.remoterobot.RemoteRobot
4+
import com.intellij.remoterobot.data.RemoteComponent
5+
import com.intellij.remoterobot.fixtures.CommonContainerFixture
6+
import com.intellij.remoterobot.fixtures.ContainerFixture
7+
import com.intellij.remoterobot.fixtures.FixtureName
8+
import com.intellij.remoterobot.search.locators.byXpath
9+
import com.intellij.remoterobot.stepsProcessing.step
10+
import java.time.Duration
11+
12+
fun ContainerFixture.dialog(
13+
title: String,
14+
timeout: Duration = Duration.ofSeconds(20),
15+
function: DialogFixture.() -> Unit = {}): DialogFixture = step("Search for dialog with title $title") {
16+
find<DialogFixture>(DialogFixture.byTitle(title), timeout).apply(function)
17+
}
18+
19+
@FixtureName("Dialog")
20+
open class DialogFixture(
21+
remoteRobot: RemoteRobot,
22+
remoteComponent: RemoteComponent) : CommonContainerFixture(remoteRobot, remoteComponent) {
23+
24+
companion object {
25+
@JvmStatic
26+
fun byTitle(title: String) = byXpath("title $title", "//div[@title='$title' and @class='MyDialog']")
27+
}
28+
29+
val title: String
30+
get() = callJs("component.getTitle();")
31+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package org.utbot.dialogs
2+
3+
import com.intellij.remoterobot.RemoteRobot
4+
import com.intellij.remoterobot.data.RemoteComponent
5+
import com.intellij.remoterobot.fixtures.*
6+
import com.intellij.remoterobot.search.locators.byXpath
7+
import com.intellij.remoterobot.stepsProcessing.step
8+
import com.intellij.remoterobot.utils.Keyboard
9+
import com.intellij.remoterobot.utils.waitFor
10+
import org.utbot.data.IdeaBuildSystem
11+
import org.utbot.data.JDKVersion
12+
import java.awt.event.KeyEvent
13+
import java.time.Duration
14+
import java.time.Duration.ofSeconds
15+
16+
@FixtureName("NewProjectDialog")
17+
@DefaultXpath("type", "//*[contains(@title.key, 'title.new.project')]")
18+
class NewProjectDialogFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent)
19+
: DialogFixture(remoteRobot, remoteComponent) {
20+
val keyboard: Keyboard = Keyboard(remoteRobot)
21+
22+
val wizardsList
23+
get() = jList(
24+
byXpath("//div[@class='JBList']"))
25+
26+
val nameInput
27+
get() = textField(
28+
byXpath("//div[@class='JBTextField']"))
29+
30+
val locationInput
31+
get() = textField(
32+
byXpath("//div[@class='ExtendableTextField']"))
33+
34+
val addSampleCodeCheckbox
35+
get() = checkBox(
36+
byXpath("//div[@text.key='label.project.wizard.new.project.add.sample.code']"))
37+
38+
val jdkComboBox
39+
get() = comboBox(
40+
byXpath("//div[@class='JdkComboBox']"),
41+
Duration.ofSeconds(10))
42+
43+
val jdkList
44+
get() = heavyWeightWindow().itemsList
45+
46+
val createButton
47+
get() = button(
48+
byXpath("//div[@text.key='button.create']"))
49+
50+
val cancelButton
51+
get() = button(
52+
byXpath("//div[@text.key='button.cancel']"))
53+
54+
fun selectWizard(wizardName: String) {
55+
if (title != wizardName) {
56+
wizardsList.findText(wizardName).click()
57+
}
58+
}
59+
60+
fun selectJDK(jdkVersion: String) {
61+
step("Select JDK: $jdkVersion") {
62+
jdkComboBox.click()
63+
try {
64+
waitFor(ofSeconds(10)) {
65+
findAll<ComponentFixture>(byXpath("//*[@text.key='progress.title.detecting.sdks']")).isNotEmpty()
66+
}
67+
} catch (ignore: Throwable) {}
68+
waitFor(ofSeconds(20)) {
69+
findAll<ComponentFixture>(byXpath("//*[@text.key='progress.title.detecting.sdks']")).isEmpty()
70+
}
71+
val jdkMatching = jdkList.collectItems().first { it.contains(jdkVersion) }
72+
jdkList.clickItem(jdkMatching)
73+
}
74+
}
75+
76+
fun fillDialog(projectName: String,
77+
location: String = "",
78+
language: String = "Java",
79+
buildSystem: IdeaBuildSystem = IdeaBuildSystem.INTELLIJ,
80+
jdkVersion: JDKVersion,
81+
addSampleCode: Boolean = true) {
82+
step("Fill New Project dialog") {
83+
nameInput.doubleClick()
84+
keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A)
85+
keyboard.enterText(projectName)
86+
if (location != "") {
87+
if (locationInput.hasText(location).not()) {
88+
locationInput.doubleClick()
89+
keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A)
90+
keyboard.enterText(location.replace("\\", "\\\\"))
91+
}
92+
}
93+
this.findText(language).click()
94+
this.findText(buildSystem.system).click()
95+
addSampleCodeCheckbox.setValue(addSampleCode)
96+
if (!jdkComboBox.selectedText().contains(jdkVersion.namePart)) {
97+
selectJDK(jdkVersion.namePart)
98+
}
99+
}
100+
}
101+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.utbot.dialogs
2+
3+
import com.intellij.remoterobot.RemoteRobot
4+
import com.intellij.remoterobot.data.RemoteComponent
5+
import com.intellij.remoterobot.fixtures.*
6+
import com.intellij.remoterobot.search.locators.byXpath
7+
8+
@FixtureName("OpenProjectDialog")
9+
@DefaultXpath("Dialog type", "//*[@title.key='title.open.file.or.project']")
10+
class OpenProjectDialogFixture(
11+
remoteRobot: RemoteRobot,
12+
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {
13+
14+
val pathInput
15+
get() = textField(
16+
byXpath("//div[@class='BorderlessTextField']"))
17+
18+
val okButton
19+
get() = button(
20+
byXpath("//div[@text.key='button.ok']"))
21+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.utbot.dialogs
2+
3+
import com.intellij.remoterobot.RemoteRobot
4+
import com.intellij.remoterobot.data.RemoteComponent
5+
import com.intellij.remoterobot.fixtures.*
6+
import com.intellij.remoterobot.search.locators.byXpath
7+
import com.intellij.remoterobot.utils.Keyboard
8+
9+
@FixtureName("UnitTestBotDialog")
10+
@DefaultXpath("Dialog type", "//*[contains(@title, 'UnitTestBot')]")
11+
class UnitTestBotDialogFixture(
12+
remoteRobot: RemoteRobot,
13+
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {
14+
val keyboard: Keyboard = Keyboard(remoteRobot)
15+
16+
val testSourcesRootComboBox
17+
get() = comboBox(
18+
byXpath("//div[@class='TestFolderComboWithBrowseButton']/div[1]"))
19+
20+
val generateTestsButton
21+
get() = button(
22+
byXpath("//div[@class='MainButton']"))
23+
24+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.utbot.pages
2+
3+
import com.intellij.remoterobot.RemoteRobot
4+
import com.intellij.remoterobot.data.RemoteComponent
5+
import com.intellij.remoterobot.fixtures.ComponentFixture
6+
import com.intellij.remoterobot.fixtures.FixtureName
7+
import com.intellij.remoterobot.search.locators.byXpath
8+
import com.intellij.remoterobot.utils.waitFor
9+
10+
fun RemoteRobot.actionMenu(text: String): ActionMenuFixture {
11+
val xpath = byXpath("text '$text'", "//div[@class='ActionMenu' and @text='$text']")
12+
waitFor {
13+
findAll<ActionMenuFixture>(xpath).isNotEmpty()
14+
}
15+
return findAll<ActionMenuFixture>(xpath).first()
16+
}
17+
18+
fun RemoteRobot.actionMenuItem(text: String): ActionMenuItemFixture {
19+
val xpath = byXpath("text '$text'", "//div[@class='ActionMenuItem' and @text='$text']")
20+
waitFor {
21+
findAll<ActionMenuItemFixture>(xpath).isNotEmpty()
22+
}
23+
return findAll<ActionMenuItemFixture>(xpath).first()
24+
}
25+
26+
@FixtureName("ActionMenu")
27+
class ActionMenuFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) : ComponentFixture(remoteRobot, remoteComponent)
28+
29+
@FixtureName("ActionMenuItem")
30+
class ActionMenuItemFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) : ComponentFixture(remoteRobot, remoteComponent)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.utbot.elements
2+
3+
import com.intellij.remoterobot.RemoteRobot
4+
import com.intellij.remoterobot.data.RemoteComponent
5+
import com.intellij.remoterobot.fixtures.CommonContainerFixture
6+
import com.intellij.remoterobot.fixtures.ComponentFixture
7+
import com.intellij.remoterobot.fixtures.DefaultXpath
8+
import com.intellij.remoterobot.fixtures.FixtureName
9+
import com.intellij.remoterobot.search.locators.byXpath
10+
import java.time.Duration.ofSeconds
11+
12+
@FixtureName("Notification Center Panel")
13+
@DefaultXpath("NotificationCenterPanel type", "//div[@class='NotificationCenterPanel']")
14+
class NotificationFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) : CommonContainerFixture(remoteRobot, remoteComponent) {
15+
16+
val title
17+
get() = jLabel(byXpath("//div[@class='JLabel']"),
18+
ofSeconds(5))
19+
20+
val body
21+
get() = remoteRobot.find<ComponentFixture>(byXpath("//div[@class='JEditorPane']"),
22+
ofSeconds(5))
23+
24+
val link
25+
get() = remoteRobot.find<ComponentFixture>(byXpath("//div[@class='LinkLabel']"),
26+
ofSeconds(5))
27+
}
28+

0 commit comments

Comments
 (0)