diff --git a/utbot-intellij/readme.md b/utbot-intellij/readme.md index 1cab7af388..55b6a3c3ab 100644 --- a/utbot-intellij/readme.md +++ b/utbot-intellij/readme.md @@ -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. diff --git a/utbot-intellij/src/test/kotlin/org/utbot/data/RunInfo.kt b/utbot-intellij/src/test/kotlin/org/utbot/data/RunInfo.kt index f91630c119..4e89fba84e 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/data/RunInfo.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/data/RunInfo.kt @@ -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://github.com/spring-projects/spring-petclinic.git" + +val random: Random = Random() diff --git a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/AddFileToGitDialogFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/AddFileToGitDialogFixture.kt new file mode 100644 index 0000000000..32c0f25842 --- /dev/null +++ b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/AddFileToGitDialogFixture.kt @@ -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']")) +} \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/GetFromVersionControlDialogFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/GetFromVersionControlDialogFixture.kt new file mode 100644 index 0000000000..21509c10ec --- /dev/null +++ b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/GetFromVersionControlDialogFixture.kt @@ -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)) + } + } + } +} \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/NewProjectDialogFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/NewProjectDialogFixture.kt index 1ddc6660cc..277b033e20 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/NewProjectDialogFixture.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/NewProjectDialogFixture.kt @@ -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 @@ -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, @@ -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() diff --git a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/OpenOrImportProjectDialogFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/OpenOrImportProjectDialogFixture.kt new file mode 100644 index 0000000000..c96e3e3dde --- /dev/null +++ b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/OpenOrImportProjectDialogFixture.kt @@ -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() + } +} \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/ProjectStructureDialogFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/ProjectStructureDialogFixture.kt new file mode 100644 index 0000000000..3df95ce70d --- /dev/null +++ b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/ProjectStructureDialogFixture.kt @@ -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() + } + } + +} \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/UnitTestBotDialogFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/UnitTestBotDialogFixture.kt index 0a411ea440..2d256cff99 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/UnitTestBotDialogFixture.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/UnitTestBotDialogFixture.kt @@ -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')]") @@ -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(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(byXpath( "//div[@title='Warning']")) } \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/WarningDialogFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/WarningDialogFixture.kt index f5e4a1e651..210d33e687 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/dialogs/WarningDialogFixture.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/dialogs/WarningDialogFixture.kt @@ -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']")) + } \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/elements/NotificationFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/elements/NotificationFixture.kt index 5683f12db5..1ba3205e88 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/elements/NotificationFixture.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/elements/NotificationFixture.kt @@ -21,8 +21,15 @@ class NotificationFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteCompo get() = remoteRobot.find(byXpath("//div[@class='JEditorPane']"), ofSeconds(5)) - val link - get() = remoteRobot.find(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')]")) + } diff --git a/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaFrame.kt b/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaFrame.kt index 317cd626a6..ee569961bb 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaFrame.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaFrame.kt @@ -10,9 +10,12 @@ import com.intellij.remoterobot.utils.waitFor import com.intellij.remoterobot.utils.waitForIgnoringError import org.assertj.swing.core.MouseButton import org.utbot.data.IdeaBuildSystem +import org.utbot.dialogs.AddFileToGitDialogFixture +import org.utbot.dialogs.ProjectStructureDialogFixture import org.utbot.dialogs.UnitTestBotDialogFixture import org.utbot.dialogs.WarningDialogFixture import org.utbot.elements.NotificationFixture +import org.utbot.tabs.InspectionViewFixture import java.awt.event.KeyEvent import java.time.Duration import java.time.Duration.ofSeconds @@ -40,7 +43,7 @@ open class IdeaFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) val inlineProgressTextPanel get() = remoteRobot.find(byXpath("//div[@class='InlineProgressPanel']//div[@class='TextPanel']"), - ofSeconds(10)) + ofSeconds(5)) val statusTextPanel get() = remoteRobot.find(byXpath("//div[@class='StatusPanel']//div[@class='TextPanel']"), @@ -54,18 +57,39 @@ open class IdeaFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) get() = textField(byXpath("//div[contains(@accessiblename.key, 'editor.accessible.name')]"), ofSeconds(20)) + // Notifications val ideError get() = remoteRobot.find(byXpath( "//div[@class='NotificationCenterPanel'][.//div[@accessiblename.key='error.new.notification.title']]"), ofSeconds(10)) val utbotNotification - get() = remoteRobot.find(byXpath( "//div[@class='NotificationCenterPanel'][div[contains(.,'UnitTestBot')]]"), + get() = remoteRobot.find(byXpath( "//div[@class='NotificationCenterPanel' and contains(.,'UnitTestBot')]"), ofSeconds(10)) - val unitTestBotDialog - get() = remoteRobot.find(UnitTestBotDialogFixture::class.java, + val loadProjectNotification + get() = remoteRobot.find(byXpath( "//div[@class='NotificationActionPanel' and contains(.,'Load')]"), + ofSeconds(20)) + + val addToGitNotification + get() = remoteRobot.find(byXpath( "//div[@class='NotificationCenterPanel' and contains(.,'Git')]"), ofSeconds(10)) + val inspectionsView + get() = remoteRobot.find(InspectionViewFixture::class.java) + + val problemsTabButton + get() = button( byXpath("//div[contains(@text.key, 'toolwindow.stripe.Problems_View')]")) + + // Dialogs + val unitTestBotDialog + get() = remoteRobot.find(UnitTestBotDialogFixture::class.java) + + val projectStructureDialog + get() = remoteRobot.find(ProjectStructureDialogFixture::class.java) + + val addFileToGitDialog + get() = remoteRobot.find(AddFileToGitDialogFixture::class.java) + @JvmOverloads fun dumbAware(timeout: Duration = Duration.ofMinutes(5), function: () -> Unit) { step("Wait for smart mode") { @@ -109,27 +133,31 @@ open class IdeaFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) } catch (ignore: Throwable) {} } - fun openUTBotDialogFromProjectViewForClass(classname: String) { + fun openUTBotDialogFromProjectViewForClass(classname: String, packageName: String = "") { step("Call UnitTestBot action") { waitFor(ofSeconds(200)) { !isDumbMode() } with(projectViewTree) { + if (hasText(classname).not() && packageName != "") { + findText{it.text.endsWith(packageName)}.doubleClick() + } findText(classname).click(MouseButton.RIGHT_BUTTON) } remoteRobot.actionMenuItem("Generate Tests with UnitTestBot...").click() } } - open fun waitProjectIsOpened() { + open fun waitProjectIsBuilt() { + projectViewTree.click() + keyboard { key(KeyEvent.VK_PAGE_UP) } waitForIgnoringError(ofSeconds(30)) { projectViewTree.hasText(projectName) } + waitFor(Duration.ofSeconds(90)) { + !isDumbMode() + } } - open fun waitProjectIsCreated() { - waitProjectIsOpened() - } - - open fun expandProjectTree(projectName: String) { + open fun expandProjectTree() { with(projectViewTree) { if (hasText("src").not()) { findText(projectName).doubleClick() @@ -158,8 +186,6 @@ open class IdeaFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) fun createNewJavaClass(newClassname: String = "Example", textToClickOn: String = "Main") { - waitProjectIsOpened() - expandProjectTree(projectName) with(projectViewTree) { findText(textToClickOn).click(MouseButton.RIGHT_BUTTON) } @@ -170,4 +196,16 @@ open class IdeaFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) enter() } } + + fun openProjectStructureDialog() { + if (remoteRobot.isMac()) { + keyboard { + hotKey(KeyEvent.VK_SHIFT, KeyEvent.VK_META, KeyEvent.VK_A) + enterText("Project Structure...") + enter() + } + } else { + menuBar.select("File", "Project Structure...") + } + } } \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaGradleFrame.kt b/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaGradleFrame.kt index 52d0fad081..11fe5fdce0 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaGradleFrame.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaGradleFrame.kt @@ -3,6 +3,7 @@ package org.utbot.pages import com.intellij.remoterobot.RemoteRobot import com.intellij.remoterobot.data.RemoteComponent import com.intellij.remoterobot.fixtures.DefaultXpath +import com.intellij.remoterobot.utils.waitFor import com.intellij.remoterobot.utils.waitForIgnoringError import org.utbot.data.IdeaBuildSystem import java.time.Duration.ofSeconds @@ -12,37 +13,39 @@ class IdeaGradleFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent override val buildSystemToUse = IdeaBuildSystem.GRADLE - override fun waitProjectIsCreated() { - super.waitProjectIsOpened() - repeat (120) { - inlineProgressTextPanel.isShowing.not() - } + override fun waitProjectIsBuilt() { + super.waitProjectIsBuilt() + try { + waitFor (ofSeconds(90)) { + inlineProgressTextPanel.isShowing.not() + } + } catch (ignore: Throwable) {} } - override fun expandProjectTree(projectName: String) { + override fun expandProjectTree() { with(projectViewTree) { waitForIgnoringError(ofSeconds(10)) { - hasText("src") + hasText(projectName) } if (hasText("src").not()) { findText(projectName).doubleClick() - waitForIgnoringError{ - hasText("src") - } + } + waitForIgnoringError{ + hasText("src") } if (hasText("main").not()) { findText("src").doubleClick() - waitForIgnoringError{ - hasText("src").and(hasText("main")) - } + } + waitForIgnoringError{ + hasText("src").and(hasText("main")) } if (hasText("java").not()) { findText("main").doubleClick() - waitForIgnoringError{ - hasText("src").and(hasText("main")).and(hasText("java")) - } } - if (hasText("Main").not()) { + waitForIgnoringError{ + hasText("src").and(hasText("main")).and(hasText("java")) + } + if (hasText {it.text.startsWith("org") || it.text.startsWith("com")}.not()) { findText("java").doubleClick() } } diff --git a/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaMavenFrame.kt b/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaMavenFrame.kt index f3fbe39805..c555880aa5 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaMavenFrame.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/pages/IdeaMavenFrame.kt @@ -12,8 +12,8 @@ class IdeaMavenFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) override val buildSystemToUse = IdeaBuildSystem.MAVEN - override fun waitProjectIsOpened() { - super.waitProjectIsOpened() + override fun waitProjectIsBuilt() { + super.waitProjectIsBuilt() waitForIgnoringError (ofSeconds(60)) { projectViewTree.hasText("Main.java").not() projectViewTree.hasText("Main") diff --git a/utbot-intellij/src/test/kotlin/org/utbot/pages/WelcomeFrame.kt b/utbot-intellij/src/test/kotlin/org/utbot/pages/WelcomeFrame.kt index 16eab0011f..987085e6ae 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/pages/WelcomeFrame.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/pages/WelcomeFrame.kt @@ -7,8 +7,11 @@ import com.intellij.remoterobot.search.locators.byXpath import com.intellij.remoterobot.utils.Keyboard import org.utbot.data.IdeaBuildSystem import org.utbot.data.JDKVersion +import org.utbot.dialogs.GetFromVersionControlDialogFixture import org.utbot.dialogs.NewProjectDialogFixture +import org.utbot.dialogs.OpenOrImportProjectDialogFixture import org.utbot.dialogs.OpenProjectDialogFixture +import java.io.File import java.time.Duration fun RemoteRobot.welcomeFrame(function: WelcomeFrame.()-> Unit) { @@ -26,35 +29,52 @@ class WelcomeFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) : get() = actionLink(byXpath("New Project","//div[(@class='MainButton' and @text='New Project') or (@accessiblename='New Project' and @class='JButton')]")) val openProjectLink get() = actionLink(byXpath("Open","//div[(@class='MainButton' and @text='Open') or (@accessiblename.key='action.WelcomeScreen.OpenProject.text')]")) + val getFromVSCLink + get() = actionLink(byXpath("Get from VCS","//div[(@class='MainButton' and @text='Get from VCS')]")) val moreActions get() = button(byXpath("More Action", "//div[@accessiblename='More Actions']")) val recentProjectLinks get() = jTree(byXpath("//div[@class='CardLayoutPanel']//div[@class='Tree']")) + val newProjectDialog + get() = remoteRobot.find(NewProjectDialogFixture::class.java) + val openProjectDialog get() = remoteRobot.find(OpenProjectDialogFixture::class.java) - val newProjectDialog - get() = remoteRobot.find(NewProjectDialogFixture::class.java) + val getFromVersionControlDialog + get() = remoteRobot.find(GetFromVersionControlDialogFixture::class.java) + + val openOrImportProjectDialog + get() = remoteRobot.find(OpenOrImportProjectDialogFixture::class.java, + Duration.ofSeconds(120)) - fun openProjectByPath(projectName: String, - location: String = "") { - val localPath = location + projectName + fun openProjectByPath(location: String, projectName: String = "") { + val separator = File.separator + val localPath = location + separator + projectName openProjectLink.click() - keyboard.enterText(localPath) + keyboard.enterText(localPath.replace(separator, separator + separator)) openProjectDialog.okButton.click() } - fun createNewProject(projectName: String, location: String = "", + fun createNewProject(projectName: String, location: String = "", locationPart: String = "", language: String = "Java", buildSystem: IdeaBuildSystem = IdeaBuildSystem.INTELLIJ, jdkVersion: JDKVersion, addSampleCode: Boolean = true) { newProjectLink.click() newProjectDialog.selectWizard("New Project") newProjectDialog.fillDialog( - projectName, location, language, + projectName, location, locationPart, language, buildSystem, jdkVersion, addSampleCode ) newProjectDialog.createButton.click() } + + fun cloneProjectFromVC(url: String, location: String = "", + buildSystem: IdeaBuildSystem) { + getFromVSCLink.click() + getFromVersionControlDialog.fillDialog(url, location) + getFromVersionControlDialog.cloneButton.click() + openOrImportProjectDialog.selectBuildSystem(buildSystem) + } } diff --git a/utbot-intellij/src/test/kotlin/org/utbot/samples/CodeSamples.kt b/utbot-intellij/src/test/kotlin/org/utbot/samples/CodeSamples.kt index 0464782fe3..5fe1cc06a1 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/samples/CodeSamples.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/samples/CodeSamples.kt @@ -13,7 +13,7 @@ fun TextEditorFixture.typeAdditionFunction(className: String): String { enterText("public int addition(") enterText("int a, int b") key(KeyEvent.VK_END) - enterText("{") + enterText(" {") enter() enterText("// Test run ${TEST_RUN_NUMBER}") enter() @@ -30,7 +30,7 @@ fun TextEditorFixture.typeDivisionFunction(className: String) : String { enterText("public int division(") enterText("int a, int b") key(KeyEvent.VK_END) - enterText("{") + enterText(" {") enter() enterText("// Test run ${TEST_RUN_NUMBER}") enter() diff --git a/utbot-intellij/src/test/kotlin/org/utbot/steps/IDESteps.kt b/utbot-intellij/src/test/kotlin/org/utbot/steps/IDESteps.kt index c6dc22c7b3..7119df5ebf 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/steps/IDESteps.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/steps/IDESteps.kt @@ -1,5 +1,6 @@ package org.utbot.steps +import com.intellij.remoterobot.fixtures.JButtonFixture import com.intellij.remoterobot.fixtures.TextEditorFixture import com.intellij.remoterobot.fixtures.dataExtractor.contains import com.intellij.remoterobot.search.locators.byXpath @@ -38,6 +39,13 @@ fun TextEditorFixture.goToLineAndColumn(row: Int, column: Int) { } } +fun TextEditorFixture.closeAllTabs() { + val closeTabButtons = remoteRobot.findAll(byXpath("//div[@class='EditorTabs']//div[@myicon='close.svg']")) + closeTabButtons.forEach { + it.click() + } +} + fun IdeaFrame.closeTipOfTheDay() { step("Close Tip of the Day if it appears") { waitFor(ofSeconds(20)) { diff --git a/utbot-intellij/src/test/kotlin/org/utbot/tabs/InspectionViewFixture.kt b/utbot-intellij/src/test/kotlin/org/utbot/tabs/InspectionViewFixture.kt new file mode 100644 index 0000000000..b6fc97b370 --- /dev/null +++ b/utbot-intellij/src/test/kotlin/org/utbot/tabs/InspectionViewFixture.kt @@ -0,0 +1,16 @@ +package org.utbot.tabs + +import com.intellij.remoterobot.RemoteRobot +import com.intellij.remoterobot.data.RemoteComponent +import com.intellij.remoterobot.fixtures.* +import com.intellij.remoterobot.search.locators.byXpath +import java.time.Duration.ofSeconds + +@FixtureName("Inspection Results View") +@DefaultXpath("InspectionResultsView type", "//div[@class='InspectionResultsView']") +class InspectionViewFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) : CommonContainerFixture(remoteRobot, remoteComponent) { + + val inspectionTree // not all problems, but only inspections tab + get() = find(byXpath("//div[@class='InspectionTree']"), + ofSeconds(10)) +} diff --git a/utbot-intellij/src/test/kotlin/org/utbot/tests/BaseTest.kt b/utbot-intellij/src/test/kotlin/org/utbot/tests/BaseTest.kt index 2978faa03d..becf8db9eb 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/tests/BaseTest.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/tests/BaseTest.kt @@ -4,25 +4,24 @@ import com.intellij.remoterobot.RemoteRobot import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.params.provider.Arguments import org.utbot.data.IdeaBuildSystem import org.utbot.data.JDKVersion -import org.utbot.pages.IdeaFrame -import org.utbot.pages.IdeaGradleFrame -import org.utbot.pages.IdeaMavenFrame -import org.utbot.pages.idea +import org.utbot.pages.* import org.utbot.utils.RemoteRobotExtension import org.utbot.utils.StepsLogger import java.time.Duration.ofSeconds +@TestInstance(TestInstance.Lifecycle.PER_CLASS) @ExtendWith(RemoteRobotExtension::class) open class BaseTest { fun getIdeaFrameForBuildSystem(remoteRobot: RemoteRobot, ideaBuildSystem: IdeaBuildSystem): IdeaFrame { - when (ideaBuildSystem) { - IdeaBuildSystem.INTELLIJ -> return remoteRobot.find(IdeaFrame::class.java, ofSeconds(10)) - IdeaBuildSystem.GRADLE -> return remoteRobot.find(IdeaGradleFrame::class.java, ofSeconds(10)) - IdeaBuildSystem.MAVEN -> return remoteRobot.find(IdeaMavenFrame::class.java, ofSeconds(10)) + return when (ideaBuildSystem) { + IdeaBuildSystem.INTELLIJ -> remoteRobot.find(IdeaFrame::class.java, ofSeconds(10)) + IdeaBuildSystem.GRADLE -> remoteRobot.find(IdeaGradleFrame::class.java, ofSeconds(10)) + IdeaBuildSystem.MAVEN -> remoteRobot.find(IdeaMavenFrame::class.java, ofSeconds(10)) } } @@ -45,11 +44,11 @@ open class BaseTest { companion object { @BeforeAll @JvmStatic - fun init(remoteRobot: RemoteRobot): Unit = with(remoteRobot) { + fun init(remoteRobot: RemoteRobot) { StepsLogger.init() } - private val supportedProjectsList: List = + internal val supportedProjectsList: List = addPairsToList(true) private val unsupportedProjectsList: List = addPairsToList(false) diff --git a/utbot-intellij/src/test/kotlin/org/utbot/tests/CreateProjects.kt b/utbot-intellij/src/test/kotlin/org/utbot/tests/CreateProjects.kt index eee5299898..82d34b8dbe 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/tests/CreateProjects.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/tests/CreateProjects.kt @@ -2,40 +2,67 @@ package org.utbot.tests import com.intellij.remoterobot.RemoteRobot import com.intellij.remoterobot.utils.waitFor +import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Order import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tags +import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource -import org.utbot.data.IdeaBuildSystem -import org.utbot.data.JDKVersion -import org.utbot.data.NEW_PROJECT_NAME_START +import org.utbot.data.* import org.utbot.pages.welcomeFrame +import java.io.File import java.time.Duration @Order(1) class CreateProjects : BaseTest() { @ParameterizedTest(name = "Create {0} project with JDK {1}") - @Tags(Tag("smoke"), Tag("NewProject"), Tag("Java"), Tag("UTBot"), Tag("")) + @Tags(Tag("Setup"), Tag("Java"), Tag("UTBot")) @MethodSource("allProjectsProvider") - fun createProjectWithSupportedJDK( + fun createProjectWithJDK( ideaBuildSystem: IdeaBuildSystem, jdkVersion: JDKVersion, remoteRobot: RemoteRobot - ): Unit = with(remoteRobot) { - val newProjectName = NEW_PROJECT_NAME_START + ideaBuildSystem.system + jdkVersion.number + ) { + val newProjectName = ideaBuildSystem.system + jdkVersion.number remoteRobot.welcomeFrame { createNewProject( projectName = newProjectName, buildSystem = ideaBuildSystem, - jdkVersion = jdkVersion + jdkVersion = jdkVersion, + location = CURRENT_RUN_DIRECTORY_FULL_PATH, + locationPart = CURRENT_RUN_DIRECTORY_END ) } val ideaFrame = getIdeaFrameForBuildSystem(remoteRobot, ideaBuildSystem) - with(ideaFrame) { - waitProjectIsCreated() - waitFor(Duration.ofSeconds(30)) { + return with(ideaFrame) { + waitProjectIsBuilt() + waitFor(Duration.ofSeconds(90)) { !isDumbMode() } } } + + @Test + @DisplayName("Clone Spring project") + @Tags(Tag("Setup"), Tag("Java"), Tag("Spring"), Tag("UTBot")) + fun cloneSpringProject(remoteRobot: RemoteRobot): Unit = with(remoteRobot) { + welcomeFrame { + cloneProjectFromVC( + SPRING_PROJECT_URL, + CURRENT_RUN_DIRECTORY_FULL_PATH + File.separator + SPRING_PROJECT_NAME, + IdeaBuildSystem.MAVEN + ) + } + with (getIdeaFrameForBuildSystem(remoteRobot, IdeaBuildSystem.GRADLE)) { + try { + loadProjectNotification.projectLoadButton.click() + waitProjectIsBuilt() + } catch (ignore: Throwable) {} + openProjectStructureDialog() + projectStructureDialog.setProjectSdk(JDKVersion.JDK_17) + projectStructureDialog.okButton.click() + waitProjectIsBuilt() + expandProjectTree() + } + } } \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/tests/SpringUTBotActionTest.kt b/utbot-intellij/src/test/kotlin/org/utbot/tests/SpringUTBotActionTest.kt new file mode 100644 index 0000000000..c38b97b00e --- /dev/null +++ b/utbot-intellij/src/test/kotlin/org/utbot/tests/SpringUTBotActionTest.kt @@ -0,0 +1,222 @@ +package org.utbot.tests + +import com.intellij.remoterobot.RemoteRobot +import com.intellij.remoterobot.utils.waitForIgnoringError +import org.assertj.core.api.SoftAssertions +import org.junit.jupiter.api.* +import org.utbot.data.* +import org.utbot.pages.idea +import org.utbot.pages.welcomeFrame +import java.io.File +import java.time.Duration + +class SpringUTBotActionTest : BaseTest() { + + val EXISTING_PACKAGE_NAME = "vet" + val EXISTING_CLASS_NAME = "VetController" + + @BeforeEach + fun openSpringProject(remoteRobot: RemoteRobot): Unit = with(remoteRobot) { + welcomeFrame { + findText { + it.text.endsWith(CURRENT_RUN_DIRECTORY_END + File.separator + SPRING_PROJECT_NAME) + }.click() + } + with (getIdeaFrameForBuildSystem(remoteRobot, IdeaBuildSystem.GRADLE)) { + waitProjectIsBuilt() + try { + loadProjectNotification.projectLoadButton.click() + waitProjectIsBuilt() + } catch (ignore: Throwable) {} + expandProjectTree() + openUTBotDialogFromProjectViewForClass(EXISTING_CLASS_NAME, EXISTING_PACKAGE_NAME) + } + } + + @Test + @DisplayName("Check action dialog UI default state in a Spring project") + @Tags(Tag("Spring"), Tag("Java"), Tag("UnitTestBot"), Tag("UI")) + fun checkSpringDefaultActionDialog(remoteRobot: RemoteRobot) { + with (getIdeaFrameForBuildSystem(remoteRobot, IdeaBuildSystem.GRADLE)) { + with (unitTestBotDialog) { + val softly = SoftAssertions() + softly.assertThat(springConfigurationLabel.isVisible()) + softly.assertThat(springConfigurationComboBox.isShowing) + softly.assertThat(springConfigurationComboBox.selectedText()== "No Configuration") + softly.assertThat(springConfigurationComboBox.listValues() + .containsAll(listOf("No Configuration", "PetClinicApplication", "CacheConfiguration"))) + softly.assertThat(springTestsTypeLabel.isVisible()) + softly.assertThat(springTestsTypeComboBox.isShowing) + softly.assertThat(springTestsTypeComboBox.selectedText() == "Unit tests") + softly.assertThat(springActiveProfilesLabel.isShowing) + softly.assertThat(springActiveProfilesTextField.text =="default") + softly.assertThat(mockingStrategyLabel.isVisible()) + softly.assertThat(mockingStrategyComboBox.selectedText() == "Mock everything outside the class") + softly.assertThat(mockingStrategyComboBox.listValues() + .containsAll(listOf("Do not mock", "Mock everything outside the package", "Mock everything outside the class"))) + softly.assertThat(mockStaticMethodsCheckbox.isShowing) + softly.assertThat(parameterizedTestsCheckbox.isShowing) + softly.assertThat(parameterizedTestsCheckbox.isSelected().not()) + softly.assertThat(testGenerationTimeoutLabel.isShowing) + softly.assertThat(testGenerationTimeoutTextField.text.isNotEmpty()) + softly.assertThat(memberListTable.isShowing) + softly.assertThat(memberListTable.columnCount == 1) + softly.assertThat(memberListTable.rowCount == 2) + softly.assertThat(memberListTable.data.getAll().map { it.text } + .containsAll(listOf("showResourcesVetList():Vets", "showVetList(page:int, model:Model):String"))) + softly.assertThat(generateTestsButton.isEnabled()) + softly.assertThat(arrowOnGenerateTestsButton.isShowing) + arrowOnGenerateTestsButton.click() + softly.assertThat(buttonsList.isShowing) + softly.assertThat(buttonsList.collectItems().containsAll(listOf("Generate Tests", "Generate and Run"))) + softly.assertAll() + } + } + } + + @Test + @DisplayName("Check action dialog UI when Spring configuration is selected") + @Tags(Tag("Spring"), Tag("Java"), Tag("UnitTestBot"), Tag("UI")) + fun checkActionDialogWithSpringConfiguration(remoteRobot: RemoteRobot) { + with (getIdeaFrameForBuildSystem(remoteRobot, IdeaBuildSystem.GRADLE)) { + with (unitTestBotDialog) { + springConfigurationComboBox.click() /* ComboBoxFixture::selectItem doesn't work with heavyWeightWindow */ + heavyWeightWindow().itemsList.clickItem("PetClinicApplication") + val softly = SoftAssertions() + softly.assertThat(springConfigurationComboBox.selectedText()== "PetClinicApplication") + softly.assertThat(springConfigurationComboBox.listValues() + .containsAll(listOf("No Configuration", "PetClinicApplication", "CacheConfiguration"))) + softly.assertThat(springTestsTypeComboBox.selectedText() == "Unit tests") + softly.assertThat(springActiveProfilesTextField.text =="default") + softly.assertThat(generateTestsButton.isEnabled()) + softly.assertAll() + } + } + } + + @Test + @DisplayName("Check action dialog UI when Integration tests are selected") + @Tags(Tag("Spring"), Tag("Java"), Tag("UnitTestBot"), Tag("UI")) + fun checkActionDialogWithIntegrationTests(remoteRobot: RemoteRobot) { + with (getIdeaFrameForBuildSystem(remoteRobot, IdeaBuildSystem.GRADLE)) { + with (unitTestBotDialog) { + springConfigurationComboBox.click() /* ComboBoxFixture::selectItem doesn't work with heavyWeightWindow */ + heavyWeightWindow().itemsList.clickItem("PetClinicApplication") + springTestsTypeComboBox.selectItem("Integration tests") + val softly = SoftAssertions() + softly.assertThat(springConfigurationComboBox.selectedText()== "PetClinicApplication") + softly.assertThat(springConfigurationComboBox.listValues() + .containsAll(listOf("No Configuration", "PetClinicApplication", "CacheConfiguration"))) + softly.assertThat(springTestsTypeComboBox.selectedText() == "Unit tests") + softly.assertThat(springActiveProfilesTextField.text =="default") + softly.assertThat(generateTestsButton.isEnabled()) + softly.assertAll() + } + } + } + + @Order(1) // to close git notification + @Test + @DisplayName("Check Spring Unit tests generation") + @Tags(Tag("Spring"), Tag("Java"), Tag("UnitTestBot"), Tag("Unit tests"), Tag("Generate tests")) + fun checkSpringUnitTestsGeneration(remoteRobot: RemoteRobot) { + with (getIdeaFrameForBuildSystem(remoteRobot, IdeaBuildSystem.GRADLE)) { + with (unitTestBotDialog) { + springConfigurationComboBox.click() /* ComboBoxFixture::selectItem doesn't work with heavyWeightWindow */ + heavyWeightWindow().itemsList.clickItem("PetClinicApplication") + unitTestBotDialog.generateTestsButton.click() + } + waitForIgnoringError (Duration.ofSeconds(10)){ + inlineProgressTextPanel.isShowing + } + waitForIgnoringError (Duration.ofSeconds(60)){ + inlineProgressTextPanel.hasText("Generate test cases for class $EXISTING_CLASS_NAME") + } + waitForIgnoringError (Duration.ofSeconds(90)){ + addToGitNotification.isShowing + } + addToGitNotification.alwaysAddButton.click() // otherwise prompt dialog will be shown for each created test file + waitForIgnoringError(Duration.ofSeconds(90)) { + utbotNotification.title.hasText("UnitTestBot: unit tests generated with warnings") + // because project has several test frameworks + } + val softly = SoftAssertions() + softly.assertThat(utbotNotification.body.hasText("Target: org.springframework.samples.petclinic.vet.VetController Overall test methods: 7")) + softly.assertThat(textEditor().editor.text).contains("class ${EXISTING_CLASS_NAME}Test") + softly.assertThat(textEditor().editor.text).contains("@Test\n") + softly.assertThat(textEditor().editor.text).contains("@InjectMocks\n\tprivate VetController vetController;") + softly.assertThat(textEditor().editor.text).contains("@Mock\n\tprivate VetRepository vetRepositoryMock;") + softly.assertThat(textEditor().editor.text).contains("@utbot.classUnderTest {@link ${EXISTING_CLASS_NAME}}") + softly.assertThat(textEditor().editor.text).contains("@utbot.methodUnderTest {@link ${EXISTING_CLASS_NAME}#showResourcesVetList") + softly.assertThat(textEditor().editor.text).contains("@utbot.methodUnderTest {@link ${EXISTING_CLASS_NAME}#showVetList") + softly.assertThat(inspectionsView.inspectionTree.isShowing) + softly.assertThat(inspectionsView.inspectionTree.hasText("Errors detected by UnitTestBot")) + softly.assertThat(inspectionsView.inspectionTree.hasText("${EXISTING_CLASS_NAME}.java")) + buildResultInEditor.rightClick() // to check test class is compilable + softly.assertThat(heavyWeightWindow().data.getAll().toString().contains("error").not()) + problemsTabButton.click() //to close problems view + softly.assertAll() + } + } + + @Test + @DisplayName("Check Spring Integration tests generation") + @Tags(Tag("Spring"), Tag("Java"), Tag("UnitTestBot"), Tag("Integration tests"), Tag("Generate tests")) + fun checkSpringIntegrationTestsGeneration(remoteRobot: RemoteRobot) { + with (getIdeaFrameForBuildSystem(remoteRobot, IdeaBuildSystem.GRADLE)) { + with (unitTestBotDialog) { + springConfigurationComboBox.click() /* ComboBoxFixture::selectItem doesn't work with heavyWeightWindow */ + heavyWeightWindow().itemsList.clickItem("PetClinicApplication") + springTestsTypeComboBox.selectItem("Integration tests") + unitTestBotDialog.generateTestsButton.click() + unitTestBotDialog.integrationTestsWarningDialog.proceedButton.click() + } + waitForIgnoringError (Duration.ofSeconds(10)){ + inlineProgressTextPanel.isShowing + } + waitForIgnoringError (Duration.ofSeconds(60)){ + inlineProgressTextPanel.hasText("Generate test cases for class $EXISTING_CLASS_NAME") + } + waitForIgnoringError(Duration.ofSeconds(90)) { + utbotNotification.title.hasText("UnitTestBot: unit tests generated with warnings") + // because project has several test frameworks + } + val softly = SoftAssertions() + softly.assertThat(utbotNotification.body.hasText("Target: org.springframework.samples.petclinic.vet.VetController Overall test methods: ")) + softly.assertThat(textEditor().editor.text).contains("@SpringBootTest\n") + softly.assertThat(textEditor().editor.text).contains("@BootstrapWith(SpringBootTestContextBootstrapper.class)\n") + softly.assertThat(textEditor().editor.text).contains("@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)\n") + softly.assertThat(textEditor().editor.text).contains("@Transactional\n") + softly.assertThat(textEditor().editor.text).contains("@AutoConfigureTestDatabase\n") + softly.assertThat(textEditor().editor.text).contains("@AutoConfigureMockMvc\n") + softly.assertThat(textEditor().editor.text).contains("class ${EXISTING_CLASS_NAME}Test") + softly.assertThat(textEditor().editor.text).contains("@Test\n") + softly.assertThat(textEditor().editor.text).contains(CONTEXT_LOADS_TEST_TEXT) + softly.assertThat(textEditor().editor.text).contains("///region FUZZER: SUCCESSFUL EXECUTIONS for method showResourcesVetList()") + softly.assertThat(inspectionsView.inspectionTree.isShowing) + softly.assertThat(inspectionsView.inspectionTree.hasText("Errors detected by UnitTestBot")) + softly.assertThat(inspectionsView.inspectionTree.hasText("${EXISTING_CLASS_NAME}.java")) + buildResultInEditor.rightClick() // to check test class is compilable + softly.assertThat(heavyWeightWindow().data.getAll().toString().contains("error").not()) + problemsTabButton.click() //to close problems view + softly.assertAll() + } + } + + @AfterEach + fun closeDialogIfNotClosed (remoteRobot: RemoteRobot): Unit = with(remoteRobot){ + idea { + try { + unitTestBotDialog.closeButton.click() + } catch (ignore: Throwable) {} + } + } + + val CONTEXT_LOADS_TEST_TEXT = """ /** + * This sanity check test fails if the application context cannot start. + */ + @Test + public void contextLoads() { + }""" + +} \ No newline at end of file diff --git a/utbot-intellij/src/test/kotlin/org/utbot/tests/UnitTestBotActionTest.kt b/utbot-intellij/src/test/kotlin/org/utbot/tests/UTBotActionTest.kt similarity index 59% rename from utbot-intellij/src/test/kotlin/org/utbot/tests/UnitTestBotActionTest.kt rename to utbot-intellij/src/test/kotlin/org/utbot/tests/UTBotActionTest.kt index e06b403bc8..497d6911fe 100644 --- a/utbot-intellij/src/test/kotlin/org/utbot/tests/UnitTestBotActionTest.kt +++ b/utbot-intellij/src/test/kotlin/org/utbot/tests/UTBotActionTest.kt @@ -3,30 +3,32 @@ package org.utbot.tests import com.intellij.remoterobot.RemoteRobot import com.intellij.remoterobot.utils.waitForIgnoringError import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.SoftAssertions +import org.jetbrains.kotlin.konan.file.File import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource -import org.utbot.data.IdeaBuildSystem -import org.utbot.data.JDKVersion -import org.utbot.data.NEW_PROJECT_NAME_START +import org.utbot.data.* import org.utbot.pages.* import org.utbot.samples.typeAdditionFunction import org.utbot.samples.typeDivisionFunction import java.time.Duration.ofSeconds -class UnitTestBotActionTest : BaseTest() { - +class UTBotActionTest : BaseTest() { @ParameterizedTest(name = "Generate tests in {0} project with JDK {1}") @MethodSource("supportedProjectsProvider") - @Tags(Tag("Java"), Tag("UnitTestBot"), Tag("Positive")) + @Tags(Tag("Java"), Tag("UnitTestBot"), Tag("Positive"), Tag("Generate tests")) fun checkBasicTestGeneration(ideaBuildSystem: IdeaBuildSystem, jdkVersion: JDKVersion, remoteRobot: RemoteRobot) { - val createdProjectName = NEW_PROJECT_NAME_START + ideaBuildSystem.system + jdkVersion.number + val createdProjectName = ideaBuildSystem.system + jdkVersion.number remoteRobot.welcomeFrame { - findText(createdProjectName).click() + findText { + it.text.endsWith(CURRENT_RUN_DIRECTORY_END + File.separator + createdProjectName) + }.click() } - val ideaFrame = getIdeaFrameForBuildSystem(remoteRobot, ideaBuildSystem) - with (ideaFrame) { + return with (getIdeaFrameForBuildSystem(remoteRobot, ideaBuildSystem)) { + waitProjectIsBuilt() + expandProjectTree() val newClassName = "Arithmetic" createNewJavaClass(newClassName, "Main") val returnsFromTagBody = textEditor().typeDivisionFunction(newClassName) @@ -41,34 +43,39 @@ class UnitTestBotActionTest : BaseTest() { waitForIgnoringError(ofSeconds(30)) { utbotNotification.title.hasText("UnitTestBot: unit tests generated successfully") } - assertThat(textEditor().editor.text).contains("class ${newClassName}Test") - assertThat(textEditor().editor.text).contains("@Test\n") - assertThat(textEditor().editor.text).contains("assertEquals(") - assertThat(textEditor().editor.text).contains("@utbot.classUnderTest {@link ${newClassName}}") - assertThat(textEditor().editor.text).contains("@utbot.methodUnderTest {@link ${newClassName}#") - assertThat(textEditor().editor.text).contains(returnsFromTagBody) + val softly = SoftAssertions() + softly.assertThat(textEditor().editor.text).contains("class ${newClassName}Test") + softly.assertThat(textEditor().editor.text).contains("@Test\n") + softly.assertThat(textEditor().editor.text).contains("assertEquals(") + softly.assertThat(textEditor().editor.text).contains("@utbot.classUnderTest {@link ${newClassName}}") + softly.assertThat(textEditor().editor.text).contains("@utbot.methodUnderTest {@link ${newClassName}#") + softly.assertThat(textEditor().editor.text).contains(returnsFromTagBody) //ToDo verify how many tests are generated //ToDo verify Problems view and Arithmetic exception on it + softly.assertAll() } } @ParameterizedTest(name = "Check Generate tests button is disabled in {0} project with unsupported JDK {1}") @MethodSource("unsupportedProjectsProvider") - @Tags(Tag("Java"), Tag("UnitTestBot"), Tag("Negative")) + @Tags(Tag("Java"), Tag("UnitTestBot"), Tag("Negative"), Tag("UI")) fun checkProjectWithUnsupportedJDK(ideaBuildSystem: IdeaBuildSystem, jdkVersion: JDKVersion, remoteRobot: RemoteRobot) { - val createdProjectName = NEW_PROJECT_NAME_START + ideaBuildSystem.system + jdkVersion.number + val createdProjectName = ideaBuildSystem.system + jdkVersion.number remoteRobot.welcomeFrame { - findText(createdProjectName).click() + findText { + it.text.endsWith(CURRENT_RUN_DIRECTORY_END + File.separator + createdProjectName) + }.click() } - val ideaFrame = getIdeaFrameForBuildSystem(remoteRobot, ideaBuildSystem) - return with (ideaFrame) { + return with (getIdeaFrameForBuildSystem(remoteRobot, ideaBuildSystem)) { + waitProjectIsBuilt() + expandProjectTree() val newClassName = "Arithmetic" createNewJavaClass(newClassName, "Main") textEditor().typeAdditionFunction(newClassName) openUTBotDialogFromProjectViewForClass(newClassName) assertThat(unitTestBotDialog.generateTestsButton.isEnabled().not()) - assertThat(unitTestBotDialog.sdkNotificationLabel.hasText("SDK version 19 is not supported, use 1.8, 11 or 17 instead.")) + assertThat(unitTestBotDialog.sdkNotificationLabel.hasText("SDK version ${jdkVersion.number} is not supported, use 1.8, 11 or 17 instead.")) assertThat(unitTestBotDialog.setupSdkLink.isShowing) unitTestBotDialog.closeButton.click() }