Skip to content
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

IntelliJ UI tests for Spring and corrections of regular Java tests #2629

Merged
merged 22 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b1307e6
Spring autotests: Unit test generation and UI action dialog checks.
alisevych Sep 12, 2023
8f3a9eb
Merge branch 'main' into alisevych/spring_ui_tests
alisevych Sep 15, 2023
6f766be
Merge branch 'main' into alisevych/spring_ui_tests
alisevych Sep 25, 2023
c6479e2
UI tests optimizations
alisevych Sep 25, 2023
ee33ec0
Merge branch 'main' into alisevych/spring_ui_tests
alisevych Sep 28, 2023
93fc34b
InspectionViewFixture added + several corrections
alisevych Sep 29, 2023
b52778d
Rename back
alisevych Sep 29, 2023
faeac76
Smoke test on Spring Integration test generation.
alisevych Sep 29, 2023
a146630
Draft default project directory in TMP folder.
alisevych Oct 2, 2023
1036a98
Merge branch 'main' into alisevych/spring_ui_tests
alisevych Oct 5, 2023
bd20fea
readme.md correction of how to run autotests in utbot-intellij
alisevych Oct 9, 2023
be76ddf
Merge branch 'main' into alisevych/spring_ui_tests
alisevych Oct 9, 2023
96a772f
Current version of UI tests
alisevych Oct 9, 2023
3cfdb4e
Merge branch 'main' into alisevych/spring_ui_tests
alisevych Oct 10, 2023
d812d26
Spring UI tests updates - draft
alisevych Oct 10, 2023
6f36d6f
Spring UI tests updated and stabilized
alisevych Oct 11, 2023
9796015
Fixes
alisevych Oct 12, 2023
dd0cd66
Turn CreateProjects back ON
alisevych Oct 12, 2023
e25bdb5
Exceeded timeouts for project building
alisevych Oct 12, 2023
b2636e6
Added check test class is compilable to Spring Unit and Integration t…
alisevych Oct 12, 2023
b9ae681
wait loadProjectNotification for 30 sec on Spring project clone
alisevych Oct 12, 2023
6e6c961
fix
alisevych Oct 12, 2023
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
7 changes: 6 additions & 1 deletion utbot-intellij/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ To compile plugin:

## UnitTestBot Intellij Plugin UI Tests

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

Note: projects are created first and only on new projects tests are executed.
Expand Down
19 changes: 14 additions & 5 deletions utbot-intellij/src/test/kotlin/org/utbot/data/RunInfo.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
package org.utbot.data

import org.utbot.common.utBotTempDirectory
import java.io.File
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.Random

val TEST_RUN_NUMBER = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))
val DEFAULT_TEST_GENERATION_TIMEOUT = 60L
val NEW_PROJECT_NAME_START = "Aut_${TEST_RUN_NUMBER}_"
val DEFAULT_PROJECT_DIRECTORY = "~\\IdeaProjects"
var random: Random = Random()
val TEST_RUN_NUMBER: String = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))!!

val tempDirectoryPath: String = utBotTempDirectory.toAbsolutePath().toString()
const val DEFAULT_DIRECTORY_NAME = "Autotests"
val DEFAULT_DIRECTORY_FULL_PATH = tempDirectoryPath + File.separator + DEFAULT_DIRECTORY_NAME
val CURRENT_RUN_DIRECTORY_FULL_PATH = DEFAULT_DIRECTORY_FULL_PATH + File.separator + TEST_RUN_NUMBER
val CURRENT_RUN_DIRECTORY_END = DEFAULT_DIRECTORY_NAME + File.separator + TEST_RUN_NUMBER

const val SPRING_PROJECT_NAME = "spring-petclinic"
const val SPRING_PROJECT_URL = "https:/spring-projects/spring-petclinic.git"

val random: Random = Random()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.utbot.dialogs

import com.intellij.remoterobot.RemoteRobot
import com.intellij.remoterobot.data.RemoteComponent
import com.intellij.remoterobot.fixtures.*
import com.intellij.remoterobot.search.locators.byXpath
import com.intellij.remoterobot.utils.waitFor
import org.utbot.data.IdeaBuildSystem
import java.time.Duration

@FixtureName("Add File to Git Dialog")
@DefaultXpath("Dialog type", "//*[@title.key='vfs.listener.add.single.title']")
class AddFileToGitDialogFixture(
remoteRobot: RemoteRobot,
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {

val cancelButton
get() = button(
byXpath("//div[@text.key='button.cancel']"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.utbot.dialogs

import com.intellij.remoterobot.RemoteRobot
import com.intellij.remoterobot.data.RemoteComponent
import com.intellij.remoterobot.fixtures.*
import com.intellij.remoterobot.search.locators.byXpath
import com.intellij.remoterobot.utils.keyboard
import org.utbot.data.IdeaBuildSystem
import java.awt.event.KeyEvent
import java.io.File

@FixtureName("Get from Version Control Dialog")
@DefaultXpath("Dialog type", "//*[@title.key='get.from.version.control']")
class GetFromVersionControlDialogFixture(
remoteRobot: RemoteRobot,
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {

val urlInput
get() = textField(
byXpath("//div[@class='BorderlessTextField']"))

val directoryInput
get() = textField(
byXpath("//div[@class='ExtendableTextField']"))

val cloneButton
get() = button(
byXpath("//div[@text.key='clone.dialog.clone.button']"))

val cancelButton
get() = button(
byXpath("//div[@text.key='button.cancel']"))

fun fillDialog(url: String, location: String = "") {
urlInput.keyboard { enterText(url) }
if (directoryInput.hasText(location).not()) { // firstly change directory, otherwise it won't be updated with project name
directoryInput.click()
keyboard{
hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A)
enterText(location.replace(File.separator, File.separator + File.separator))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import com.intellij.remoterobot.stepsProcessing.step
import com.intellij.remoterobot.utils.Keyboard
import com.intellij.remoterobot.utils.keyboard
import com.intellij.remoterobot.utils.waitForIgnoringError
import org.utbot.data.DEFAULT_PROJECT_DIRECTORY
import org.utbot.data.IdeaBuildSystem
import org.utbot.data.JDKVersion
import java.awt.event.KeyEvent
import java.io.File
import java.time.Duration
import java.time.Duration.ofSeconds

Expand Down Expand Up @@ -73,7 +73,7 @@ class NewProjectDialogFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteC
}

fun fillDialog(projectName: String,
location: String = "",
location: String = "", locationPart: String = "",
language: String = "Java",
buildSystem: IdeaBuildSystem = IdeaBuildSystem.INTELLIJ,
jdkVersion: JDKVersion,
Expand All @@ -82,15 +82,11 @@ class NewProjectDialogFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteC
nameInput.doubleClick()
keyboard.hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A)
keyboard.enterText(projectName)
var input = DEFAULT_PROJECT_DIRECTORY
if (location != "") {
input = location
}
if (locationInput.hasText(input).not()) {
if (!locationInput.hasText{it.text.contains(locationPart)}) {
locationInput.click()
keyboard{
hotKey(KeyEvent.VK_CONTROL, KeyEvent.VK_A)
enterText(input.replace("\\", "\\\\"))
enterText(location.replace(File.separator, File.separator + File.separator))
}
}
this.findText(language).click()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.utbot.dialogs

import com.intellij.remoterobot.RemoteRobot
import com.intellij.remoterobot.data.RemoteComponent
import com.intellij.remoterobot.fixtures.*
import com.intellij.remoterobot.search.locators.byXpath
import com.intellij.remoterobot.utils.waitFor
import org.utbot.data.IdeaBuildSystem
import java.time.Duration

@FixtureName("Open or Import Project Dialog")
@DefaultXpath("Dialog type", "//*[@title.key='project.open.select.from.multiple.processors.dialog.title']")
class OpenOrImportProjectDialogFixture(
remoteRobot: RemoteRobot,
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {

val openAsRadioButtons
get() = radioButtons(
byXpath("//div[@class='JBRadioButton']"))

val okButton
get() = button(
byXpath("//div[@text.key='button.ok']"))

val cancelButton
get() = button(
byXpath("//div[@text.key='button.cancel']"))

fun selectBuildSystem(buildSystem: IdeaBuildSystem) {
waitFor {
openAsRadioButtons.isNotEmpty()
}
openAsRadioButtons.filter {
it.text.contains(buildSystem.system)
}[0].click()
okButton.click()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.utbot.dialogs

import com.intellij.remoterobot.RemoteRobot
import com.intellij.remoterobot.data.RemoteComponent
import com.intellij.remoterobot.fixtures.*
import com.intellij.remoterobot.search.locators.byXpath
import com.intellij.remoterobot.utils.keyboard
import com.intellij.remoterobot.utils.waitForIgnoringError
import org.utbot.data.JDKVersion
import java.time.Duration

@FixtureName("Project Structure Dialog")
@DefaultXpath("Dialog type", "//*[@title.key='project.settings.display.name']")
class ProjectStructureDialogFixture(
remoteRobot: RemoteRobot,
remoteComponent: RemoteComponent) : DialogFixture(remoteRobot, remoteComponent) {

val projectJdkCombobox
get() = comboBox(
byXpath("//div[@class='JdkComboBox']"))

val moduleSdkCombobox
get() = comboBox(
byXpath("//div[@text.key='module.libraries.target.jdk.module.radio']/../div[@class='JdkComboBox']"))

val okButton
get() = button(
byXpath("//div[@text.key='button.ok']"))

fun setProjectSdk(jdkVersion: JDKVersion) {
findText("Project").click()
projectJdkCombobox.click()
waitForIgnoringError(Duration.ofSeconds(5)) {
heavyWeightWindow().itemsList.isShowing
}
keyboard {
enterText(jdkVersion.namePart)
enter()
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.intellij.remoterobot.data.RemoteComponent
import com.intellij.remoterobot.fixtures.*
import com.intellij.remoterobot.search.locators.byXpath
import com.intellij.remoterobot.utils.Keyboard
import java.time.Duration

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

val testSourcesRootLabel
get() = jLabel(
byXpath("//div[@text='Test sources root:']"))

val testSourcesRootComboBox
get() = comboBox(
byXpath("//div[@class='TestFolderComboWithBrowseButton']/div[1]"))
byXpath("//div[@class='TestFolderComboWithBrowseButton']/div[@class='ComboBox']"))

val testingFrameworkLabel
get() = jLabel(
byXpath("//div[@text='Testing framework:']"))

val testingFrameworkComboBox
get() = comboBox(
byXpath("//div[@accessiblename='Testing framework:' and @class='ComboBox']"))

val mockingStrategyLabel
get() = jLabel(
byXpath("//div[@text='Mocking strategy:']"))

val mockingStrategyComboBox
get() = comboBox(
byXpath("//div[@accessiblename='Mocking strategy:' and @class='ComboBox']"))

val mockStaticMethodsCheckbox
get() = checkBox(
byXpath("//div[@text='Mock static methods']"))

val parameterizedTestsCheckbox
get() = checkBox(
byXpath("//div[@text='Parameterized tests']"))

val testGenerationTimeoutLabel
get() = jLabel(
byXpath("//div[@text='Test generation timeout:']"))

val testGenerationTimeoutTextField
get() = textField(
byXpath("//div[@class='JFormattedTextField']"))

val timeoutSecondsPerClassLabel
get() = jLabel(
byXpath("//div[@text='seconds per class']"))

val generateTestsForLabel
get() = jLabel(
byXpath("//div[@text='Generate tests for:']"))

val memberListTable
get() = remoteRobot.find<JTableFixture>(byXpath("//div[@class='MemberSelectionTable']"),
Duration.ofSeconds(5)
)

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

val arrowOnGenerateTestsButton
get() = button(
byXpath("//div[@class='JBOptionButton' and @text='Generate Tests']//div[@class='ArrowButton']"))

val buttonsList
get() = heavyWeightWindow().itemsList


// Spring-specific elements
val springConfigurationLabel
get() = jLabel(
byXpath("//div[@text='Spring configuration:']"))

val springConfigurationComboBox
get() = comboBox(
byXpath("//div[@accessiblename='Spring configuration:' and @class='ComboBox']"))

val springTestsTypeLabel
get() = jLabel(
byXpath("//div[@text='Test type:']"))

val springTestsTypeComboBox
get() = comboBox(
byXpath("//div[@accessiblename='Test type:' and @class='ComboBox']"))

val springActiveProfilesLabel
get() = jLabel(
byXpath("//div[@text='Active profile(s):']"))

val springActiveProfilesTextField
get() = textField(
byXpath("//div[@accessiblename='Active profile(s):' and @class='JBTextField']"))

val integrationTestsWarningDialog: WarningDialogFixture
get() = remoteRobot.find<WarningDialogFixture>(byXpath( "//div[@title='Warning']"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,12 @@ class WarningDialogFixture(
get() = button(
byXpath("//div[@text.key='button.cancel']"))

val proceedButton
get() = button(
byXpath("//div[@text='Proceed']"))

val goBackButton
get() = button(
byXpath("//div[@text='Go Back']"))

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ class NotificationFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteCompo
get() = remoteRobot.find<ComponentFixture>(byXpath("//div[@class='JEditorPane']"),
ofSeconds(5))

val link
get() = remoteRobot.find<ComponentFixture>(byXpath("//div[@class='LinkLabel']"),
ofSeconds(5))
val projectLoadButton
get() = button(byXpath("//div[@text.key='unlinked.project.notification.load.action']"))

// For add file to Git notification
val alwaysAddButton
get() = button(byXpath("//div[contains(@text.key, 'external.files.add.notification.action.add')]"))

val dontAskAgainButton
get() = button(byXpath("//div[contains(@text.key, 'external.files.add.notification.action.mute')]"))

}

Loading
Loading