Skip to content

Commit ba1b365

Browse files
authored
IntelliJ UI tests for Spring and corrections of regular Java tests (#2629)
IntelliJ UI tests for Spring and corrections of regular Java tests (#2629)
1 parent 4e5ba7f commit ba1b365

21 files changed

+697
-103
lines changed

utbot-intellij/readme.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ To compile plugin:
1414

1515
## UnitTestBot Intellij Plugin UI Tests
1616

17-
* Comment `exclude("/org/utbot/**")` in utbot-intellij/build.gradle.kts
17+
* comment `exclude("/org/utbot/**")` in utbot-intellij/build.gradle.kts
18+
* correct DEFAULT_PROJECT_DIRECTORY in RunInfo.kt if needed (it is your local directory in which test projects will be created locally)
1819
* run IDEA in sandbox with IntelliJ Robot server plugin installed: `gradle runIdeForUiTests`
20+
* wait till debug IDEA is started
21+
* check it is above other windows and maximized
22+
* check keyboard language is EN
23+
* do NOT lock screen
1924
* run **All** the tests in utbot-intellij/src/test/kotlin/org/utbot/tests
2025

2126
Note: projects are created first and only on new projects tests are executed.
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
package org.utbot.data
22

3+
import org.utbot.common.utBotTempDirectory
4+
import java.io.File
35
import java.time.LocalDateTime
46
import java.time.format.DateTimeFormatter
57
import java.util.Random
68

7-
val TEST_RUN_NUMBER = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))
8-
val DEFAULT_TEST_GENERATION_TIMEOUT = 60L
9-
val NEW_PROJECT_NAME_START = "Aut_${TEST_RUN_NUMBER}_"
10-
val DEFAULT_PROJECT_DIRECTORY = "~\\IdeaProjects"
11-
var random: Random = Random()
9+
val TEST_RUN_NUMBER: String = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))!!
10+
11+
val tempDirectoryPath: String = utBotTempDirectory.toAbsolutePath().toString()
12+
const val DEFAULT_DIRECTORY_NAME = "Autotests"
13+
val DEFAULT_DIRECTORY_FULL_PATH = tempDirectoryPath + File.separator + DEFAULT_DIRECTORY_NAME
14+
val CURRENT_RUN_DIRECTORY_FULL_PATH = DEFAULT_DIRECTORY_FULL_PATH + File.separator + TEST_RUN_NUMBER
15+
val CURRENT_RUN_DIRECTORY_END = DEFAULT_DIRECTORY_NAME + File.separator + TEST_RUN_NUMBER
16+
17+
const val SPRING_PROJECT_NAME = "spring-petclinic"
18+
const val SPRING_PROJECT_URL = "https://github.com/spring-projects/spring-petclinic.git"
19+
20+
val random: Random = Random()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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.waitFor
8+
import org.utbot.data.IdeaBuildSystem
9+
import java.time.Duration
10+
11+
@FixtureName("Add File to Git Dialog")
12+
@DefaultXpath("Dialog type", "//*[@title.key='vfs.listener.add.single.title']")
13+
class AddFileToGitDialogFixture(
14+
remoteRobot: RemoteRobot,
15+
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {
16+
17+
val cancelButton
18+
get() = button(
19+
byXpath("//div[@text.key='button.cancel']"))
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
import org.utbot.data.IdeaBuildSystem
9+
import java.awt.event.KeyEvent
10+
import java.io.File
11+
12+
@FixtureName("Get from Version Control Dialog")
13+
@DefaultXpath("Dialog type", "//*[@title.key='get.from.version.control']")
14+
class GetFromVersionControlDialogFixture(
15+
remoteRobot: RemoteRobot,
16+
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {
17+
18+
val urlInput
19+
get() = textField(
20+
byXpath("//div[@class='BorderlessTextField']"))
21+
22+
val directoryInput
23+
get() = textField(
24+
byXpath("//div[@class='ExtendableTextField']"))
25+
26+
val cloneButton
27+
get() = button(
28+
byXpath("//div[@text.key='clone.dialog.clone.button']"))
29+
30+
val cancelButton
31+
get() = button(
32+
byXpath("//div[@text.key='button.cancel']"))
33+
34+
fun fillDialog(url: String, location: String = "") {
35+
urlInput.keyboard { enterText(url) }
36+
if (directoryInput.hasText(location).not()) { // firstly change directory, otherwise it won't be updated with project name
37+
directoryInput.click()
38+
keyboard{
39+
hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A)
40+
enterText(location.replace(File.separator, File.separator + File.separator))
41+
}
42+
}
43+
}
44+
}

utbot-intellij/src/test/kotlin/org/utbot/dialogs/NewProjectDialogFixture.kt

+4-8
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import com.intellij.remoterobot.stepsProcessing.step
88
import com.intellij.remoterobot.utils.Keyboard
99
import com.intellij.remoterobot.utils.keyboard
1010
import com.intellij.remoterobot.utils.waitForIgnoringError
11-
import org.utbot.data.DEFAULT_PROJECT_DIRECTORY
1211
import org.utbot.data.IdeaBuildSystem
1312
import org.utbot.data.JDKVersion
1413
import java.awt.event.KeyEvent
14+
import java.io.File
1515
import java.time.Duration
1616
import java.time.Duration.ofSeconds
1717

@@ -73,7 +73,7 @@ class NewProjectDialogFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteC
7373
}
7474

7575
fun fillDialog(projectName: String,
76-
location: String = "",
76+
location: String = "", locationPart: String = "",
7777
language: String = "Java",
7878
buildSystem: IdeaBuildSystem = IdeaBuildSystem.INTELLIJ,
7979
jdkVersion: JDKVersion,
@@ -82,15 +82,11 @@ class NewProjectDialogFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteC
8282
nameInput.doubleClick()
8383
keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A)
8484
keyboard.enterText(projectName)
85-
var input = DEFAULT_PROJECT_DIRECTORY
86-
if (location != "") {
87-
input = location
88-
}
89-
if (locationInput.hasText(input).not()) {
85+
if (!locationInput.hasText{it.text.contains(locationPart)}) {
9086
locationInput.click()
9187
keyboard{
9288
hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A)
93-
enterText(input.replace("\\", "\\\\"))
89+
enterText(location.replace(File.separator, File.separator + File.separator))
9490
}
9591
}
9692
this.findText(language).click()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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.waitFor
8+
import org.utbot.data.IdeaBuildSystem
9+
import java.time.Duration
10+
11+
@FixtureName("Open or Import Project Dialog")
12+
@DefaultXpath("Dialog type", "//*[@title.key='project.open.select.from.multiple.processors.dialog.title']")
13+
class OpenOrImportProjectDialogFixture(
14+
remoteRobot: RemoteRobot,
15+
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {
16+
17+
val openAsRadioButtons
18+
get() = radioButtons(
19+
byXpath("//div[@class='JBRadioButton']"))
20+
21+
val okButton
22+
get() = button(
23+
byXpath("//div[@text.key='button.ok']"))
24+
25+
val cancelButton
26+
get() = button(
27+
byXpath("//div[@text.key='button.cancel']"))
28+
29+
fun selectBuildSystem(buildSystem: IdeaBuildSystem) {
30+
waitFor {
31+
openAsRadioButtons.isNotEmpty()
32+
}
33+
openAsRadioButtons.filter {
34+
it.text.contains(buildSystem.system)
35+
}[0].click()
36+
okButton.click()
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
import com.intellij.remoterobot.utils.waitForIgnoringError
9+
import org.utbot.data.JDKVersion
10+
import java.time.Duration
11+
12+
@FixtureName("Project Structure Dialog")
13+
@DefaultXpath("Dialog type", "//*[@title.key='project.settings.display.name']")
14+
class ProjectStructureDialogFixture(
15+
remoteRobot: RemoteRobot,
16+
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {
17+
18+
val projectJdkCombobox
19+
get() = comboBox(
20+
byXpath("//div[@class='JdkComboBox']"))
21+
22+
val moduleSdkCombobox
23+
get() = comboBox(
24+
byXpath("//div[@text.key='module.libraries.target.jdk.module.radio']/../div[@class='JdkComboBox']"))
25+
26+
val okButton
27+
get() = button(
28+
byXpath("//div[@text.key='button.ok']"))
29+
30+
fun setProjectSdk(jdkVersion: JDKVersion) {
31+
findText("Project").click()
32+
projectJdkCombobox.click()
33+
waitForIgnoringError(Duration.ofSeconds(5)) {
34+
heavyWeightWindow().itemsList.isShowing
35+
}
36+
keyboard {
37+
enterText(jdkVersion.namePart)
38+
enter()
39+
}
40+
}
41+
42+
}

utbot-intellij/src/test/kotlin/org/utbot/dialogs/UnitTestBotDialogFixture.kt

+86-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.intellij.remoterobot.data.RemoteComponent
55
import com.intellij.remoterobot.fixtures.*
66
import com.intellij.remoterobot.search.locators.byXpath
77
import com.intellij.remoterobot.utils.Keyboard
8+
import java.time.Duration
89

910
@FixtureName("UnitTestBotDialog")
1011
@DefaultXpath("Dialog type", "//*[contains(@title, 'UnitTestBot')]")
@@ -21,12 +22,96 @@ class UnitTestBotDialogFixture(
2122
get() = actionLink(
2223
byXpath("//div[@class='SdkNotificationPanel']//div[@class='HyperlinkLabel']"))
2324

25+
val testSourcesRootLabel
26+
get() = jLabel(
27+
byXpath("//div[@text='Test sources root:']"))
28+
2429
val testSourcesRootComboBox
2530
get() = comboBox(
26-
byXpath("//div[@class='TestFolderComboWithBrowseButton']/div[1]"))
31+
byXpath("//div[@class='TestFolderComboWithBrowseButton']/div[@class='ComboBox']"))
32+
33+
val testingFrameworkLabel
34+
get() = jLabel(
35+
byXpath("//div[@text='Testing framework:']"))
36+
37+
val testingFrameworkComboBox
38+
get() = comboBox(
39+
byXpath("//div[@accessiblename='Testing framework:' and @class='ComboBox']"))
40+
41+
val mockingStrategyLabel
42+
get() = jLabel(
43+
byXpath("//div[@text='Mocking strategy:']"))
44+
45+
val mockingStrategyComboBox
46+
get() = comboBox(
47+
byXpath("//div[@accessiblename='Mocking strategy:' and @class='ComboBox']"))
48+
49+
val mockStaticMethodsCheckbox
50+
get() = checkBox(
51+
byXpath("//div[@text='Mock static methods']"))
52+
53+
val parameterizedTestsCheckbox
54+
get() = checkBox(
55+
byXpath("//div[@text='Parameterized tests']"))
56+
57+
val testGenerationTimeoutLabel
58+
get() = jLabel(
59+
byXpath("//div[@text='Test generation timeout:']"))
60+
61+
val testGenerationTimeoutTextField
62+
get() = textField(
63+
byXpath("//div[@class='JFormattedTextField']"))
64+
65+
val timeoutSecondsPerClassLabel
66+
get() = jLabel(
67+
byXpath("//div[@text='seconds per class']"))
68+
69+
val generateTestsForLabel
70+
get() = jLabel(
71+
byXpath("//div[@text='Generate tests for:']"))
72+
73+
val memberListTable
74+
get() = remoteRobot.find<JTableFixture>(byXpath("//div[@class='MemberSelectionTable']"),
75+
Duration.ofSeconds(5)
76+
)
2777

2878
val generateTestsButton
2979
get() = button(
3080
byXpath("//div[@class='MainButton']"))
3181

82+
val arrowOnGenerateTestsButton
83+
get() = button(
84+
byXpath("//div[@class='JBOptionButton' and @text='Generate Tests']//div[@class='ArrowButton']"))
85+
86+
val buttonsList
87+
get() = heavyWeightWindow().itemsList
88+
89+
90+
// Spring-specific elements
91+
val springConfigurationLabel
92+
get() = jLabel(
93+
byXpath("//div[@text='Spring configuration:']"))
94+
95+
val springConfigurationComboBox
96+
get() = comboBox(
97+
byXpath("//div[@accessiblename='Spring configuration:' and @class='ComboBox']"))
98+
99+
val springTestsTypeLabel
100+
get() = jLabel(
101+
byXpath("//div[@text='Test type:']"))
102+
103+
val springTestsTypeComboBox
104+
get() = comboBox(
105+
byXpath("//div[@accessiblename='Test type:' and @class='ComboBox']"))
106+
107+
val springActiveProfilesLabel
108+
get() = jLabel(
109+
byXpath("//div[@text='Active profile(s):']"))
110+
111+
val springActiveProfilesTextField
112+
get() = textField(
113+
byXpath("//div[@accessiblename='Active profile(s):' and @class='JBTextField']"))
114+
115+
val integrationTestsWarningDialog: WarningDialogFixture
116+
get() = remoteRobot.find<WarningDialogFixture>(byXpath( "//div[@title='Warning']"))
32117
}

utbot-intellij/src/test/kotlin/org/utbot/dialogs/WarningDialogFixture.kt

+8
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,12 @@ class WarningDialogFixture(
2121
get() = button(
2222
byXpath("//div[@text.key='button.cancel']"))
2323

24+
val proceedButton
25+
get() = button(
26+
byXpath("//div[@text='Proceed']"))
27+
28+
val goBackButton
29+
get() = button(
30+
byXpath("//div[@text='Go Back']"))
31+
2432
}

utbot-intellij/src/test/kotlin/org/utbot/elements/NotificationFixture.kt

+10-3
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,15 @@ class NotificationFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteCompo
2121
get() = remoteRobot.find<ComponentFixture>(byXpath("//div[@class='JEditorPane']"),
2222
ofSeconds(5))
2323

24-
val link
25-
get() = remoteRobot.find<ComponentFixture>(byXpath("//div[@class='LinkLabel']"),
26-
ofSeconds(5))
24+
val projectLoadButton
25+
get() = button(byXpath("//div[@text.key='unlinked.project.notification.load.action']"))
26+
27+
// For add file to Git notification
28+
val alwaysAddButton
29+
get() = button(byXpath("//div[contains(@text.key, 'external.files.add.notification.action.add')]"))
30+
31+
val dontAskAgainButton
32+
get() = button(byXpath("//div[contains(@text.key, 'external.files.add.notification.action.mute')]"))
33+
2734
}
2835

0 commit comments

Comments
 (0)