From a7842dfbdaf2dace47e87773e60024a458c8026b Mon Sep 17 00:00:00 2001 From: vfilin Date: Mon, 27 Oct 2025 09:39:55 +0200 Subject: [PATCH] [AT-3388] Spring Debugger Tests GitOrigin-RevId: d5ad5b100882467b02da922cc85b2b3136dc9985 --- .../common/toolwindows/DebugToolWindowUi.kt | 72 +++++++++++++++---- .../sdk/ui/components/elements/JTreeUI.kt | 3 +- .../idea/window/SpringDebuggerWindow.kt | 30 ++++++++ .../ide/starter/process/processUtils.kt | 2 +- 4 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/idea/window/SpringDebuggerWindow.kt diff --git a/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/common/toolwindows/DebugToolWindowUi.kt b/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/common/toolwindows/DebugToolWindowUi.kt index ace1fba89521..4ee2ab426a37 100644 --- a/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/common/toolwindows/DebugToolWindowUi.kt +++ b/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/common/toolwindows/DebugToolWindowUi.kt @@ -1,23 +1,69 @@ package com.intellij.driver.sdk.ui.components.common.toolwindows import com.intellij.driver.sdk.ui.components.ComponentData +import com.intellij.driver.sdk.ui.components.UiComponent import com.intellij.driver.sdk.ui.components.common.IdeaFrameUI +import com.intellij.driver.sdk.ui.components.elements.JButtonUiComponent +import com.intellij.driver.sdk.ui.components.elements.accessibleList import com.intellij.driver.sdk.ui.components.elements.button +import com.intellij.driver.sdk.ui.shouldBe +import com.intellij.driver.sdk.ui.ui -fun IdeaFrameUI.debugToolWindow(func: DebugToolWindowUi.() -> Unit = {}) = +fun IdeaFrameUI.debugToolWindow(func: DebugToolWindowUi.() -> Unit = {}): DebugToolWindowUi = x(DebugToolWindowUi::class.java) { componentWithChild(byClass("InternalDecoratorImpl"), byAccessibleName("Threads & Variables")) }.apply(func) -class DebugToolWindowUi(data: ComponentData) : ToolWindowUiComponent(data) { - val consoleTab get() = x { and(byClass("SimpleColoredComponent"), byAccessibleName("Console")) } - val threadsAndVariablesTab get() = x { and(byClass("SimpleColoredComponent"), byAccessibleName("Threads & Variables")) } - val debuggerConsoleTab get() = x { and(byClass("SimpleColoredComponent"), byAccessibleName("Debugger Console")) } - val memoryView get() = x { and(byClass("SimpleColoredComponent"), byAccessibleName("Memory View")) } - val consoleView get() = x { byType("com.intellij.execution.impl.ConsoleViewImpl") } - val resumeButton get() = button { byAccessibleName("Resume Program") } - val stopButton get() = x("//div[@myicon='stop.svg']") - val stepOverButton get() = button { byAccessibleName("Step Over") } - val stepOutButton get() = button { byAccessibleName("Step Out") } - val stepIntoButton get() = button { byAccessibleName("Step Into") } - val jbRunnerTabs get() = x { byType("com.intellij.execution.ui.layout.impl.JBRunnerTabs") } +fun DebugToolWindowUi.languageChooser(func: LanguageChooser.() -> Unit = {}): LanguageChooser = x(LanguageChooser::class.java) { byClass("LanguageChooser") }.apply(func) + + +open class DebugToolWindowUi(data: ComponentData) : ToolWindowUiComponent(data) { + + protected var defaultTabs: MutableMap = mapOf("Threads & Variables" to threadsAndVariablesTab, "Console" to consoleTab).toMutableMap() + + protected fun defineDebuggerTabByAccessibleName(name: String): UiComponent = x { and(byClass("SimpleColoredComponent"), byAccessibleName(name)) } + val consoleTab: UiComponent get() = defineDebuggerTabByAccessibleName("Console") + val threadsAndVariablesTab: UiComponent get() = defineDebuggerTabByAccessibleName("Threads & Variables") + val debuggerConsoleTab: UiComponent get() = defineDebuggerTabByAccessibleName("Debugger Console") + val memoryView: UiComponent get() = defineDebuggerTabByAccessibleName("Memory View") + val consoleView: UiComponent get() = x { byType("com.intellij.execution.impl.ConsoleViewImpl") } + val resumeButton: JButtonUiComponent get() = button { byAccessibleName("Resume Program") } + val stopButton: UiComponent get() = x("//div[@myicon='stop.svg']") + val stepOverButton: JButtonUiComponent get() = button { byAccessibleName("Step Over") } + val stepOutButton: JButtonUiComponent get() = button { byAccessibleName("Step Out") } + val stepIntoButton: JButtonUiComponent get() = button { byAccessibleName("Step Into") } + val jbRunnerTabs: UiComponent get() = x { byType("com.intellij.execution.ui.layout.impl.JBRunnerTabs") } + val debugTabWindow: UiComponent get() = x { byType("com.intellij.openapi.wm.impl.ToolWindowImpl") } + + fun selectOptionFromEvaluationToolTip(optionToSelect: String, fullMatch: Boolean = false) { + driver.ui.accessibleList { byClass("LookupList") } + .shouldBe("Evaluation tooltip with available items should be present") { present() } + .clickItem(optionToSelect, fullMatch) + keyboard { + enter() + enter() + } + } } +class LanguageChooser(data: ComponentData) : DebugToolWindowUi(data) { + + fun getCurrentValue(): String { + return getAllTexts().map { it.text }.first() + } + + fun verifyCurrentValue(expectedValue: String): LanguageChooser { + shouldBe("Verify current value equals to $expectedValue", { getCurrentValue() == expectedValue }) + return this + } + + fun openLanguagePicker(): LanguageChooser { + this.click() + return this + } + + fun selectLanguage(languageToSelect: String): LanguageChooser { + driver.ui.accessibleList { and(byAccessibleName("Choose Language"), byClass("MyList")) } + .clickItem(languageToSelect) + return this + } + +} diff --git a/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/elements/JTreeUI.kt b/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/elements/JTreeUI.kt index 046eb23fbc33..154ce82098db 100644 --- a/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/elements/JTreeUI.kt +++ b/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/elements/JTreeUI.kt @@ -122,9 +122,10 @@ open class JTreeUiComponent(data: ComponentData) : UiComponent(data) { } ?: throw PathNotFoundException(path.toList()) } - fun expandAll(timeout: Duration = 5.seconds) { + fun expandAll(timeout: Duration = 5.seconds): JTreeUiComponent { waitForNodesLoaded() fixture.expandAll(timeout.inWholeMilliseconds.toInt()) + return this } fun expandPath(vararg path: String, fullMatch: Boolean = true) { diff --git a/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/idea/window/SpringDebuggerWindow.kt b/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/idea/window/SpringDebuggerWindow.kt new file mode 100644 index 000000000000..72571d550115 --- /dev/null +++ b/platform/remote-driver/test-sdk/src/com/intellij/driver/sdk/ui/components/idea/window/SpringDebuggerWindow.kt @@ -0,0 +1,30 @@ +package com.intellij.driver.sdk.ui.components.idea.window + +import com.intellij.driver.sdk.ui.components.ComponentData +import com.intellij.driver.sdk.ui.components.UiComponent +import com.intellij.driver.sdk.ui.components.UiComponent.Companion.waitFound +import com.intellij.driver.sdk.ui.components.common.IdeaFrameUI +import com.intellij.driver.sdk.ui.components.common.toolwindows.DebugToolWindowUi +import kotlin.time.Duration.Companion.minutes + +fun IdeaFrameUI.springDebuggerWindow(func: SpringDebuggerWindow.() -> Unit = {}): SpringDebuggerWindow = + x(SpringDebuggerWindow::class.java) + { componentWithChild(byClass("InternalDecoratorImpl"), byAccessibleName("Threads & Variables")) } + .waitFound(timeout = 5.minutes) + .apply(func) + +class SpringDebuggerWindow(data: ComponentData) : DebugToolWindowUi(data) { + + val beansTab: UiComponent = defineDebuggerTabByAccessibleName("Beans") + + val healthTab: UiComponent = defineDebuggerTabByAccessibleName("Health") + val mappingsTab: UiComponent = defineDebuggerTabByAccessibleName("Mappings") + val environmentTab: UiComponent = defineDebuggerTabByAccessibleName("Environment, JSON file") + + var springDefaultTabs: Map = defaultTabs.apply { + putIfAbsent("Beans", beansTab) + putIfAbsent("Health", healthTab) + putIfAbsent("Mappings", mappingsTab) + putIfAbsent("Environment, JSON file", environmentTab) + } +} \ No newline at end of file diff --git a/tools/intellij.tools.ide.starter/src/com/intellij/ide/starter/process/processUtils.kt b/tools/intellij.tools.ide.starter/src/com/intellij/ide/starter/process/processUtils.kt index 09f52a23a8c1..58255f042294 100644 --- a/tools/intellij.tools.ide.starter/src/com/intellij/ide/starter/process/processUtils.kt +++ b/tools/intellij.tools.ide.starter/src/com/intellij/ide/starter/process/processUtils.kt @@ -46,7 +46,7 @@ fun findAndKillLeftoverProcessesFromTestRuns(reportErrors: Boolean = false) { val substringToSearch: List = listOf("/$IDE_TESTS_SUBSTRING/", "\\$IDE_TESTS_SUBSTRING\\") findAndKillProcessesBySubstring(*substringToSearch.toTypedArray()) { processInfosToKill -> if (reportErrors) { - val message = "Unexpected running processes were detected after IDE was stopped ${processInfosToKill.joinToString(", ") { it.name }}" + val message = "Unexpected running processes were detected after IDE was stopped ${processInfosToKill.joinToString(", ") { "Process:[Name:${it.name},Id:${it.pid}]\n" }}" CIServer.instance.reportTestFailure(testName = message, message = message + "\n" + "Please investigate if the process should have been stopped together with the IDE, it means it is a bug, you can raise a YT ticket and mute the exception.\n" +