From 0dc672a851d5cb4b4b07c4324d38678cc7557f39 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 14:01:18 +0200 Subject: [PATCH 01/41] chore: allow running GHA on this branch --- .github/workflows/quality-check.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/quality-check.yaml b/.github/workflows/quality-check.yaml index 8f1686534..17fe7fc70 100644 --- a/.github/workflows/quality-check.yaml +++ b/.github/workflows/quality-check.yaml @@ -3,6 +3,7 @@ on: push: branches: - main + - chore/INTELLIJ-107 pull_request: branches: - main From 375f7154be770e7e25e44c68d851c146a86b884b Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 14:23:35 +0200 Subject: [PATCH 02/41] chore: comment out the flaking assertion --- .../impl/MongoDbRunQueryActionUiTest.kt | 43 ++- .../JavaDriverToolbarVisibilityUiTest.kt | 267 +++++++++--------- .../jbplugin/settings/SettingsUiTest.kt | 74 +++-- 3 files changed, 181 insertions(+), 203 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt index 278fb75ff..af1f90329 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt @@ -2,15 +2,12 @@ package com.mongodb.jbplugin.codeActions.impl import com.intellij.remoterobot.RemoteRobot import com.mongodb.jbplugin.fixtures.* -import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbar import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbarPopup import com.mongodb.jbplugin.fixtures.components.findRunQueryGutter import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import kotlin.time.Duration.Companion.minutes @UiTest @RequiresMongoDbCluster @@ -39,24 +36,24 @@ class MongoDbRunQueryActionUiTest { popup.cancel() } - @Test - @RequiresProject("basic-java-project-with-mongodb", smartMode = true) - fun `opens the popup, connects and opens the datagrip console`(remoteRobot: RemoteRobot) { - remoteRobot.ideaFrame().openFile( - "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - ) - remoteRobot.findJavaEditorToolbar().detachDataSource() - remoteRobot.findRunQueryGutter(atLine = 24)!!.click() - // because we are disconnected, we should now try to connect - val popup = remoteRobot.findJavaEditorToolbarPopup() - popup.dataSources.selectItem( - javaClass.simpleName - ) - popup.ok("Run Query", timeout = 1.minutes) - // check that we open a console - eventually { - val currentEditor = remoteRobot.ideaFrame().currentTab() - assertTrue(currentEditor.editor.fileName.startsWith("console")) - } - } + // @Test + // @RequiresProject("basic-java-project-with-mongodb", smartMode = true) + // fun `opens the popup, connects and opens the datagrip console`(remoteRobot: RemoteRobot) { + // remoteRobot.ideaFrame().openFile( + // "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + // ) + // remoteRobot.findJavaEditorToolbar().detachDataSource() + // remoteRobot.findRunQueryGutter(atLine = 24)!!.click() + // // because we are disconnected, we should now try to connect + // val popup = remoteRobot.findJavaEditorToolbarPopup() + // popup.dataSources.selectItem( + // javaClass.simpleName + // ) + // popup.ok("Run Query", timeout = 1.minutes) + // // check that we open a console + // eventually { + // val currentEditor = remoteRobot.ideaFrame().currentTab() + // assertTrue(currentEditor.editor.fileName.startsWith("console")) + // } + // } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index 94b5bc2a3..32f473008 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -1,147 +1,136 @@ package com.mongodb.jbplugin.editor.javaEditor -import com.intellij.remoterobot.RemoteRobot import com.mongodb.jbplugin.fixtures.* -import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbar -import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame -import com.mongodb.jbplugin.fixtures.components.isJavaEditorToolbarHidden -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import kotlin.time.Duration.Companion.minutes -import kotlin.time.toJavaDuration @UiTest @RequiresMongoDbCluster class JavaDriverToolbarVisibilityUiTest { - @BeforeEach - fun setUp( - remoteRobot: RemoteRobot, - url: MongoDbServerUrl, - ) { - remoteRobot.ideaFrame().addDataSourceWithUrl(javaClass.simpleName, url) - } - - @AfterEach - fun tearDown(remoteRobot: RemoteRobot) { - remoteRobot.ideaFrame().cleanDataSources() - } - - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `shows the toolbar in a java file with references to the driver`(remoteRobot: RemoteRobot) { - remoteRobot.ideaFrame().openFile( - "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - ) - val toolbar = remoteRobot.findJavaEditorToolbar() - assertTrue(toolbar.isShowing) - } - - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `shows the toolbar in all the java files with references to the driver`( - remoteRobot: RemoteRobot - ) { - remoteRobot.ideaFrame().openFile( - path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - ) - assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) - - remoteRobot.ideaFrame().openFile( - path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepositoryClone.java", - closeOpenedFiles = false - ) - assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) - - remoteRobot.ideaFrame().openFile( - path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java", - closeOpenedFiles = false - ) - assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) - } - - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `does not show the toolbar in a java file without references to the driver`( - remoteRobot: RemoteRobot - ) { - remoteRobot.ideaFrame().openFile( - "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" - ) - assertTrue(remoteRobot.isJavaEditorToolbarHidden()) - } - - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `does show existing data sources in the combo box`( - remoteRobot: RemoteRobot, - url: MongoDbServerUrl, - ) { - remoteRobot.ideaFrame().openFile( - "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - ) - - val toolbar = remoteRobot.findJavaEditorToolbar() - assertTrue(toolbar.dataSources.listValues().contains(javaClass.simpleName)) - } - - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `does not show the database select on a java driver file`( - remoteRobot: RemoteRobot, - url: MongoDbServerUrl, - ) { - remoteRobot.ideaFrame().openFile( - "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - ) - - val toolbar = remoteRobot.findJavaEditorToolbar() - assertFalse(toolbar.hasDatabasesComboBox) - } - - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `does show the database select on a spring criteria file`( - remoteRobot: RemoteRobot, - url: MongoDbServerUrl, - ) { - remoteRobot.ideaFrame().openFile( - "/src/main/java/alt/mongodb/springcriteria/SpringCriteriaRepository.java" - ) - - val toolbar = remoteRobot.findJavaEditorToolbar() - assertTrue(toolbar.hasDatabasesComboBox) - - eventually(1.minutes.toJavaDuration()) { - // when we select a cluster, it will connect asynchronously - toolbar.dataSources.selectItem(javaClass.simpleName) - } - eventually(1.minutes.toJavaDuration()) { - // it can take a few seconds, we will retry every few milliseconds - // but wait at least for a minute if we can't select a database - toolbar.databases.selectItem("admin") - } - } - - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `shows the toolbar when a reference to the driver is added`( - remoteRobot: RemoteRobot, - url: MongoDbServerUrl, - ) { - assertTrue(remoteRobot.isJavaEditorToolbarHidden()) - - remoteRobot.ideaFrame().openFile( - "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" - ) - val editor = remoteRobot.ideaFrame().currentTab().editor - val textBeforeChanges = editor.text - - editor.insertTextAtLine(1, 0, "import com.mongodb.client.MongoClient;") - - remoteRobot.findJavaEditorToolbar() - editor.text = textBeforeChanges.replace("\n", "\\\n") - } + // @BeforeEach + // fun setUp( + // remoteRobot: RemoteRobot, + // url: MongoDbServerUrl, + // ) { + // remoteRobot.ideaFrame().addDataSourceWithUrl(javaClass.simpleName, url) + // } + // + // @AfterEach + // fun tearDown(remoteRobot: RemoteRobot) { + // remoteRobot.ideaFrame().cleanDataSources() + // } + // + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `shows the toolbar in a java file with references to the driver`(remoteRobot: RemoteRobot) { + // remoteRobot.ideaFrame().openFile( + // "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + // ) + // val toolbar = remoteRobot.findJavaEditorToolbar() + // assertTrue(toolbar.isShowing) + // } + // + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `shows the toolbar in all the java files with references to the driver`( + // remoteRobot: RemoteRobot + // ) { + // remoteRobot.ideaFrame().openFile( + // path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + // ) + // assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) + // + // remoteRobot.ideaFrame().openFile( + // path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepositoryClone.java", + // closeOpenedFiles = false + // ) + // assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) + // + // remoteRobot.ideaFrame().openFile( + // path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java", + // closeOpenedFiles = false + // ) + // assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) + // } + // + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `does not show the toolbar in a java file without references to the driver`( + // remoteRobot: RemoteRobot + // ) { + // remoteRobot.ideaFrame().openFile( + // "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" + // ) + // assertTrue(remoteRobot.isJavaEditorToolbarHidden()) + // } + // + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `does show existing data sources in the combo box`( + // remoteRobot: RemoteRobot, + // url: MongoDbServerUrl, + // ) { + // remoteRobot.ideaFrame().openFile( + // "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + // ) + // + // val toolbar = remoteRobot.findJavaEditorToolbar() + // assertTrue(toolbar.dataSources.listValues().contains(javaClass.simpleName)) + // } + // + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `does not show the database select on a java driver file`( + // remoteRobot: RemoteRobot, + // url: MongoDbServerUrl, + // ) { + // remoteRobot.ideaFrame().openFile( + // "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + // ) + // + // val toolbar = remoteRobot.findJavaEditorToolbar() + // assertFalse(toolbar.hasDatabasesComboBox) + // } + // + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `does show the database select on a spring criteria file`( + // remoteRobot: RemoteRobot, + // url: MongoDbServerUrl, + // ) { + // remoteRobot.ideaFrame().openFile( + // "/src/main/java/alt/mongodb/springcriteria/SpringCriteriaRepository.java" + // ) + // + // val toolbar = remoteRobot.findJavaEditorToolbar() + // assertTrue(toolbar.hasDatabasesComboBox) + // + // eventually(1.minutes.toJavaDuration()) { + // // when we select a cluster, it will connect asynchronously + // toolbar.dataSources.selectItem(javaClass.simpleName) + // } + // eventually(1.minutes.toJavaDuration()) { + // // it can take a few seconds, we will retry every few milliseconds + // // but wait at least for a minute if we can't select a database + // toolbar.databases.selectItem("admin") + // } + // } + // + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `shows the toolbar when a reference to the driver is added`( + // remoteRobot: RemoteRobot, + // url: MongoDbServerUrl, + // ) { + // assertTrue(remoteRobot.isJavaEditorToolbarHidden()) + // + // remoteRobot.ideaFrame().openFile( + // "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" + // ) + // val editor = remoteRobot.ideaFrame().currentTab().editor + // val textBeforeChanges = editor.text + // + // editor.insertTextAtLine(1, 0, "import com.mongodb.client.MongoClient;") + // + // remoteRobot.findJavaEditorToolbar() + // editor.text = textBeforeChanges.replace("\n", "\\\n") + // } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/settings/SettingsUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/settings/SettingsUiTest.kt index 5aedc64aa..c17310a71 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/settings/SettingsUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/settings/SettingsUiTest.kt @@ -1,48 +1,40 @@ package com.mongodb.jbplugin.settings -import com.intellij.remoterobot.RemoteRobot -import com.mongodb.jbplugin.fixtures.RequiresProject import com.mongodb.jbplugin.fixtures.UiTest -import com.mongodb.jbplugin.fixtures.components.openBrowserSettings -import com.mongodb.jbplugin.fixtures.components.openSettings -import com.mongodb.jbplugin.fixtures.components.useSetting -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Test @UiTest class SettingsUiTest { - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `allows toggling the telemetry`(remoteRobot: RemoteRobot) { - val telemetryBeforeTest = remoteRobot.useSetting("isTelemetryEnabled") - - val settings = remoteRobot.openSettings() - settings.enableTelemetry.click() - settings.ok.click() - - val telemetryAfterTest = remoteRobot.useSetting("isTelemetryEnabled") - assertNotEquals(telemetryBeforeTest, telemetryAfterTest) - } - - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `allows opening the privacy policy in a browser`(remoteRobot: RemoteRobot) { - remoteRobot.openBrowserSettings().run { - useFakeBrowser() - } - - val settings = remoteRobot.openSettings() - settings.privacyPolicyButton.click() - settings.ok.click() - - val lastBrowserUrl = - remoteRobot.openBrowserSettings().run { - useSystemBrowser() - ok.click() - lastBrowserUrl() - } - - assertEquals("https://www.mongodb.com/legal/privacy/privacy-policy", lastBrowserUrl) - } + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `allows toggling the telemetry`(remoteRobot: RemoteRobot) { + // val telemetryBeforeTest = remoteRobot.useSetting("isTelemetryEnabled") + // + // val settings = remoteRobot.openSettings() + // settings.enableTelemetry.click() + // settings.ok.click() + // + // val telemetryAfterTest = remoteRobot.useSetting("isTelemetryEnabled") + // assertNotEquals(telemetryBeforeTest, telemetryAfterTest) + // } + // + // @Test + // @RequiresProject("basic-java-project-with-mongodb") + // fun `allows opening the privacy policy in a browser`(remoteRobot: RemoteRobot) { + // remoteRobot.openBrowserSettings().run { + // useFakeBrowser() + // } + // + // val settings = remoteRobot.openSettings() + // settings.privacyPolicyButton.click() + // settings.ok.click() + // + // val lastBrowserUrl = + // remoteRobot.openBrowserSettings().run { + // useSystemBrowser() + // ok.click() + // lastBrowserUrl() + // } + // + // assertEquals("https://www.mongodb.com/legal/privacy/privacy-policy", lastBrowserUrl) + // } } From 17daadfe0cd8b684ff438ee192a019766eaa8f3c Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 16:08:29 +0200 Subject: [PATCH 03/41] chore: use invokeLater for better concurrency control --- .../editor/inputs/DataSourceComboBox.kt | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt index 9d3016b81..f7889abac 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt @@ -8,6 +8,7 @@ import com.intellij.sql.indexOf import com.intellij.ui.AnimatedIcon.ANIMATION_IN_RENDERER_ALLOWED import com.intellij.ui.components.JBLabel import com.mongodb.jbplugin.accessadapter.datagrip.adapter.isConnected +import com.mongodb.jbplugin.editor.models.ToolbarState import com.mongodb.jbplugin.editor.models.getToolbarModel import com.mongodb.jbplugin.i18n.Icons import com.mongodb.jbplugin.i18n.Icons.scaledToText @@ -20,6 +21,7 @@ import java.awt.event.ItemListener import javax.swing.DefaultComboBoxModel import javax.swing.JComponent import javax.swing.SwingConstants +import javax.swing.SwingUtilities import javax.swing.event.PopupMenuEvent import javax.swing.event.PopupMenuListener @@ -98,14 +100,9 @@ class DataSourceComboBox( var isFirstInit = true coroutineScope.launch { project.getToolbarModel().toolbarState.collect { state -> - withoutSelectionChangedListener { - selectedDataSourceConnecting = state.selectedDataSourceConnecting - selectedDataSourceFailedConnecting = state.selectedDataSourceConnectionFailed - if (isFirstInit || state.dataSources != dataSources) { - isFirstInit = false - populateComboBoxWithDataSources(state.dataSources) - } - selectDataSourceByUniqueId(state.selectedDataSource?.uniqueId) + SwingUtilities.invokeLater { + updateComboBoxState(state, isFirstInit) + isFirstInit = false } } } @@ -120,11 +117,28 @@ class DataSourceComboBox( } } - private fun populateComboBoxWithDataSources(dataSources: List) { - comboBoxModel.removeAllElements() - // First item is purposely a null to render "Detach data source label" - comboBoxModel.addElement(null) - comboBoxModel.addAll(dataSources) + private fun updateComboBoxState(state: ToolbarState, isFirstInit: Boolean) = withoutSelectionChangedListener { + selectedDataSourceConnecting = state.selectedDataSourceConnecting + selectedDataSourceFailedConnecting = state.selectedDataSourceConnectionFailed + if (isFirstInit || state.dataSources != dataSources) { + populateComboBoxWithDataSources(state.dataSources.toSet()) + } + selectDataSourceByUniqueId(state.selectedDataSource?.uniqueId) + } + + private fun populateComboBoxWithDataSources(newDataSources: Set) { + val oldDataSources = dataSources.toSet() + + val dataSourcesToAdd = newDataSources - oldDataSources + val dataSourcesToRemove = oldDataSources - newDataSources + + dataSourcesToAdd.forEach { comboBoxModel.addElement(it) } + dataSourcesToRemove.forEach { comboBoxModel.removeElement(it) } + + if (comboBoxModel.getIndexOf(null) != 0) { + comboBoxModel.removeElement(null) + comboBoxModel.insertElementAt(null, 0) + } } private fun selectDataSourceByUniqueId(uniqueId: String?) { From 61fc8b9550c1ae1d1ca9a1d4b3a10df5a0779814 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 16:14:50 +0200 Subject: [PATCH 04/41] chore: re-enable other test for testing --- .../impl/MongoDbRunQueryActionUiTest.kt | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt index af1f90329..6dcb6e48f 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt @@ -2,12 +2,15 @@ package com.mongodb.jbplugin.codeActions.impl import com.intellij.remoterobot.RemoteRobot import com.mongodb.jbplugin.fixtures.* +import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbar import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbarPopup import com.mongodb.jbplugin.fixtures.components.findRunQueryGutter import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import kotlin.time.Duration.Companion.minutes @UiTest @RequiresMongoDbCluster @@ -36,24 +39,24 @@ class MongoDbRunQueryActionUiTest { popup.cancel() } - // @Test - // @RequiresProject("basic-java-project-with-mongodb", smartMode = true) - // fun `opens the popup, connects and opens the datagrip console`(remoteRobot: RemoteRobot) { - // remoteRobot.ideaFrame().openFile( - // "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - // ) - // remoteRobot.findJavaEditorToolbar().detachDataSource() - // remoteRobot.findRunQueryGutter(atLine = 24)!!.click() - // // because we are disconnected, we should now try to connect - // val popup = remoteRobot.findJavaEditorToolbarPopup() - // popup.dataSources.selectItem( - // javaClass.simpleName - // ) - // popup.ok("Run Query", timeout = 1.minutes) - // // check that we open a console - // eventually { - // val currentEditor = remoteRobot.ideaFrame().currentTab() - // assertTrue(currentEditor.editor.fileName.startsWith("console")) - // } - // } + @Test + @RequiresProject("basic-java-project-with-mongodb", smartMode = true) + fun `opens the popup, connects and opens the datagrip console`(remoteRobot: RemoteRobot) { + remoteRobot.ideaFrame().openFile( + "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + ) + remoteRobot.findJavaEditorToolbar().detachDataSource() + remoteRobot.findRunQueryGutter(atLine = 24)!!.click() + // because we are disconnected, we should now try to connect + val popup = remoteRobot.findJavaEditorToolbarPopup() + popup.dataSources.selectItem( + javaClass.simpleName + ) + popup.ok("Run Query", timeout = 1.minutes) + // check that we open a console + eventually { + val currentEditor = remoteRobot.ideaFrame().currentTab() + assertTrue(currentEditor.editor.fileName.startsWith("console")) + } + } } From 3879ff1de5a3bb19c03250083fd6e25c4dc3a8aa Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 16:40:14 +0200 Subject: [PATCH 05/41] chore: make dependent actions recoverable --- .../impl/MongoDbRunQueryActionUiTest.kt | 19 ++++++----------- .../components/MdbActionGutterFixture.kt | 14 +++++++++++-- .../components/MdbJavaEditorToolbarFixture.kt | 17 ++++++++++++--- .../MdbJavaEditorToolbarPopupFixture.kt | 21 +++++++++++++++++++ 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt index 6dcb6e48f..758158287 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt @@ -2,15 +2,14 @@ package com.mongodb.jbplugin.codeActions.impl import com.intellij.remoterobot.RemoteRobot import com.mongodb.jbplugin.fixtures.* -import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbar -import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbarPopup -import com.mongodb.jbplugin.fixtures.components.findRunQueryGutter import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame +import com.mongodb.jbplugin.fixtures.components.openRunQueryPopup import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import kotlin.time.Duration.Companion.minutes +import kotlin.time.toJavaDuration @UiTest @RequiresMongoDbCluster @@ -34,8 +33,7 @@ class MongoDbRunQueryActionUiTest { remoteRobot.ideaFrame().openFile( "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" ) - remoteRobot.findRunQueryGutter(atLine = 24)!!.click() - val popup = remoteRobot.findJavaEditorToolbarPopup() + val popup = remoteRobot.openRunQueryPopup(atLine = 24) popup.cancel() } @@ -45,16 +43,11 @@ class MongoDbRunQueryActionUiTest { remoteRobot.ideaFrame().openFile( "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" ) - remoteRobot.findJavaEditorToolbar().detachDataSource() - remoteRobot.findRunQueryGutter(atLine = 24)!!.click() - // because we are disconnected, we should now try to connect - val popup = remoteRobot.findJavaEditorToolbarPopup() - popup.dataSources.selectItem( - javaClass.simpleName - ) + val popup = remoteRobot.openRunQueryPopup(atLine = 24) + popup.selectDataSource(javaClass.simpleName) popup.ok("Run Query", timeout = 1.minutes) // check that we open a console - eventually { + eventually(1.minutes.toJavaDuration()) { val currentEditor = remoteRobot.ideaFrame().currentTab() assertTrue(currentEditor.editor.fileName.startsWith("console")) } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt index 6ff6ef822..dc8fa5763 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt @@ -20,8 +20,8 @@ fun RemoteRobot.findRunQueryGutter(atLine: Int? = null) = eventually ideaFrame().currentTab() .gutter.run { atLine?.let { -// for some reason, gutter icons lines are always 2 minus the line in the editor :shrug: -// hide this somehow in this implementation + // for some reason, gutter icons lines are always 2 minus the line in the editor :shrug: + // hide this somehow in this implementation getIcons().find { it.lineNumber == atLine - 2 && it.description.contains("path=/icons/ConsoleRun") @@ -29,3 +29,13 @@ fun RemoteRobot.findRunQueryGutter(atLine: Int? = null) = eventually } ?: getIcons().find { it.description.contains("path=/icons/ConsoleRun") } }!! } + +fun RemoteRobot.openRunQueryPopup(atLine: Int? = null): MdbJavaEditorToolbarPopupFixture { + // We always deselect the current data source because otherwise clicking on gutter icon will + // do the action instead itself of opening the popup + findJavaEditorToolbar().selectDetachDataSource() + return eventually { + findRunQueryGutter(atLine)!!.click() + return@eventually findJavaEditorToolbarPopup() + }!! +} diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt index 2a821081f..049717b09 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt @@ -12,6 +12,7 @@ import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration @@ -43,10 +44,20 @@ class MdbJavaEditorToolbarFixture( timeout = 50.milliseconds.toJavaDuration() ) }.isSuccess - fun detachDataSource() { - eventually { + + fun selectDataSource(title: String) { + eventually(1.minutes.toJavaDuration()) { + dataSources.selectItemContains(title) + if (!dataSources.selectedText().contains(title)) { + throw Exception("Could not select data source - $title") + } + } + } + + fun selectDetachDataSource() { + eventually(1.minutes.toJavaDuration()) { dataSources.selectItem("Detach data source") - if (!dataSources.selectedText().contains("Attach MongoDB")) { + if (dataSources.selectedText() != "") { throw Exception("Could not detach data source") } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt index 5a45f7fa4..cd3201ee0 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt @@ -5,9 +5,11 @@ 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 com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration @@ -50,7 +52,26 @@ class MdbJavaEditorToolbarPopupFixture( } button.click() } + fun cancel() = find(byXpath("//div[@text='Cancel']")).click() + + fun selectDataSource(title: String) { + eventually(1.minutes.toJavaDuration()) { + dataSources.selectItemContains(title) + if (!dataSources.selectedText().contains(title)) { + throw Exception("Could not select data source - $title") + } + } + } + + fun selectDetachDataSource() { + eventually(1.minutes.toJavaDuration()) { + dataSources.selectItem("Detach data source") + if (dataSources.selectedText() != "") { + throw Exception("Could not detach data source") + } + } + } } /** From 7d2ddd16cffa52c8f0a40b38f9bb74558638bd8c Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 16:46:24 +0200 Subject: [PATCH 06/41] chore: decrease the recovery timeout for actions --- .../jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt | 3 ++- .../jbplugin/fixtures/components/MdbActionGutterFixture.kt | 4 +++- .../fixtures/components/MdbJavaEditorToolbarFixture.kt | 5 ++--- .../fixtures/components/MdbJavaEditorToolbarPopupFixture.kt | 5 ++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt index 758158287..024333f11 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration @UiTest @@ -47,7 +48,7 @@ class MongoDbRunQueryActionUiTest { popup.selectDataSource(javaClass.simpleName) popup.ok("Run Query", timeout = 1.minutes) // check that we open a console - eventually(1.minutes.toJavaDuration()) { + eventually(30.seconds.toJavaDuration()) { val currentEditor = remoteRobot.ideaFrame().currentTab() assertTrue(currentEditor.editor.fileName.startsWith("console")) } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt index dc8fa5763..3d0fe5fb4 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt @@ -8,6 +8,8 @@ import com.intellij.remoterobot.RemoteRobot import com.intellij.remoterobot.fixtures.GutterIcon import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame import com.mongodb.jbplugin.fixtures.eventually +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration /** * Function that returns the run query gutter at a specific line if provided. If no line provided, @@ -34,7 +36,7 @@ fun RemoteRobot.openRunQueryPopup(atLine: Int? = null): MdbJavaEditorToolbarPopu // We always deselect the current data source because otherwise clicking on gutter icon will // do the action instead itself of opening the popup findJavaEditorToolbar().selectDetachDataSource() - return eventually { + return eventually(10.seconds.toJavaDuration()) { findRunQueryGutter(atLine)!!.click() return@eventually findJavaEditorToolbarPopup() }!! diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt index 049717b09..8b3d7aa61 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt @@ -12,7 +12,6 @@ import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration @@ -46,7 +45,7 @@ class MdbJavaEditorToolbarFixture( }.isSuccess fun selectDataSource(title: String) { - eventually(1.minutes.toJavaDuration()) { + eventually(30.seconds.toJavaDuration()) { dataSources.selectItemContains(title) if (!dataSources.selectedText().contains(title)) { throw Exception("Could not select data source - $title") @@ -55,7 +54,7 @@ class MdbJavaEditorToolbarFixture( } fun selectDetachDataSource() { - eventually(1.minutes.toJavaDuration()) { + eventually(30.seconds.toJavaDuration()) { dataSources.selectItem("Detach data source") if (dataSources.selectedText() != "") { throw Exception("Could not detach data source") diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt index cd3201ee0..d983e1fc7 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt @@ -9,7 +9,6 @@ import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration @@ -56,7 +55,7 @@ class MdbJavaEditorToolbarPopupFixture( fun cancel() = find(byXpath("//div[@text='Cancel']")).click() fun selectDataSource(title: String) { - eventually(1.minutes.toJavaDuration()) { + eventually(30.seconds.toJavaDuration()) { dataSources.selectItemContains(title) if (!dataSources.selectedText().contains(title)) { throw Exception("Could not select data source - $title") @@ -65,7 +64,7 @@ class MdbJavaEditorToolbarPopupFixture( } fun selectDetachDataSource() { - eventually(1.minutes.toJavaDuration()) { + eventually(30.seconds.toJavaDuration()) { dataSources.selectItem("Detach data source") if (dataSources.selectedText() != "") { throw Exception("Could not detach data source") From 89663e2bb020cc116c084186dd7284d4cd1e9d09 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 17:58:12 +0200 Subject: [PATCH 07/41] chore: decrease the recovery timeout for actions, enable other UI tests --- .../JavaDriverToolbarVisibilityUiTest.kt | 53 +++++++++++-------- .../components/MdbJavaEditorToolbarFixture.kt | 4 +- .../MdbJavaEditorToolbarPopupFixture.kt | 4 +- .../fixtures/components/idea/IdeaFrame.kt | 5 ++ 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index 32f473008..bb3d62d65 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -1,33 +1,40 @@ package com.mongodb.jbplugin.editor.javaEditor +import com.intellij.remoterobot.RemoteRobot import com.mongodb.jbplugin.fixtures.* +import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbar +import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test @UiTest @RequiresMongoDbCluster class JavaDriverToolbarVisibilityUiTest { - // @BeforeEach - // fun setUp( - // remoteRobot: RemoteRobot, - // url: MongoDbServerUrl, - // ) { - // remoteRobot.ideaFrame().addDataSourceWithUrl(javaClass.simpleName, url) - // } - // - // @AfterEach - // fun tearDown(remoteRobot: RemoteRobot) { - // remoteRobot.ideaFrame().cleanDataSources() - // } - // - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `shows the toolbar in a java file with references to the driver`(remoteRobot: RemoteRobot) { - // remoteRobot.ideaFrame().openFile( - // "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - // ) - // val toolbar = remoteRobot.findJavaEditorToolbar() - // assertTrue(toolbar.isShowing) - // } - // + @BeforeEach + fun setUp( + remoteRobot: RemoteRobot, + url: MongoDbServerUrl, + ) { + remoteRobot.ideaFrame().addDataSourceWithUrl(javaClass.simpleName, url) + } + + @AfterEach + fun tearDown(remoteRobot: RemoteRobot) { + remoteRobot.ideaFrame().cleanDataSources() + } + + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `shows the toolbar in a java file with references to the driver`(remoteRobot: RemoteRobot) { + remoteRobot.ideaFrame().openFile( + "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + ) + val toolbar = remoteRobot.findJavaEditorToolbar() + assertTrue(toolbar.isShowing) + } + // @Test // @RequiresProject("basic-java-project-with-mongodb") // fun `shows the toolbar in all the java files with references to the driver`( diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt index 8b3d7aa61..2c06cf52f 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt @@ -45,7 +45,7 @@ class MdbJavaEditorToolbarFixture( }.isSuccess fun selectDataSource(title: String) { - eventually(30.seconds.toJavaDuration()) { + eventually(10.seconds.toJavaDuration()) { dataSources.selectItemContains(title) if (!dataSources.selectedText().contains(title)) { throw Exception("Could not select data source - $title") @@ -54,7 +54,7 @@ class MdbJavaEditorToolbarFixture( } fun selectDetachDataSource() { - eventually(30.seconds.toJavaDuration()) { + eventually(10.seconds.toJavaDuration()) { dataSources.selectItem("Detach data source") if (dataSources.selectedText() != "") { throw Exception("Could not detach data source") diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt index d983e1fc7..8b6812a14 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt @@ -55,7 +55,7 @@ class MdbJavaEditorToolbarPopupFixture( fun cancel() = find(byXpath("//div[@text='Cancel']")).click() fun selectDataSource(title: String) { - eventually(30.seconds.toJavaDuration()) { + eventually(10.seconds.toJavaDuration()) { dataSources.selectItemContains(title) if (!dataSources.selectedText().contains(title)) { throw Exception("Could not select data source - $title") @@ -64,7 +64,7 @@ class MdbJavaEditorToolbarPopupFixture( } fun selectDetachDataSource() { - eventually(30.seconds.toJavaDuration()) { + eventually(10.seconds.toJavaDuration()) { dataSources.selectItem("Detach data source") if (dataSources.selectedText() != "") { throw Exception("Could not detach data source") diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index e92688e41..6e2f4357f 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -71,6 +71,7 @@ class IdeaFrame( """, true, ) + CommonSteps(remoteRobot).wait(1) } fun currentTab(): TextEditorFixture = remoteRobot.findVisible( @@ -132,6 +133,7 @@ class IdeaFrame( """.trimIndent(), runInEdt = true, ) + CommonSteps(remoteRobot).wait(1) } fun waitUntilConnectedToMongoDb(name: String, timeout: Duration = Duration.ofMinutes(1)) { @@ -191,6 +193,7 @@ class IdeaFrame( """.trimIndent() ) } + CommonSteps(remoteRobot).wait(1) } fun waitUntilProjectIsInSync() { @@ -264,6 +267,7 @@ class IdeaFrame( """.trimIndent(), runInEdt = true, ) + CommonSteps(remoteRobot).wait(1) } fun closeAllFiles() { @@ -290,6 +294,7 @@ class IdeaFrame( """, true, ) + CommonSteps(remoteRobot).wait(1) } fun ensureNotificationIsVisible(title: String) { From f76781841c069b115a16454f825fd1142fc29924 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 18:06:05 +0200 Subject: [PATCH 08/41] chore: enable more UI tests --- .../JavaDriverToolbarVisibilityUiTest.kt | 97 ++++++++++--------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index bb3d62d65..4ad53e401 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -4,6 +4,7 @@ import com.intellij.remoterobot.RemoteRobot import com.mongodb.jbplugin.fixtures.* import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbar import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame +import com.mongodb.jbplugin.fixtures.components.isJavaEditorToolbarHidden import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach @@ -35,54 +36,54 @@ class JavaDriverToolbarVisibilityUiTest { assertTrue(toolbar.isShowing) } - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `shows the toolbar in all the java files with references to the driver`( - // remoteRobot: RemoteRobot - // ) { - // remoteRobot.ideaFrame().openFile( - // path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - // ) - // assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) - // - // remoteRobot.ideaFrame().openFile( - // path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepositoryClone.java", - // closeOpenedFiles = false - // ) - // assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) - // - // remoteRobot.ideaFrame().openFile( - // path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java", - // closeOpenedFiles = false - // ) - // assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) - // } - // - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `does not show the toolbar in a java file without references to the driver`( - // remoteRobot: RemoteRobot - // ) { - // remoteRobot.ideaFrame().openFile( - // "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" - // ) - // assertTrue(remoteRobot.isJavaEditorToolbarHidden()) - // } - // - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `does show existing data sources in the combo box`( - // remoteRobot: RemoteRobot, - // url: MongoDbServerUrl, - // ) { - // remoteRobot.ideaFrame().openFile( - // "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - // ) - // - // val toolbar = remoteRobot.findJavaEditorToolbar() - // assertTrue(toolbar.dataSources.listValues().contains(javaClass.simpleName)) - // } - // + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `shows the toolbar in all the java files with references to the driver`( + remoteRobot: RemoteRobot + ) { + remoteRobot.ideaFrame().openFile( + path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + ) + assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) + + remoteRobot.ideaFrame().openFile( + path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepositoryClone.java", + closeOpenedFiles = false + ) + assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) + + remoteRobot.ideaFrame().openFile( + path = "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java", + closeOpenedFiles = false + ) + assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) + } + + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `does not show the toolbar in a java file without references to the driver`( + remoteRobot: RemoteRobot + ) { + remoteRobot.ideaFrame().openFile( + "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" + ) + assertTrue(remoteRobot.isJavaEditorToolbarHidden()) + } + + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `does show existing data sources in the combo box`( + remoteRobot: RemoteRobot, + url: MongoDbServerUrl, + ) { + remoteRobot.ideaFrame().openFile( + "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + ) + + val toolbar = remoteRobot.findJavaEditorToolbar() + assertTrue(toolbar.dataSources.listValues().contains(javaClass.simpleName)) + } + // @Test // @RequiresProject("basic-java-project-with-mongodb") // fun `does not show the database select on a java driver file`( From fe49142030d95f0c017759101b87ccc9a68fcd6d Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 18:48:15 +0200 Subject: [PATCH 09/41] chore: enable more UI tests --- .../JavaDriverToolbarVisibilityUiTest.kt | 114 +++++++++--------- .../components/MdbJavaEditorToolbarFixture.kt | 14 ++- .../MdbJavaEditorToolbarPopupFixture.kt | 14 ++- .../mongodb/javadriver/NoDriverReference.java | 5 +- 4 files changed, 82 insertions(+), 65 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index 4ad53e401..bbbe374b3 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -9,6 +9,8 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import kotlin.time.Duration.Companion.minutes +import kotlin.time.toJavaDuration @UiTest @RequiresMongoDbCluster @@ -84,61 +86,59 @@ class JavaDriverToolbarVisibilityUiTest { assertTrue(toolbar.dataSources.listValues().contains(javaClass.simpleName)) } - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `does not show the database select on a java driver file`( - // remoteRobot: RemoteRobot, - // url: MongoDbServerUrl, - // ) { - // remoteRobot.ideaFrame().openFile( - // "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" - // ) - // - // val toolbar = remoteRobot.findJavaEditorToolbar() - // assertFalse(toolbar.hasDatabasesComboBox) - // } - // - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `does show the database select on a spring criteria file`( - // remoteRobot: RemoteRobot, - // url: MongoDbServerUrl, - // ) { - // remoteRobot.ideaFrame().openFile( - // "/src/main/java/alt/mongodb/springcriteria/SpringCriteriaRepository.java" - // ) - // - // val toolbar = remoteRobot.findJavaEditorToolbar() - // assertTrue(toolbar.hasDatabasesComboBox) - // - // eventually(1.minutes.toJavaDuration()) { - // // when we select a cluster, it will connect asynchronously - // toolbar.dataSources.selectItem(javaClass.simpleName) - // } - // eventually(1.minutes.toJavaDuration()) { - // // it can take a few seconds, we will retry every few milliseconds - // // but wait at least for a minute if we can't select a database - // toolbar.databases.selectItem("admin") - // } - // } - // - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `shows the toolbar when a reference to the driver is added`( - // remoteRobot: RemoteRobot, - // url: MongoDbServerUrl, - // ) { - // assertTrue(remoteRobot.isJavaEditorToolbarHidden()) - // - // remoteRobot.ideaFrame().openFile( - // "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" - // ) - // val editor = remoteRobot.ideaFrame().currentTab().editor - // val textBeforeChanges = editor.text - // - // editor.insertTextAtLine(1, 0, "import com.mongodb.client.MongoClient;") - // - // remoteRobot.findJavaEditorToolbar() - // editor.text = textBeforeChanges.replace("\n", "\\\n") - // } + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `does not show the database select on a java driver file`( + remoteRobot: RemoteRobot, + url: MongoDbServerUrl, + ) { + remoteRobot.ideaFrame().openFile( + "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" + ) + + val toolbar = remoteRobot.findJavaEditorToolbar() + assertFalse(toolbar.hasDatabasesComboBox) + } + + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `does show the database select on a spring criteria file`( + remoteRobot: RemoteRobot, + url: MongoDbServerUrl, + ) { + remoteRobot.ideaFrame().openFile( + "/src/main/java/alt/mongodb/springcriteria/SpringCriteriaRepository.java" + ) + + val toolbar = remoteRobot.findJavaEditorToolbar() + assertTrue(toolbar.hasDatabasesComboBox) + + toolbar.selectDataSource(javaClass.simpleName) + + eventually(1.minutes.toJavaDuration()) { + // it can take a few seconds, we will retry every few milliseconds + // but wait at least for a minute if we can't select a database + toolbar.selectDatabase("admin") + } + } + + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `shows the toolbar when a reference to the driver is added`( + remoteRobot: RemoteRobot, + url: MongoDbServerUrl, + ) { + assertTrue(remoteRobot.isJavaEditorToolbarHidden()) + + remoteRobot.ideaFrame().openFile( + "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" + ) + val editor = remoteRobot.ideaFrame().currentTab().editor + val textBeforeChanges = editor.text + + editor.insertTextAtLine(1, 0, "import com.mongodb.client.MongoClient;") + + remoteRobot.findJavaEditorToolbar() + editor.text = textBeforeChanges.replace("\n", "\\\n") + } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt index 2c06cf52f..75af3c93c 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt @@ -12,6 +12,7 @@ import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration @@ -45,7 +46,7 @@ class MdbJavaEditorToolbarFixture( }.isSuccess fun selectDataSource(title: String) { - eventually(10.seconds.toJavaDuration()) { + eventually(1.minutes.toJavaDuration()) { dataSources.selectItemContains(title) if (!dataSources.selectedText().contains(title)) { throw Exception("Could not select data source - $title") @@ -54,13 +55,22 @@ class MdbJavaEditorToolbarFixture( } fun selectDetachDataSource() { - eventually(10.seconds.toJavaDuration()) { + eventually(1.minutes.toJavaDuration()) { dataSources.selectItem("Detach data source") if (dataSources.selectedText() != "") { throw Exception("Could not detach data source") } } } + + fun selectDatabase(title: String) { + eventually(1.minutes.toJavaDuration()) { + databases.selectItemContains(title) + if (!databases.selectedText().contains(title)) { + throw Exception("Could not select database - $title") + } + } + } } /** diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt index 8b6812a14..c1b0dcf27 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt @@ -9,6 +9,7 @@ import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration @@ -55,7 +56,7 @@ class MdbJavaEditorToolbarPopupFixture( fun cancel() = find(byXpath("//div[@text='Cancel']")).click() fun selectDataSource(title: String) { - eventually(10.seconds.toJavaDuration()) { + eventually(1.minutes.toJavaDuration()) { dataSources.selectItemContains(title) if (!dataSources.selectedText().contains(title)) { throw Exception("Could not select data source - $title") @@ -64,13 +65,22 @@ class MdbJavaEditorToolbarPopupFixture( } fun selectDetachDataSource() { - eventually(10.seconds.toJavaDuration()) { + eventually(1.minutes.toJavaDuration()) { dataSources.selectItem("Detach data source") if (dataSources.selectedText() != "") { throw Exception("Could not detach data source") } } } + + fun selectDatabase(title: String) { + eventually(1.minutes.toJavaDuration()) { + databases.selectItemContains(title) + if (!databases.selectedText().contains(title)) { + throw Exception("Could not select database - $title") + } + } + } } /** diff --git a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/src/main/java/alt/mongodb/javadriver/NoDriverReference.java b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/src/main/java/alt/mongodb/javadriver/NoDriverReference.java index 641531e82..396519830 100644 --- a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/src/main/java/alt/mongodb/javadriver/NoDriverReference.java +++ b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/src/main/java/alt/mongodb/javadriver/NoDriverReference.java @@ -1,4 +1 @@ -package alt.mongodb.javadriver; - -public class NoDriverReference { -} +package alt.mongodb.javadriver;public class NoDriverReference {} From 1f440aae5dbae36d082212402098c2dd60695fc6 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 18:55:50 +0200 Subject: [PATCH 10/41] chore: fixing assertion --- .../editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt | 3 +-- .../main/java/alt/mongodb/javadriver/NoDriverReference.java | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index bbbe374b3..0cb366c4d 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -128,11 +128,10 @@ class JavaDriverToolbarVisibilityUiTest { remoteRobot: RemoteRobot, url: MongoDbServerUrl, ) { - assertTrue(remoteRobot.isJavaEditorToolbarHidden()) - remoteRobot.ideaFrame().openFile( "/src/main/java/alt/mongodb/javadriver/NoDriverReference.java" ) + assertTrue(remoteRobot.isJavaEditorToolbarHidden()) val editor = remoteRobot.ideaFrame().currentTab().editor val textBeforeChanges = editor.text diff --git a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/src/main/java/alt/mongodb/javadriver/NoDriverReference.java b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/src/main/java/alt/mongodb/javadriver/NoDriverReference.java index 396519830..641531e82 100644 --- a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/src/main/java/alt/mongodb/javadriver/NoDriverReference.java +++ b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/src/main/java/alt/mongodb/javadriver/NoDriverReference.java @@ -1 +1,4 @@ -package alt.mongodb.javadriver;public class NoDriverReference {} +package alt.mongodb.javadriver; + +public class NoDriverReference { +} From 503884e6b415348c0b92db402941207b7f8faff9 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 17 Oct 2024 19:03:20 +0200 Subject: [PATCH 11/41] chore: enable rest of the UI tests --- .../jbplugin/settings/SettingsUiTest.kt | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/settings/SettingsUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/settings/SettingsUiTest.kt index c17310a71..9922ee396 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/settings/SettingsUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/settings/SettingsUiTest.kt @@ -1,40 +1,47 @@ package com.mongodb.jbplugin.settings +import com.intellij.remoterobot.RemoteRobot +import com.mongodb.jbplugin.fixtures.RequiresProject import com.mongodb.jbplugin.fixtures.UiTest +import com.mongodb.jbplugin.fixtures.components.openBrowserSettings +import com.mongodb.jbplugin.fixtures.components.openSettings +import com.mongodb.jbplugin.fixtures.components.useSetting +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test @UiTest class SettingsUiTest { - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `allows toggling the telemetry`(remoteRobot: RemoteRobot) { - // val telemetryBeforeTest = remoteRobot.useSetting("isTelemetryEnabled") - // - // val settings = remoteRobot.openSettings() - // settings.enableTelemetry.click() - // settings.ok.click() - // - // val telemetryAfterTest = remoteRobot.useSetting("isTelemetryEnabled") - // assertNotEquals(telemetryBeforeTest, telemetryAfterTest) - // } - // - // @Test - // @RequiresProject("basic-java-project-with-mongodb") - // fun `allows opening the privacy policy in a browser`(remoteRobot: RemoteRobot) { - // remoteRobot.openBrowserSettings().run { - // useFakeBrowser() - // } - // - // val settings = remoteRobot.openSettings() - // settings.privacyPolicyButton.click() - // settings.ok.click() - // - // val lastBrowserUrl = - // remoteRobot.openBrowserSettings().run { - // useSystemBrowser() - // ok.click() - // lastBrowserUrl() - // } - // - // assertEquals("https://www.mongodb.com/legal/privacy/privacy-policy", lastBrowserUrl) - // } + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `allows toggling the telemetry`(remoteRobot: RemoteRobot) { + val telemetryBeforeTest = remoteRobot.useSetting("isTelemetryEnabled") + + val settings = remoteRobot.openSettings() + settings.enableTelemetry.click() + settings.ok.click() + + val telemetryAfterTest = remoteRobot.useSetting("isTelemetryEnabled") + assertNotEquals(telemetryBeforeTest, telemetryAfterTest) + } + + @Test + @RequiresProject("basic-java-project-with-mongodb") + fun `allows opening the privacy policy in a browser`(remoteRobot: RemoteRobot) { + remoteRobot.openBrowserSettings().run { + useFakeBrowser() + } + + val settings = remoteRobot.openSettings() + settings.privacyPolicyButton.click() + settings.ok.click() + + val lastBrowserUrl = + remoteRobot.openBrowserSettings().run { + useSystemBrowser() + ok.click() + lastBrowserUrl() + } + + assertEquals("https://www.mongodb.com/legal/privacy/privacy-policy", lastBrowserUrl) + } } From ff4d1a22aa48d68e3d17e531ed90461405af0680 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 09:18:48 +0200 Subject: [PATCH 12/41] chore: use invokeLater for better concurrency control on DatabaseComboBox --- .../editor/inputs/DatabaseComboBox.kt | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt index 2423f18d0..5e53a4950 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt @@ -5,6 +5,7 @@ import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.asSequence import com.intellij.ui.AnimatedIcon.ANIMATION_IN_RENDERER_ALLOWED import com.intellij.ui.components.JBLabel +import com.mongodb.jbplugin.editor.models.ToolbarState import com.mongodb.jbplugin.editor.models.getToolbarModel import com.mongodb.jbplugin.i18n.Icons import com.mongodb.jbplugin.i18n.Icons.scaledToText @@ -17,6 +18,7 @@ import java.awt.event.ItemListener import javax.swing.DefaultComboBoxModel import javax.swing.JComponent import javax.swing.SwingConstants +import javax.swing.SwingUtilities import javax.swing.event.PopupMenuEvent import javax.swing.event.PopupMenuListener @@ -78,13 +80,9 @@ class DatabaseComboBox( var isFirstInit = true coroutineScope.launch { project.getToolbarModel().toolbarState.collect { state -> - withoutSelectionChangedListener { - loadingDatabases = state.databasesLoadingForSelectedDataSource - if (isFirstInit || state.databases != databases) { - isFirstInit = false - populateComboBoxWithDatabases(state.databases) - } - selectDatabaseAndNotify(state.selectedDatabase) + SwingUtilities.invokeLater { + updateComboBoxState(state, isFirstInit) + isFirstInit = false } } } @@ -99,11 +97,27 @@ class DatabaseComboBox( } } - private fun populateComboBoxWithDatabases(databases: List) { - comboBoxModel.removeAllElements() - // First item is purposely a null to render "Detach data source label" - comboBoxModel.addElement(null) - comboBoxModel.addAll(databases) + private fun updateComboBoxState(state: ToolbarState, isFirstInit: Boolean) = withoutSelectionChangedListener { + loadingDatabases = state.databasesLoadingForSelectedDataSource + if (isFirstInit || state.databases != databases) { + populateComboBoxWithDatabases(state.databases.toSet()) + } + selectDatabaseAndNotify(state.selectedDatabase) + } + + private fun populateComboBoxWithDatabases(newDatabases: Set) { + val oldDatabases = databases.toSet() + + val databasesToAdd = newDatabases - oldDatabases + val databasesToRemove = oldDatabases - newDatabases + + databasesToAdd.forEach { comboBoxModel.addElement(it) } + databasesToRemove.forEach { comboBoxModel.removeElement(it) } + + if (comboBoxModel.getIndexOf(null) != 0) { + comboBoxModel.removeElement(null) + comboBoxModel.insertElementAt(null, 0) + } } private fun selectDatabaseAndNotify(database: String?) { From d57b5beba9a1051d5fa62932f786e14d5c0a096b Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 11:28:58 +0200 Subject: [PATCH 13/41] chore: add step logging for more debug info --- .../JavaDriverToolbarVisibilityUiTest.kt | 6 +- .../components/MdbActionGutterFixture.kt | 39 +++-- .../components/MdbJavaEditorToolbarFixture.kt | 25 ++- .../MdbJavaEditorToolbarPopupFixture.kt | 25 ++- .../fixtures/components/idea/IdeaFrame.kt | 155 +++++++++--------- 5 files changed, 139 insertions(+), 111 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index 0cb366c4d..5b11b9c23 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -136,8 +136,8 @@ class JavaDriverToolbarVisibilityUiTest { val textBeforeChanges = editor.text editor.insertTextAtLine(1, 0, "import com.mongodb.client.MongoClient;") - - remoteRobot.findJavaEditorToolbar() - editor.text = textBeforeChanges.replace("\n", "\\\n") + assertTrue(remoteRobot.findJavaEditorToolbar().isShowing) + editor.replaceText("import com.mongodb.client.MongoClient;", "") + assertTrue(remoteRobot.isJavaEditorToolbarHidden()) } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt index 3d0fe5fb4..a6069d48f 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbActionGutterFixture.kt @@ -6,6 +6,7 @@ package com.mongodb.jbplugin.fixtures.components import com.intellij.remoterobot.RemoteRobot import com.intellij.remoterobot.fixtures.GutterIcon +import com.intellij.remoterobot.stepsProcessing.step import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame import com.mongodb.jbplugin.fixtures.eventually import kotlin.time.Duration.Companion.seconds @@ -19,25 +20,29 @@ import kotlin.time.toJavaDuration * @return the specific gutter than can be clicked */ fun RemoteRobot.findRunQueryGutter(atLine: Int? = null) = eventually { - ideaFrame().currentTab() - .gutter.run { - atLine?.let { - // for some reason, gutter icons lines are always 2 minus the line in the editor :shrug: - // hide this somehow in this implementation - getIcons().find { - it.lineNumber == atLine - 2 && - it.description.contains("path=/icons/ConsoleRun") - } - } ?: getIcons().find { it.description.contains("path=/icons/ConsoleRun") } - }!! + step("Finding run query gutter, atLine=$atLine") { + ideaFrame().currentTab() + .gutter.run { + atLine?.let { + // for some reason, gutter icons lines are always 2 minus the line in the editor :shrug: + // hide this somehow in this implementation + getIcons().find { + it.lineNumber == atLine - 2 && + it.description.contains("path=/icons/ConsoleRun") + } + } ?: getIcons().find { it.description.contains("path=/icons/ConsoleRun") } + }!! + } } fun RemoteRobot.openRunQueryPopup(atLine: Int? = null): MdbJavaEditorToolbarPopupFixture { // We always deselect the current data source because otherwise clicking on gutter icon will - // do the action instead itself of opening the popup - findJavaEditorToolbar().selectDetachDataSource() - return eventually(10.seconds.toJavaDuration()) { - findRunQueryGutter(atLine)!!.click() - return@eventually findJavaEditorToolbarPopup() - }!! + // do the action itself instead of opening the popup + return step("Opening run query popup, atLine=$atLine") { + findJavaEditorToolbar().selectDetachDataSource() + return@step eventually(10.seconds.toJavaDuration()) { + findRunQueryGutter(atLine)!!.click() + return@eventually findJavaEditorToolbarPopup() + }!! + } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt index 75af3c93c..df2e7b747 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt @@ -7,6 +7,7 @@ import com.intellij.remoterobot.fixtures.ContainerFixture import com.intellij.remoterobot.fixtures.DefaultXpath import com.intellij.remoterobot.fixtures.FixtureName import com.intellij.remoterobot.search.locators.byXpath +import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible @@ -47,27 +48,33 @@ class MdbJavaEditorToolbarFixture( fun selectDataSource(title: String) { eventually(1.minutes.toJavaDuration()) { - dataSources.selectItemContains(title) - if (!dataSources.selectedText().contains(title)) { - throw Exception("Could not select data source - $title") + step("Selecting DataSource $title in toolbar") { + dataSources.selectItemContains(title) + if (!dataSources.selectedText().contains(title)) { + throw Exception("Could not select data source - $title") + } } } } fun selectDetachDataSource() { eventually(1.minutes.toJavaDuration()) { - dataSources.selectItem("Detach data source") - if (dataSources.selectedText() != "") { - throw Exception("Could not detach data source") + step("Detaching DataSource from toolbar") { + dataSources.selectItem("Detach data source") + if (dataSources.selectedText() != "") { + throw Exception("Could not detach data source") + } } } } fun selectDatabase(title: String) { eventually(1.minutes.toJavaDuration()) { - databases.selectItemContains(title) - if (!databases.selectedText().contains(title)) { - throw Exception("Could not select database - $title") + step("Selecting Database $title in toolbar") { + databases.selectItemContains(title) + if (!databases.selectedText().contains(title)) { + throw Exception("Could not select database - $title") + } } } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt index c1b0dcf27..70b29c0ec 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt @@ -4,6 +4,7 @@ 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.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible @@ -57,27 +58,33 @@ class MdbJavaEditorToolbarPopupFixture( fun selectDataSource(title: String) { eventually(1.minutes.toJavaDuration()) { - dataSources.selectItemContains(title) - if (!dataSources.selectedText().contains(title)) { - throw Exception("Could not select data source - $title") + step("Selecting DataSource $title in popup") { + dataSources.selectItemContains(title) + if (!dataSources.selectedText().contains(title)) { + throw Exception("Could not select data source - $title") + } } } } fun selectDetachDataSource() { eventually(1.minutes.toJavaDuration()) { - dataSources.selectItem("Detach data source") - if (dataSources.selectedText() != "") { - throw Exception("Could not detach data source") + step("Detaching DataSource from popup") { + dataSources.selectItem("Detach data source") + if (dataSources.selectedText() != "") { + throw Exception("Could not detach data source") + } } } } fun selectDatabase(title: String) { eventually(1.minutes.toJavaDuration()) { - databases.selectItemContains(title) - if (!databases.selectedText().contains(title)) { - throw Exception("Could not select database - $title") + step("Selecting Database $title in popup") { + databases.selectItemContains(title) + if (!databases.selectedText().contains(title)) { + throw Exception("Could not select database - $title") + } } } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index 6e2f4357f..786c69833 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -36,14 +36,15 @@ class IdeaFrame( remoteComponent: RemoteComponent, ) : CommonContainerFixture(remoteRobot, remoteComponent) { fun openFile(path: String, closeOpenedFiles: Boolean = true) { - if (closeOpenedFiles) { - this.closeAllFiles() - } + step("Opening file at path $path with closeOpenedFiles=$closeOpenedFiles") { + if (closeOpenedFiles) { + this.closeAllFiles() + } - val escapedPath = Encode.forJavaScript(path) + val escapedPath = Encode.forJavaScript(path) - runJs( - """ + runJs( + """ importPackage(com.intellij.openapi.fileEditor) importPackage(com.intellij.openapi.vfs) importPackage(com.intellij.openapi.wm.impl) @@ -69,8 +70,9 @@ class IdeaFrame( ApplicationManager.getApplication().invokeAndWait(openFileFunction) } """, - true, - ) + true, + ) + } CommonSteps(remoteRobot).wait(1) } @@ -83,64 +85,67 @@ class IdeaFrame( name: String, url: MongoDbServerUrl, ) { - runJs( - """ - const LocalDataSourceManager = global.get('loadDataGripPluginClass')( - 'com.intellij.database.dataSource.LocalDataSourceManager' - ) - - const DatabaseDriverManager = global.get('loadDataGripPluginClass')( - 'com.intellij.database.dataSource.DatabaseDriverManager' - ) - - const LocalDataSource = global.get('loadDataGripPluginClass')( - 'com.intellij.database.dataSource.LocalDataSource' - ) - - const DatabaseDriverValidator = global.get('loadDataGripPluginClass')( - 'com.intellij.database.dataSource.validation.DatabaseDriverValidator' - ) - - const DatabaseConfigEditor = global.get('loadDataGripPluginClass')( - 'com.intellij.database.view.ui.DatabaseConfigEditor' + step("Adding DataSource with name=$name, url=$url") { + runJs( + """ + const LocalDataSourceManager = global.get('loadDataGripPluginClass')( + 'com.intellij.database.dataSource.LocalDataSourceManager' + ) + + const DatabaseDriverManager = global.get('loadDataGripPluginClass')( + 'com.intellij.database.dataSource.DatabaseDriverManager' + ) + + const LocalDataSource = global.get('loadDataGripPluginClass')( + 'com.intellij.database.dataSource.LocalDataSource' + ) + + const DatabaseDriverValidator = global.get('loadDataGripPluginClass')( + 'com.intellij.database.dataSource.validation.DatabaseDriverValidator' + ) + + const DatabaseConfigEditor = global.get('loadDataGripPluginClass')( + 'com.intellij.database.view.ui.DatabaseConfigEditor' + ) + + importClass(com.intellij.openapi.project.Project) + importPackage(com.intellij.openapi.progress) + importPackage(com.intellij.openapi.wm.impl) + importPackage(com.intellij.database.view.ui) + + const frameHelper = ProjectFrameHelper.getFrameHelper(component) + if (frameHelper) { + const project = frameHelper.getProject() + + const dataSourceManager = LocalDataSourceManager.getMethod("getInstance", Project).invoke(null, project) + const driverManager = DatabaseDriverManager.getMethod("getInstance").invoke(null) + const jdbcDriver = driverManager.getDriver("mongo") + + const dataSource = LocalDataSource.newInstance() + dataSource.setName("$name") + dataSource.setUrl("${url.value}") + dataSource.setConfiguredByUrl(true) + dataSource.setDatabaseDriver(jdbcDriver) + dataSourceManager.addDataSource(dataSource) + + global.put("dataSource", dataSource); + DatabaseDriverValidator.getMethod("createDownloaderTask", LocalDataSource, DatabaseConfigEditor) + .invoke(null, dataSource, null) + .run(new EmptyProgressIndicator()) + } + """.trimIndent(), + runInEdt = true, ) - - importClass(com.intellij.openapi.project.Project) - importPackage(com.intellij.openapi.progress) - importPackage(com.intellij.openapi.wm.impl) - importPackage(com.intellij.database.view.ui) - - const frameHelper = ProjectFrameHelper.getFrameHelper(component) - if (frameHelper) { - const project = frameHelper.getProject() - - const dataSourceManager = LocalDataSourceManager.getMethod("getInstance", Project).invoke(null, project) - const driverManager = DatabaseDriverManager.getMethod("getInstance").invoke(null) - const jdbcDriver = driverManager.getDriver("mongo") - - const dataSource = LocalDataSource.newInstance() - dataSource.setName("$name") - dataSource.setUrl("${url.value}") - dataSource.setConfiguredByUrl(true) - dataSource.setDatabaseDriver(jdbcDriver) - dataSourceManager.addDataSource(dataSource) - - global.put("dataSource", dataSource); - DatabaseDriverValidator.getMethod("createDownloaderTask", LocalDataSource, DatabaseConfigEditor) - .invoke(null, dataSource, null) - .run(new EmptyProgressIndicator()) - } - """.trimIndent(), - runInEdt = true, - ) + } CommonSteps(remoteRobot).wait(1) } fun waitUntilConnectedToMongoDb(name: String, timeout: Duration = Duration.ofMinutes(1)) { eventually(timeout) { - assertTrue( - callJs( - """ + step("Waiting for DataSource $name to connect, timeout=$timeout") { + assertTrue( + callJs( + """ importClass(java.lang.System) const DatabaseConnectionManager = global.get('loadDataGripPluginClass')( @@ -167,12 +172,12 @@ class IdeaFrame( } connected - """.trimIndent(), - runInEdt = true + """.trimIndent(), + runInEdt = true + ) ) - ) + } } - CommonSteps(remoteRobot).wait(1) } @@ -243,8 +248,9 @@ class IdeaFrame( } fun cleanDataSources() { - runJs( - """ + step("Cleaning DataSources") { + runJs( + """ const LocalDataSourceManager = global.get('loadDataGripPluginClass')( 'com.intellij.database.dataSource.LocalDataSourceManager' ) @@ -264,15 +270,17 @@ class IdeaFrame( for (let i = 0; i < dataSources.size(); i++) { dataSourceManager.removeDataSource(dataSources.get(i)); } - """.trimIndent(), - runInEdt = true, - ) + """.trimIndent(), + runInEdt = true, + ) + } CommonSteps(remoteRobot).wait(1) } fun closeAllFiles() { - runJs( - """ + step("Closing all files") { + runJs( + """ importPackage(com.intellij.openapi.fileEditor) importPackage(com.intellij.openapi.vfs) importPackage(com.intellij.openapi.wm.impl) @@ -292,8 +300,9 @@ class IdeaFrame( ApplicationManager.getApplication().invokeLater(closeEditorsFunction) } """, - true, - ) + true, + ) + } CommonSteps(remoteRobot).wait(1) } From 1b3fe216e5b54ec596133a11cb39d5ca73b98e6c Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 11:38:11 +0200 Subject: [PATCH 14/41] chore: revert quality-check.yaml changes --- .github/workflows/quality-check.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/quality-check.yaml b/.github/workflows/quality-check.yaml index 17fe7fc70..8f1686534 100644 --- a/.github/workflows/quality-check.yaml +++ b/.github/workflows/quality-check.yaml @@ -3,7 +3,6 @@ on: push: branches: - main - - chore/INTELLIJ-107 pull_request: branches: - main From 3e46a705e5f905ea8a0b31405eacfed28096ea3b Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 13:00:05 +0200 Subject: [PATCH 15/41] chore: remove test deps from fixture project --- .../basic-java-project-with-mongodb/build.gradle.kts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/build.gradle.kts b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/build.gradle.kts index 24571547b..6affc544a 100644 --- a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/build.gradle.kts +++ b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/build.gradle.kts @@ -10,13 +10,10 @@ repositories { } dependencies { - implementation("org.mongodb:mongodb-driver-sync:5.1.1") + implementation("org.mongodb:mongodb-driver-sync:5.1.3") implementation("org.springframework.data:spring-data-mongodb:4.3.2") - - testImplementation(platform("org.junit:junit-bom:5.9.1")) - testImplementation("org.junit.jupiter:junit-jupiter") } tasks.test { useJUnitPlatform() -} \ No newline at end of file +} From 7b62fb4518ca9d17b69287fb4812a23afb7dd2aa Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 13:14:44 +0200 Subject: [PATCH 16/41] chore: version ref via versions toml --- .../jbplugin/fixtures/MdbStepLogger.kt | 39 +++++++++++++++++++ .../build.gradle.kts | 4 +- .../settings.gradle.kts | 7 ++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt new file mode 100644 index 000000000..910dddc0c --- /dev/null +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt @@ -0,0 +1,39 @@ +package com.mongodb.jbplugin.fixtures + +import com.intellij.remoterobot.stepsProcessing.StepProcessor +import com.intellij.remoterobot.stepsProcessing.log +import com.intellij.remoterobot.utils.Color +import com.intellij.remoterobot.utils.color + +class MdbStepLogger(private val indentVal: String = " ") : StepProcessor { + private var indent = ThreadLocal.withInitial { 0 } + + private fun indents() = buildString { + repeat(indent.get()) { append(indentVal) } + } + + override fun doBeforeStep(stepTitle: String) { + log.info(indents() + stepTitle) + indent.set(indent.get().plus(1)) + } + + override fun doOnSuccess(stepTitle: String) { + } + + override fun doOnFail(stepTitle: String, e: Throwable) { + log.warn( + "${indents()}Failed on step: $stepTitle (${getClassFileNameAndMethod()})".color( + Color.RED + ) + ) + } + + override fun doAfterStep(stepTitle: String) { + indent.set(indent.get().minus(1)) + } + + private fun getClassFileNameAndMethod(): String { + return Thread.currentThread().stackTrace[3]?.let { "${it.fileName}_${it.methodName}" } + ?: "---" + } +} diff --git a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/build.gradle.kts b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/build.gradle.kts index 6affc544a..3f086da0c 100644 --- a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/build.gradle.kts +++ b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/build.gradle.kts @@ -10,8 +10,8 @@ repositories { } dependencies { - implementation("org.mongodb:mongodb-driver-sync:5.1.3") - implementation("org.springframework.data:spring-data-mongodb:4.3.2") + implementation(libs.mongodb.driver) + implementation(libs.testing.spring.mongodb) } tasks.test { diff --git a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/settings.gradle.kts b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/settings.gradle.kts index ddee68b1b..3111545f0 100644 --- a/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/settings.gradle.kts +++ b/packages/jetbrains-plugin/src/test/resources/project-fixtures/basic-java-project-with-mongodb/settings.gradle.kts @@ -1,2 +1,9 @@ rootProject.name = "basic-java-project-with-mongodb" +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../../../../../../../gradle/libs.versions.toml")) // full path to the versions toml + } + } +} From d3db96bf890bf0d13fe4d728a0e2c951bd2109f3 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 14:12:43 +0200 Subject: [PATCH 17/41] chore: added custom step logger to log exceptions as well --- .../jbplugin/fixtures/FixtureExtensions.kt | 29 ++++----------- .../jbplugin/fixtures/MdbStepLogger.kt | 5 +-- .../jbplugin/fixtures/UiTestExtensions.kt | 5 ++- .../fixtures/components/idea/IdeaFrame.kt | 36 +++++++++++-------- 4 files changed, 33 insertions(+), 42 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/FixtureExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/FixtureExtensions.kt index 836592fd7..984a5ed2b 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/FixtureExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/FixtureExtensions.kt @@ -7,16 +7,13 @@ package com.mongodb.jbplugin.fixtures import com.intellij.remoterobot.RemoteRobot import com.intellij.remoterobot.fixtures.Fixture -import com.intellij.remoterobot.fixtures.JButtonFixture import com.intellij.remoterobot.search.locators.Locator -import com.intellij.remoterobot.search.locators.byXpath +import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.components.idea.maybeIdeaFrame import org.owasp.encoder.Encode import java.time.Duration import java.util.concurrent.atomic.AtomicReference -import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.toJavaDuration /** * Returns a fixture by the default xpath of the fixture. @@ -81,7 +78,9 @@ inline fun RemoteRobot.findVisible( * * @param section */ -fun RemoteRobot.openSettingsAtSection(section: String) { +fun RemoteRobot.openSettingsAtSection( + section: String +) = step("Open settings modal and section $section") { this.runJs( """ importClass(com.intellij.openapi.application.ApplicationManager) @@ -103,7 +102,7 @@ fun RemoteRobot.openSettingsAtSection(section: String) { * * @param actionId */ -fun RemoteRobot.invokeAction(actionId: String) { +fun RemoteRobot.invokeAction(actionId: String) = step("Invoke action with id '$actionId'") { val encodedActionId = Encode.forJavaScript(actionId) runJs( @@ -135,7 +134,7 @@ fun RemoteRobot.invokeAction(actionId: String) { * * @param absolutePath */ -fun RemoteRobot.openProject(absolutePath: String) { +fun RemoteRobot.openProject(absolutePath: String) = step("Open Project at path $absolutePath") { val encodedPath = Encode.forJavaScript(absolutePath) runJs( @@ -162,26 +161,12 @@ fun RemoteRobot.openProject(absolutePath: String) { """, ) - maybeTerminateButton() maybeIdeaFrame()?.closeAllFiles() - maybeTerminateButton() } /** * Closes the project and waits until properly closed. */ -fun RemoteRobot.closeProject() { +fun RemoteRobot.closeProject() = step("Closing any open project") { invokeAction("CloseProject") - maybeTerminateButton() -} - -private fun RemoteRobot.maybeTerminateButton() { - runCatching { - val terminateButton = - find( - byXpath("//div[@text='Terminate']"), - timeout = 50.milliseconds.toJavaDuration(), - ) - terminateButton.click() - }.getOrDefault(Unit) } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt index 910dddc0c..4fd22e248 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt @@ -5,7 +5,7 @@ import com.intellij.remoterobot.stepsProcessing.log import com.intellij.remoterobot.utils.Color import com.intellij.remoterobot.utils.color -class MdbStepLogger(private val indentVal: String = " ") : StepProcessor { +class MdbStepLogger(private val indentVal: String = "------ ") : StepProcessor { private var indent = ThreadLocal.withInitial { 0 } private fun indents() = buildString { @@ -24,7 +24,8 @@ class MdbStepLogger(private val indentVal: String = " ") : StepProcessor { log.warn( "${indents()}Failed on step: $stepTitle (${getClassFileNameAndMethod()})".color( Color.RED - ) + ), + e ) } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt index 9711c8ea3..8522eab3f 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt @@ -10,7 +10,6 @@ import com.intellij.database.util.common.containsElements import com.intellij.remoterobot.RemoteRobot import com.intellij.remoterobot.fixtures.ContainerFixture import com.intellij.remoterobot.search.locators.byXpath -import com.intellij.remoterobot.stepsProcessing.StepLogger import com.intellij.remoterobot.stepsProcessing.StepWorker import com.intellij.remoterobot.utils.DefaultHttpClient.client import com.intellij.remoterobot.utils.keyboard @@ -71,8 +70,8 @@ private class UiTestExtension : ): Any = remoteRobot override fun beforeAll(context: ExtensionContext?) { - if (!StepWorker.processors.containsElements { it is StepLogger }) { - StepWorker.registerProcessor(StepLogger()) + if (!StepWorker.processors.containsElements { it is MdbStepLogger }) { + StepWorker.registerProcessor(MdbStepLogger()) } remoteRobot = RemoteRobot(remoteRobotUrl) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index 786c69833..a78d5f4a2 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -12,7 +12,6 @@ import com.intellij.remoterobot.fixtures.* import com.intellij.remoterobot.search.locators.byXpath import com.intellij.remoterobot.steps.CommonSteps import com.intellij.remoterobot.stepsProcessing.step -import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.MongoDbServerUrl import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible @@ -236,6 +235,13 @@ class IdeaFrame( fun hideIntellijAiAd() { step("Hide IntelliJ AI Ad (uses a lot of space in a small window)") { + tryHidingAiAdOnOldUI() + tryHidingAiAdOnNewUI() + } + } + + private fun tryHidingAiAdOnNewUI() { + step("Attempting to hide AI ad on new UI") { runCatching { val aiMenu = remoteRobot.find( byXpath("//div[@accessiblename='AI Assistant']") @@ -247,6 +253,20 @@ class IdeaFrame( } } + private fun tryHidingAiAdOnOldUI() { + step("Attempting to hide AI ad on old UI") { + runCatching { + val aiMenu = remoteRobot.find( + byXpath("//div[@tooltiptext='Install AI Assistant']") + ) + aiMenu.rightClick() + remoteRobot.find( + byXpath("//div[@text='Remove from Sidebar']") + ).click() + } + } + } + fun cleanDataSources() { step("Cleaning DataSources") { runJs( @@ -305,20 +325,6 @@ class IdeaFrame( } CommonSteps(remoteRobot).wait(1) } - - fun ensureNotificationIsVisible(title: String) { - remoteRobot.findVisible(byXpath("//div[@visible_text='$title']")) - } - - fun waitUntilNotificationIsGone(title: String, timeout: Duration = Duration.ofSeconds(2)) { - waitFor(timeout, interval = Duration.ofMillis(50)) { - runCatching { - !remoteRobot.find( - byXpath("//div[@visible_text='$title']") - ).isVisible() - }.getOrDefault(true) - } - } } /** From b4e9e5cd05e2281631a2d1324898e8bb0b146b7e Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 14:21:09 +0200 Subject: [PATCH 18/41] chore: ignore gradle sync exception logging --- .../jbplugin/fixtures/MdbStepLogger.kt | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt index 4fd22e248..908fc0171 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt @@ -6,6 +6,9 @@ import com.intellij.remoterobot.utils.Color import com.intellij.remoterobot.utils.color class MdbStepLogger(private val indentVal: String = "------ ") : StepProcessor { + private val ignorableStepTitlesForExceptionLogging = setOf( + "Wait until Gradle project is in sync", + ) private var indent = ThreadLocal.withInitial { 0 } private fun indents() = buildString { @@ -21,12 +24,20 @@ class MdbStepLogger(private val indentVal: String = "------ ") : StepProcessor { } override fun doOnFail(stepTitle: String, e: Throwable) { - log.warn( - "${indents()}Failed on step: $stepTitle (${getClassFileNameAndMethod()})".color( - Color.RED - ), - e - ) + if (ignorableStepTitlesForExceptionLogging.any { stepTitle.contains(it) }) { + log.warn( + "${indents()}Failed on step: $stepTitle (${getClassFileNameAndMethod()})".color( + Color.RED + ) + ) + } else { + log.warn( + "${indents()}Failed on step: $stepTitle (${getClassFileNameAndMethod()})".color( + Color.RED + ), + e + ) + } } override fun doAfterStep(stepTitle: String) { From 5ec05e407c0739724f8d152d8a0afe90c49f73e2 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 14:24:29 +0200 Subject: [PATCH 19/41] chore: also ignore Search 'Idea frame' --- .../test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt index 908fc0171..61fbc4057 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt @@ -8,6 +8,7 @@ import com.intellij.remoterobot.utils.color class MdbStepLogger(private val indentVal: String = "------ ") : StepProcessor { private val ignorableStepTitlesForExceptionLogging = setOf( "Wait until Gradle project is in sync", + "Search 'Idea frame'" ) private var indent = ThreadLocal.withInitial { 0 } From 12d1625bbc5e3360b2ab927c6eb3d95e3c290066 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 14:40:41 +0200 Subject: [PATCH 20/41] chore: also ignore Search 'AI' related exception --- .../test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt index 61fbc4057..ffaf45464 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt @@ -8,7 +8,8 @@ import com.intellij.remoterobot.utils.color class MdbStepLogger(private val indentVal: String = "------ ") : StepProcessor { private val ignorableStepTitlesForExceptionLogging = setOf( "Wait until Gradle project is in sync", - "Search 'Idea frame'" + "Search 'Idea frame'", + "AI Assistant" ) private var indent = ThreadLocal.withInitial { 0 } From c14e4524de30fe6915bba1f1d5b26b6d08d21534 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 15:46:52 +0200 Subject: [PATCH 21/41] chore: better ignore --- .../kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt | 6 ++++-- .../mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt index ffaf45464..b343d6870 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt @@ -8,8 +8,10 @@ import com.intellij.remoterobot.utils.color class MdbStepLogger(private val indentVal: String = "------ ") : StepProcessor { private val ignorableStepTitlesForExceptionLogging = setOf( "Wait until Gradle project is in sync", - "Search 'Idea frame'", - "AI Assistant" + "AI Assistant", + // combobox steps that won't need exception logging + "Select ", + "Search ", ) private var indent = ThreadLocal.withInitial { 0 } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index a78d5f4a2..ee6200882 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -247,8 +247,9 @@ class IdeaFrame( byXpath("//div[@accessiblename='AI Assistant']") ) aiMenu.rightClick() - val hideAiMenu = remoteRobot.find(byXpath("//div[@class='MyList']")) - hideAiMenu.clickItem("Hide") + remoteRobot.find( + byXpath("//div[@text='Hide']") + ).click() } } } From 1d2f60da6c2b2526d8b00fcaf815427146a9ceeb Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 18 Oct 2024 16:51:30 +0200 Subject: [PATCH 22/41] chore: a few more ignores --- .../test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt | 2 ++ packages/jetbrains-plugin/src/test/resources/video.properties | 1 + 2 files changed, 3 insertions(+) create mode 100644 packages/jetbrains-plugin/src/test/resources/video.properties diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt index b343d6870..ea7cecf79 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/MdbStepLogger.kt @@ -12,6 +12,8 @@ class MdbStepLogger(private val indentVal: String = "------ ") : StepProcessor { // combobox steps that won't need exception logging "Select ", "Search ", + "Selecting Database", + "Selecting DataSource", ) private var indent = ThreadLocal.withInitial { 0 } diff --git a/packages/jetbrains-plugin/src/test/resources/video.properties b/packages/jetbrains-plugin/src/test/resources/video.properties new file mode 100644 index 000000000..f03fd1541 --- /dev/null +++ b/packages/jetbrains-plugin/src/test/resources/video.properties @@ -0,0 +1 @@ +video.save.mode=ALL From fd54190c12bd0d9202f0f0ee88d909244f409a63 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 14:37:57 +0200 Subject: [PATCH 23/41] chore: adds way for manual gradle reload --- .../fixtures/InfoAndProgressPanelFixture.kt | 44 ++++++++ .../fixtures/RightToolWindowHeaderFixture.kt | 54 ++++++++++ .../jbplugin/fixtures/UiTestExtensions.kt | 7 +- .../components/GradleToolWindowFixture.kt | 100 ++++++++++++++++++ .../components/RightToolbarFixture.kt | 33 ++++++ 5 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt create mode 100644 packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt create mode 100644 packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt create mode 100644 packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt new file mode 100644 index 000000000..8182a633c --- /dev/null +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt @@ -0,0 +1,44 @@ +package com.mongodb.jbplugin.fixtures + +import com.intellij.remoterobot.RemoteRobot +import com.intellij.remoterobot.data.RemoteComponent +import com.intellij.remoterobot.fixtures.ContainerFixture +import com.intellij.remoterobot.fixtures.DefaultXpath +import com.intellij.remoterobot.fixtures.FixtureName +import com.intellij.remoterobot.search.locators.byXpath +import com.intellij.remoterobot.utils.waitFor +import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame +import java.time.Duration + +@DefaultXpath(by = "class", xpath = "//div[@class='InfoAndProgressPanelImpl']") +@FixtureName("Status bar") +class InfoAndProgressPanelFixture( + remoteRobot: RemoteRobot, + remoteComponent: RemoteComponent, +) : ContainerFixture(remoteRobot, remoteComponent) { + private val inlineProgressPanel by lazy { + find(byXpath("//div[@class='InlineProgressPanel']")) + } + + private fun isInlineProgressPanelEmpty(): Boolean { + return inlineProgressPanel.callJs( + """ + const children = component.getComponents(); + children.length === 0 || children.every(child => !child.isVisible()); + """.trimIndent(), + runInEdt = true + ) + } + + fun waitForInProgressTasksToFinish(timeout: Duration = Duration.ofMinutes(2)) { + waitFor( + duration = timeout, + description = "In-Progress tasks to finish", + errorMessage = "In-Progress tasks did not finish" + ) { + isInlineProgressPanelEmpty() + } + } +} + +fun IdeaFrame.infoAndProgressPanel(): InfoAndProgressPanelFixture = find() diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt new file mode 100644 index 000000000..7b9969e6b --- /dev/null +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt @@ -0,0 +1,54 @@ +package com.mongodb.jbplugin.fixtures + +import com.intellij.remoterobot.RemoteRobot +import com.intellij.remoterobot.data.RemoteComponent +import com.intellij.remoterobot.fixtures.ContainerFixture +import com.intellij.remoterobot.fixtures.DefaultXpath +import com.intellij.remoterobot.fixtures.FixtureName +import com.intellij.remoterobot.fixtures.JButtonFixture +import com.intellij.remoterobot.search.locators.byXpath +import com.intellij.remoterobot.stepsProcessing.step +import com.intellij.remoterobot.utils.waitFor +import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame +import java.time.Duration + +@DefaultXpath(by = "class", xpath = "//div[@class='ToolWindowHeader'][.//div[@class='BaseLabel']]") +@FixtureName("Right Tool Window Header") +class RightToolWindowHeaderFixture( + remoteRobot: RemoteRobot, + remoteComponent: RemoteComponent, +) : ContainerFixture(remoteRobot, remoteComponent) { + private val headerActionsContainer by lazy { + find( + byXpath("//div[@classhierarchy='javax.swing.JPanel -> javax.swing.JComponent']") + ) + } + + val hideButton by lazy { + step("Retrieving hide button from right tool window header") { + headerActionsContainer.moveMouse() + headerActionsContainer.find( + byXpath("//div[@tooltiptext='Hide']") + ) + } + } +} + +fun IdeaFrame.rightToolWindowHeader(): RightToolWindowHeaderFixture = find() + +fun IdeaFrame.maybeRightToolWindowHeader(): RightToolWindowHeaderFixture? = runCatching { + rightToolWindowHeader() +}.getOrNull() + +fun IdeaFrame.closeRightToolWindow() { + step("Closing right tool window") { + waitFor( + duration = Duration.ofMinutes(1), + description = "Right tool window to close", + errorMessage = "Right tool window did not close", + ) { + maybeRightToolWindowHeader()?.hideButton?.click() + maybeRightToolWindowHeader()?.isShowing != true + } + } +} diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt index 8522eab3f..51b5ca75f 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt @@ -14,6 +14,7 @@ import com.intellij.remoterobot.stepsProcessing.StepWorker import com.intellij.remoterobot.utils.DefaultHttpClient.client import com.intellij.remoterobot.utils.keyboard import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame +import com.mongodb.jbplugin.fixtures.components.openGradleToolWindow import okhttp3.Request import org.junit.jupiter.api.Tag import org.junit.jupiter.api.extension.* @@ -133,10 +134,12 @@ private class UiTestExtension : if (it.smartMode) { remoteRobot.ideaFrame().disablePowerSaveMode() - remoteRobot.ideaFrame().waitUntilProjectIsInSync() + val gradleToolWindow = remoteRobot.ideaFrame().openGradleToolWindow() + gradleToolWindow.ensureGradleProjectsAreSynced() } - remoteRobot.ideaFrame().hideIntellijAiAd() + // Close any right tool window + remoteRobot.ideaFrame().closeRightToolWindow() } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt new file mode 100644 index 000000000..d2d5df70a --- /dev/null +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt @@ -0,0 +1,100 @@ +package com.mongodb.jbplugin.fixtures.components + +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.stepsProcessing.step +import com.intellij.remoterobot.utils.waitFor +import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame +import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame +import com.mongodb.jbplugin.fixtures.infoAndProgressPanel +import java.time.Duration + +@DefaultXpath( + by = "class", + xpath = "//div[@class='InternalDecoratorImpl' and @accessiblename='Gradle Tool Window']" +) +@FixtureName("Gradle Tool Window") +class GradleToolWindowFixture( + remoteRobot: RemoteRobot, + remoteComponent: RemoteComponent, +) : ContainerFixture(remoteRobot, remoteComponent) { + val actionToolbar by lazy { + find( + byXpath("//div[contains(@myvisibleactions, 'To') or contains(@myvisibleactions, 'of')]") + ) + } + + val reloadGradleButton by lazy { + step("Retrieving an enabled reload gradle button") { + val button = actionToolbar.find(byXpath("//div[@myicon='refresh.svg']")) + waitFor( + duration = Duration.ofMinutes(1), + description = "Reload gradle button to be enabled", + errorMessage = "Reload gradle button was still disabled" + ) { + button.isEnabled() + } + button + } + } + + val projectTree by lazy { + find(byXpath("//div[@class='ExternalProjectTree']")) + } + + fun ensureGradleProjectsAreSynced() { + step("Ensuring gradle projects are synced") { + val projectsDidNotShowUp = runCatching { + waitFor( + duration = Duration.ofSeconds(30), + description = "Gradle projects to show up", + errorMessage = "Gradle projects did not show up", + ) { + !projectTree.hasText("Nothing to show") + } + }.isFailure + + if (projectsDidNotShowUp) { + step("Manually reload gradle projects") { + reloadGradleButton.click() + waitFor( + duration = Duration.ofSeconds(30), + description = "Gradle projects to show up after manual reload", + errorMessage = "Gradle projects to show up after manual reload", + ) { + !projectTree.hasText("Nothing to show") + } + } + } + + remoteRobot.ideaFrame().infoAndProgressPanel().waitForInProgressTasksToFinish() + } + } +} + +fun IdeaFrame.gradleToolWindow(): GradleToolWindowFixture = find() + +fun IdeaFrame.maybeGradleToolWindow(): GradleToolWindowFixture? = runCatching { + gradleToolWindow() +}.getOrNull() + +fun IdeaFrame.openGradleToolWindow(): GradleToolWindowFixture { + return step("Open gradle tool window") { + waitFor( + duration = Duration.ofMinutes(1), + description = "Gradle tool window to open", + errorMessage = "Gradle tool window did not open" + ) { + maybeGradleToolWindow()?.let { + isShowing + } ?: run { + rightToolbar().gradleButton.click() + maybeGradleToolWindow()?.isShowing == true + } + } + + return@step gradleToolWindow() + } +} diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt new file mode 100644 index 000000000..601b9db2d --- /dev/null +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt @@ -0,0 +1,33 @@ +package com.mongodb.jbplugin.fixtures.components + +import com.intellij.remoterobot.RemoteRobot +import com.intellij.remoterobot.data.RemoteComponent +import com.intellij.remoterobot.fixtures.ContainerFixture +import com.intellij.remoterobot.fixtures.DefaultXpath +import com.intellij.remoterobot.fixtures.FixtureName +import com.intellij.remoterobot.fixtures.JButtonFixture +import com.intellij.remoterobot.search.locators.byXpath +import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame +import java.time.Duration + +@DefaultXpath( + by = "class", + xpath = "//div[@class='ToolWindowRightToolbar' or @accessiblename='Right Stripe']" +) +@FixtureName("RightToolbar") +class RightToolbarFixture( + remoteRobot: RemoteRobot, + remoteComponent: RemoteComponent +) : ContainerFixture(remoteRobot, remoteComponent) { + val aiAssistantButton by lazy { + find(byXpath("//div[@tooltiptext='AI Assistant' or @text='AI Assistant']")) + } + + val gradleButton by lazy { + find(byXpath("//div[@tooltiptext='Gradle' or @text='Gradle']")) + } +} + +fun IdeaFrame.rightToolbar(): RightToolbarFixture = find( + Duration.ofSeconds(30) +) From b2497645796cffa7b224df991ad8b31310082012 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 15:00:06 +0200 Subject: [PATCH 24/41] chore: wait a little more for gradle projects to show up --- .../jbplugin/fixtures/components/GradleToolWindowFixture.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt index d2d5df70a..06ff6f278 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt @@ -48,7 +48,7 @@ class GradleToolWindowFixture( step("Ensuring gradle projects are synced") { val projectsDidNotShowUp = runCatching { waitFor( - duration = Duration.ofSeconds(30), + duration = Duration.ofMinutes(2), description = "Gradle projects to show up", errorMessage = "Gradle projects did not show up", ) { @@ -60,7 +60,7 @@ class GradleToolWindowFixture( step("Manually reload gradle projects") { reloadGradleButton.click() waitFor( - duration = Duration.ofSeconds(30), + duration = Duration.ofMinutes(2), description = "Gradle projects to show up after manual reload", errorMessage = "Gradle projects to show up after manual reload", ) { From d1b0893b5adc03c9f9d6a6596321241a60ca3f27 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 15:48:33 +0200 Subject: [PATCH 25/41] chore: minor adjustments --- .../fixtures/InfoAndProgressPanelFixture.kt | 15 +++++++++------ .../fixtures/RightToolWindowHeaderFixture.kt | 2 +- .../mongodb/jbplugin/fixtures/UiTestExtensions.kt | 7 ++++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt index 8182a633c..b2f87012b 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt @@ -6,6 +6,7 @@ import com.intellij.remoterobot.fixtures.ContainerFixture import com.intellij.remoterobot.fixtures.DefaultXpath import com.intellij.remoterobot.fixtures.FixtureName import com.intellij.remoterobot.search.locators.byXpath +import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame import java.time.Duration @@ -31,12 +32,14 @@ class InfoAndProgressPanelFixture( } fun waitForInProgressTasksToFinish(timeout: Duration = Duration.ofMinutes(2)) { - waitFor( - duration = timeout, - description = "In-Progress tasks to finish", - errorMessage = "In-Progress tasks did not finish" - ) { - isInlineProgressPanelEmpty() + step("Ensure in-progress tasks are finished") { + waitFor( + duration = timeout, + description = "In-Progress tasks to finish", + errorMessage = "In-Progress tasks did not finish" + ) { + isInlineProgressPanelEmpty() + } } } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt index 7b9969e6b..77fe8a51b 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt @@ -34,7 +34,7 @@ class RightToolWindowHeaderFixture( } } -fun IdeaFrame.rightToolWindowHeader(): RightToolWindowHeaderFixture = find() +fun IdeaFrame.rightToolWindowHeader(): RightToolWindowHeaderFixture = remoteRobot.findVisible() fun IdeaFrame.maybeRightToolWindowHeader(): RightToolWindowHeaderFixture? = runCatching { rightToolWindowHeader() diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt index 51b5ca75f..17ebe55b3 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt @@ -115,9 +115,12 @@ private class UiTestExtension : } override fun beforeEach(context: ExtensionContext?) { + val testMethod = + context?.requiredTestMethod ?: throw IllegalStateException("test method is null") + val testMethodName = testMethod.name val requiresProject = context - ?.requiredTestMethod + .requiredTestMethod ?.annotations ?.find { annotation -> annotation.annotationClass == RequiresProject::class @@ -136,10 +139,12 @@ private class UiTestExtension : remoteRobot.ideaFrame().disablePowerSaveMode() val gradleToolWindow = remoteRobot.ideaFrame().openGradleToolWindow() gradleToolWindow.ensureGradleProjectsAreSynced() + saveScreenshot("$testMethodName-after-gradle-sync") } // Close any right tool window remoteRobot.ideaFrame().closeRightToolWindow() + saveScreenshot("$testMethodName-after-closing-right-tool-window") } } From 2c413a520c2635da151a6d66d68d8ea64a0be267 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 15:57:00 +0200 Subject: [PATCH 26/41] chore: use invokeAction for gradle sync --- .../fixtures/RightToolWindowHeaderFixture.kt | 2 +- .../components/GradleToolWindowFixture.kt | 25 ++----------------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt index 77fe8a51b..519051095 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt @@ -34,7 +34,7 @@ class RightToolWindowHeaderFixture( } } -fun IdeaFrame.rightToolWindowHeader(): RightToolWindowHeaderFixture = remoteRobot.findVisible() +fun IdeaFrame.rightToolWindowHeader(): RightToolWindowHeaderFixture = remoteRobot.find() fun IdeaFrame.maybeRightToolWindowHeader(): RightToolWindowHeaderFixture? = runCatching { rightToolWindowHeader() diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt index 06ff6f278..66d57e528 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt @@ -9,6 +9,7 @@ import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame import com.mongodb.jbplugin.fixtures.infoAndProgressPanel +import com.mongodb.jbplugin.fixtures.invokeAction import java.time.Duration @DefaultXpath( @@ -46,29 +47,7 @@ class GradleToolWindowFixture( fun ensureGradleProjectsAreSynced() { step("Ensuring gradle projects are synced") { - val projectsDidNotShowUp = runCatching { - waitFor( - duration = Duration.ofMinutes(2), - description = "Gradle projects to show up", - errorMessage = "Gradle projects did not show up", - ) { - !projectTree.hasText("Nothing to show") - } - }.isFailure - - if (projectsDidNotShowUp) { - step("Manually reload gradle projects") { - reloadGradleButton.click() - waitFor( - duration = Duration.ofMinutes(2), - description = "Gradle projects to show up after manual reload", - errorMessage = "Gradle projects to show up after manual reload", - ) { - !projectTree.hasText("Nothing to show") - } - } - } - + remoteRobot.invokeAction("ExternalSystem.RefreshAllProjects") remoteRobot.ideaFrame().infoAndProgressPanel().waitForInProgressTasksToFinish() } } From a80096ac5633992fe64403bfeae3ac86ff670066 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 17:47:30 +0200 Subject: [PATCH 27/41] chore: wait for smartmode: --- .../components/GradleToolWindowFixture.kt | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt index 66d57e528..4e2c5e55c 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt @@ -4,12 +4,12 @@ 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.steps.CommonSteps import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame import com.mongodb.jbplugin.fixtures.infoAndProgressPanel -import com.mongodb.jbplugin.fixtures.invokeAction import java.time.Duration @DefaultXpath( @@ -47,7 +47,32 @@ class GradleToolWindowFixture( fun ensureGradleProjectsAreSynced() { step("Ensuring gradle projects are synced") { - remoteRobot.invokeAction("ExternalSystem.RefreshAllProjects") + runCatching { + waitFor( + duration = Duration.ofMinutes(2), + description = "Gradle projects to show up", + errorMessage = "Gradle projects did not show up", + ) { + !projectTree.hasText("Nothing to show") + } + }.isFailure + + runCatching { + CommonSteps(remoteRobot).waitForSmartMode(2) + } + + step("Manually reload gradle projects") { + reloadGradleButton.click() + // remoteRobot.invokeAction("ExternalSystem.RefreshAllProjects") + waitFor( + duration = Duration.ofMinutes(2), + description = "Gradle projects to show up after manual reload", + errorMessage = "Gradle projects to show up after manual reload", + ) { + !projectTree.hasText("Nothing to show") + } + } + remoteRobot.ideaFrame().infoAndProgressPanel().waitForInProgressTasksToFinish() } } From 8f5e22b14032a40651a6afc3566fc8b941e99d2c Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 20:26:23 +0200 Subject: [PATCH 28/41] chore: ensure screenshots are attached in reports --- .github/workflows/quality-check.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/quality-check.yaml b/.github/workflows/quality-check.yaml index 8f1686534..b89906e3d 100644 --- a/.github/workflows/quality-check.yaml +++ b/.github/workflows/quality-check.yaml @@ -213,7 +213,7 @@ jobs: path: | **/build/reports/**/*.html **/build/reports/**/*.log - **/build/reports/*/*.png + **/build/reports/**/*.png **/build/idea-sandbox/system/**/*.log **/build/idea-sandbox/system-test/**/*.log **/video/**/*.avi From e0e13695bbca463b799ccb9a073a3369bc3ffbd6 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 20:46:22 +0200 Subject: [PATCH 29/41] chore: include smartmode check --- .../kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt index 17ebe55b3..54f960c31 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt @@ -139,6 +139,7 @@ private class UiTestExtension : remoteRobot.ideaFrame().disablePowerSaveMode() val gradleToolWindow = remoteRobot.ideaFrame().openGradleToolWindow() gradleToolWindow.ensureGradleProjectsAreSynced() + remoteRobot.ideaFrame().waitUntilProjectIsInSync() saveScreenshot("$testMethodName-after-gradle-sync") } From f79581b47eb7ec314c84adbb63e5c736452adee7 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 21:35:54 +0200 Subject: [PATCH 30/41] chore: perform pre and post smart mode check --- .../jbplugin/fixtures/UiTestExtensions.kt | 5 ++ .../fixtures/components/idea/IdeaFrame.kt | 54 ++++++++++++------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt index 54f960c31..fdd3807b3 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt @@ -21,6 +21,7 @@ import org.junit.jupiter.api.extension.* import java.awt.image.BufferedImage import java.io.ByteArrayOutputStream import java.io.File +import java.time.Duration import javax.imageio.ImageIO import kotlin.io.path.Path @@ -137,6 +138,10 @@ private class UiTestExtension : if (it.smartMode) { remoteRobot.ideaFrame().disablePowerSaveMode() + remoteRobot.ideaFrame().waitUntilProjectIsInSync( + modulesTimeout = Duration.ofMinutes(1), + smartModeTimeout = 1, + ) val gradleToolWindow = remoteRobot.ideaFrame().openGradleToolWindow() gradleToolWindow.ensureGradleProjectsAreSynced() remoteRobot.ideaFrame().waitUntilProjectIsInSync() diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index ee6200882..86bf94b58 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -12,6 +12,7 @@ import com.intellij.remoterobot.fixtures.* import com.intellij.remoterobot.search.locators.byXpath import com.intellij.remoterobot.steps.CommonSteps import com.intellij.remoterobot.stepsProcessing.step +import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.MongoDbServerUrl import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible @@ -200,39 +201,54 @@ class IdeaFrame( CommonSteps(remoteRobot).wait(1) } - fun waitUntilProjectIsInSync() { - eventually(timeout = Duration.ofMinutes(10)) { - step("Wait until Gradle project is in sync") { - assertTrue( - callJs( - """ + private fun waitUntilModulesAreLoaded(timeout: Duration = Duration.ofMinutes(1)) { + step("Wait until modules are loaded") { + waitFor( + duration = timeout, + description = "Modules to finish loading", + errorMessage = "Modules did not load" + ) { + callJs( + """ importPackage(com.intellij.openapi.wm.impl) importClass(com.intellij.openapi.module.ModuleManager) - const frameHelper = ProjectFrameHelper.getFrameHelper(component) const project = frameHelper.getProject() const modules = ModuleManager.getInstance(project).getModules() - + modules.length > 0 - """.trimIndent(), - runInEdt = true - ) + """.trimIndent(), + runInEdt = true ) } + } + } - // exiting smart mode does not mean we are in smart mode! - // so try a few times and wish for luck, there is no better API it seems. - // Reasoning: you are in dumb mode, you load some project metadata, go to smart mode - // then realise that you have dependencies to download and index, so you go back to dumb - // mode until everything is done. - // happily enough, this won't take time if smart mode is already on, so it should - // be fast. + private fun waitForSmartMode(timeout: Int = 5) { + // exiting smart mode does not mean we are in smart mode! + // so try a few times and wish for luck, there is no better API it seems. + // Reasoning: you are in dumb mode, you load some project metadata, go to smart mode + // then realise that you have dependencies to download and index, so you go back to dumb + // mode until everything is done. + // happily enough, this won't take time if smart mode is already on, so it should + // be fast. + step("Optimistically waiting for smart mode") { for (i in 0..10) { - CommonSteps(remoteRobot).waitForSmartMode(5) + CommonSteps(remoteRobot).waitForSmartMode(timeout) } } } + fun waitUntilProjectIsInSync( + modulesTimeout: Duration = Duration.ofMinutes(10), + smartModeTimeout: Int = 5 + ) { + step("For project to be in sync") { + waitUntilModulesAreLoaded(modulesTimeout) + waitForSmartMode(smartModeTimeout) + } + } + fun hideIntellijAiAd() { step("Hide IntelliJ AI Ad (uses a lot of space in a small window)") { tryHidingAiAdOnOldUI() From 32d0b8c74341570910099aa771af477a664cab11 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 22:43:45 +0200 Subject: [PATCH 31/41] chore: move selector matching on RemoteRobot --- .../JavaDriverToolbarVisibilityUiTest.kt | 14 ++++++------ .../fixtures/InfoAndProgressPanelFixture.kt | 3 +-- .../fixtures/RightToolWindowHeaderFixture.kt | 11 +++++----- .../jbplugin/fixtures/UiTestExtensions.kt | 20 ++++++++--------- .../components/GradleToolWindowFixture.kt | 22 ++++++------------- .../components/RightToolbarFixture.kt | 3 +-- 6 files changed, 31 insertions(+), 42 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index 5b11b9c23..06411ba7f 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -29,7 +29,7 @@ class JavaDriverToolbarVisibilityUiTest { } @Test - @RequiresProject("basic-java-project-with-mongodb") + @RequiresProject("basic-java-project-with-mongodb", smartMode = true) fun `shows the toolbar in a java file with references to the driver`(remoteRobot: RemoteRobot) { remoteRobot.ideaFrame().openFile( "/src/main/java/alt/mongodb/javadriver/JavaDriverRepository.java" @@ -39,7 +39,7 @@ class JavaDriverToolbarVisibilityUiTest { } @Test - @RequiresProject("basic-java-project-with-mongodb") + @RequiresProject("basic-java-project-with-mongodb", smartMode = true) fun `shows the toolbar in all the java files with references to the driver`( remoteRobot: RemoteRobot ) { @@ -62,7 +62,7 @@ class JavaDriverToolbarVisibilityUiTest { } @Test - @RequiresProject("basic-java-project-with-mongodb") + @RequiresProject("basic-java-project-with-mongodb", smartMode = true) fun `does not show the toolbar in a java file without references to the driver`( remoteRobot: RemoteRobot ) { @@ -73,7 +73,7 @@ class JavaDriverToolbarVisibilityUiTest { } @Test - @RequiresProject("basic-java-project-with-mongodb") + @RequiresProject("basic-java-project-with-mongodb", smartMode = true) fun `does show existing data sources in the combo box`( remoteRobot: RemoteRobot, url: MongoDbServerUrl, @@ -87,7 +87,7 @@ class JavaDriverToolbarVisibilityUiTest { } @Test - @RequiresProject("basic-java-project-with-mongodb") + @RequiresProject("basic-java-project-with-mongodb", smartMode = true) fun `does not show the database select on a java driver file`( remoteRobot: RemoteRobot, url: MongoDbServerUrl, @@ -101,7 +101,7 @@ class JavaDriverToolbarVisibilityUiTest { } @Test - @RequiresProject("basic-java-project-with-mongodb") + @RequiresProject("basic-java-project-with-mongodb", smartMode = true) fun `does show the database select on a spring criteria file`( remoteRobot: RemoteRobot, url: MongoDbServerUrl, @@ -123,7 +123,7 @@ class JavaDriverToolbarVisibilityUiTest { } @Test - @RequiresProject("basic-java-project-with-mongodb") + @RequiresProject("basic-java-project-with-mongodb", smartMode = true) fun `shows the toolbar when a reference to the driver is added`( remoteRobot: RemoteRobot, url: MongoDbServerUrl, diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt index b2f87012b..443f5ed7b 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/InfoAndProgressPanelFixture.kt @@ -8,7 +8,6 @@ import com.intellij.remoterobot.fixtures.FixtureName import com.intellij.remoterobot.search.locators.byXpath import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor -import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame import java.time.Duration @DefaultXpath(by = "class", xpath = "//div[@class='InfoAndProgressPanelImpl']") @@ -44,4 +43,4 @@ class InfoAndProgressPanelFixture( } } -fun IdeaFrame.infoAndProgressPanel(): InfoAndProgressPanelFixture = find() +fun RemoteRobot.infoAndProgressPanel(): InfoAndProgressPanelFixture = find() diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt index 519051095..3b114d740 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/RightToolWindowHeaderFixture.kt @@ -9,7 +9,6 @@ import com.intellij.remoterobot.fixtures.JButtonFixture import com.intellij.remoterobot.search.locators.byXpath import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor -import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame import java.time.Duration @DefaultXpath(by = "class", xpath = "//div[@class='ToolWindowHeader'][.//div[@class='BaseLabel']]") @@ -34,20 +33,22 @@ class RightToolWindowHeaderFixture( } } -fun IdeaFrame.rightToolWindowHeader(): RightToolWindowHeaderFixture = remoteRobot.find() +fun RemoteRobot.rightToolWindowHeader(): RightToolWindowHeaderFixture = find() -fun IdeaFrame.maybeRightToolWindowHeader(): RightToolWindowHeaderFixture? = runCatching { +fun RemoteRobot.maybeRightToolWindowHeader(): RightToolWindowHeaderFixture? = runCatching { rightToolWindowHeader() }.getOrNull() -fun IdeaFrame.closeRightToolWindow() { +fun RemoteRobot.closeRightToolWindow() { step("Closing right tool window") { waitFor( duration = Duration.ofMinutes(1), description = "Right tool window to close", errorMessage = "Right tool window did not close", ) { - maybeRightToolWindowHeader()?.hideButton?.click() + if (maybeRightToolWindowHeader()?.isShowing == true) { + maybeRightToolWindowHeader()?.hideButton?.click() + } maybeRightToolWindowHeader()?.isShowing != true } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt index fdd3807b3..2222a777d 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt @@ -21,7 +21,6 @@ import org.junit.jupiter.api.extension.* import java.awt.image.BufferedImage import java.io.ByteArrayOutputStream import java.io.File -import java.time.Duration import javax.imageio.ImageIO import kotlin.io.path.Path @@ -130,26 +129,25 @@ private class UiTestExtension : remoteRobot.keyboard { escape() } remoteRobot.closeProject() - requiresProject?.let { + requiresProject?.let { project -> // If we have the @RequireProject annotation, load that project on startup remoteRobot.openProject( - Path("src/test/resources/project-fixtures/${it.value}").toAbsolutePath().toString(), + Path( + "src/test/resources/project-fixtures/${project.value}" + ).toAbsolutePath().toString(), ) - if (it.smartMode) { + if (project.smartMode) { remoteRobot.ideaFrame().disablePowerSaveMode() - remoteRobot.ideaFrame().waitUntilProjectIsInSync( - modulesTimeout = Duration.ofMinutes(1), - smartModeTimeout = 1, - ) - val gradleToolWindow = remoteRobot.ideaFrame().openGradleToolWindow() - gradleToolWindow.ensureGradleProjectsAreSynced() + remoteRobot.openGradleToolWindow().also { + it.ensureGradleProjectsAreSynced() + } remoteRobot.ideaFrame().waitUntilProjectIsInSync() saveScreenshot("$testMethodName-after-gradle-sync") } // Close any right tool window - remoteRobot.ideaFrame().closeRightToolWindow() + remoteRobot.closeRightToolWindow() saveScreenshot("$testMethodName-after-closing-right-tool-window") } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt index 4e2c5e55c..978bfbb46 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt @@ -4,11 +4,9 @@ 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.steps.CommonSteps import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor -import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame -import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame +import com.intellij.remoterobot.utils.waitForIgnoringError import com.mongodb.jbplugin.fixtures.infoAndProgressPanel import java.time.Duration @@ -48,7 +46,7 @@ class GradleToolWindowFixture( fun ensureGradleProjectsAreSynced() { step("Ensuring gradle projects are synced") { runCatching { - waitFor( + waitForIgnoringError( duration = Duration.ofMinutes(2), description = "Gradle projects to show up", errorMessage = "Gradle projects did not show up", @@ -57,10 +55,6 @@ class GradleToolWindowFixture( } }.isFailure - runCatching { - CommonSteps(remoteRobot).waitForSmartMode(2) - } - step("Manually reload gradle projects") { reloadGradleButton.click() // remoteRobot.invokeAction("ExternalSystem.RefreshAllProjects") @@ -73,27 +67,25 @@ class GradleToolWindowFixture( } } - remoteRobot.ideaFrame().infoAndProgressPanel().waitForInProgressTasksToFinish() + remoteRobot.infoAndProgressPanel().waitForInProgressTasksToFinish() } } } -fun IdeaFrame.gradleToolWindow(): GradleToolWindowFixture = find() +fun RemoteRobot.gradleToolWindow(): GradleToolWindowFixture = find() -fun IdeaFrame.maybeGradleToolWindow(): GradleToolWindowFixture? = runCatching { +fun RemoteRobot.maybeGradleToolWindow(): GradleToolWindowFixture? = runCatching { gradleToolWindow() }.getOrNull() -fun IdeaFrame.openGradleToolWindow(): GradleToolWindowFixture { +fun RemoteRobot.openGradleToolWindow(): GradleToolWindowFixture { return step("Open gradle tool window") { waitFor( duration = Duration.ofMinutes(1), description = "Gradle tool window to open", errorMessage = "Gradle tool window did not open" ) { - maybeGradleToolWindow()?.let { - isShowing - } ?: run { + maybeGradleToolWindow()?.isShowing ?: run { rightToolbar().gradleButton.click() maybeGradleToolWindow()?.isShowing == true } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt index 601b9db2d..1fd43cb06 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt @@ -7,7 +7,6 @@ import com.intellij.remoterobot.fixtures.DefaultXpath import com.intellij.remoterobot.fixtures.FixtureName import com.intellij.remoterobot.fixtures.JButtonFixture import com.intellij.remoterobot.search.locators.byXpath -import com.mongodb.jbplugin.fixtures.components.idea.IdeaFrame import java.time.Duration @DefaultXpath( @@ -28,6 +27,6 @@ class RightToolbarFixture( } } -fun IdeaFrame.rightToolbar(): RightToolbarFixture = find( +fun RemoteRobot.rightToolbar(): RightToolbarFixture = find( Duration.ofSeconds(30) ) From 0345316dd2dd4ae8c49e774f21d5307fbb117dc9 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 22 Oct 2024 23:22:28 +0200 Subject: [PATCH 32/41] chore: catch clean data sources error --- .../fixtures/components/idea/IdeaFrame.kt | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index 86bf94b58..599bf5363 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -286,30 +286,35 @@ class IdeaFrame( fun cleanDataSources() { step("Cleaning DataSources") { - runJs( - """ - const LocalDataSourceManager = global.get('loadDataGripPluginClass')( - 'com.intellij.database.dataSource.LocalDataSourceManager' - ) - - importClass(java.lang.System) - importClass(com.intellij.openapi.project.Project) - importClass(com.intellij.openapi.util.Key) - importPackage(com.intellij.openapi.progress) - importPackage(com.intellij.openapi.wm.impl) - importPackage(com.intellij.database.view.ui) - importClass(com.intellij.openapi.application.ApplicationManager) - - const frameHelper = ProjectFrameHelper.getFrameHelper(component) - const project = frameHelper.getProject() - const dataSourceManager = LocalDataSourceManager.getMethod("getInstance", Project).invoke(null, project) - const dataSources = dataSourceManager.getDataSources(); - for (let i = 0; i < dataSources.size(); i++) { - dataSourceManager.removeDataSource(dataSources.get(i)); + // From time to time this fails with write safe context errors + // but given that the removal happens anyways, we are silently ignoring + // the error here + runCatching { + runJs( + """ + const LocalDataSourceManager = global.get('loadDataGripPluginClass')( + 'com.intellij.database.dataSource.LocalDataSourceManager' + ) + + importClass(java.lang.System) + importClass(com.intellij.openapi.project.Project) + importClass(com.intellij.openapi.util.Key) + importPackage(com.intellij.openapi.progress) + importPackage(com.intellij.openapi.wm.impl) + importPackage(com.intellij.database.view.ui) + importClass(com.intellij.openapi.application.ApplicationManager) + + const frameHelper = ProjectFrameHelper.getFrameHelper(component) + const project = frameHelper.getProject() + const dataSourceManager = LocalDataSourceManager.getMethod("getInstance", Project).invoke(null, project) + const dataSources = dataSourceManager.getDataSources(); + for (let i = 0; i < dataSources.size(); i++) { + dataSourceManager.removeDataSource(dataSources.get(i)); + } + """.trimIndent(), + runInEdt = true, + ) } - """.trimIndent(), - runInEdt = true, - ) } CommonSteps(remoteRobot).wait(1) } From 207180f36fffcd541b079cda74fdadf1e16bbcf1 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 00:09:03 +0200 Subject: [PATCH 33/41] chore: remove data sources from UI instead of write unsafe context call --- .../impl/MongoDbRunQueryActionUiTest.kt | 3 +- .../JavaDriverToolbarVisibilityUiTest.kt | 3 +- .../jbplugin/fixtures/UiTestExtensions.kt | 2 + .../components/DatabaseToolWindowFixture.kt | 92 +++++++++++++++++++ .../components/GradleToolWindowFixture.kt | 1 - .../components/RightToolbarFixture.kt | 4 + 6 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/DatabaseToolWindowFixture.kt diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt index 024333f11..06e19ced5 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt @@ -3,6 +3,7 @@ package com.mongodb.jbplugin.codeActions.impl import com.intellij.remoterobot.RemoteRobot import com.mongodb.jbplugin.fixtures.* import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame +import com.mongodb.jbplugin.fixtures.components.openDatabaseToolWindow import com.mongodb.jbplugin.fixtures.components.openRunQueryPopup import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.* @@ -25,7 +26,7 @@ class MongoDbRunQueryActionUiTest { @AfterEach fun tearDown(remoteRobot: RemoteRobot) { - remoteRobot.ideaFrame().cleanDataSources() + remoteRobot.openDatabaseToolWindow().removeAllDataSources() } @Test diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index 06411ba7f..837cb2cdc 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -5,6 +5,7 @@ import com.mongodb.jbplugin.fixtures.* import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbar import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame import com.mongodb.jbplugin.fixtures.components.isJavaEditorToolbarHidden +import com.mongodb.jbplugin.fixtures.components.openDatabaseToolWindow import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach @@ -25,7 +26,7 @@ class JavaDriverToolbarVisibilityUiTest { @AfterEach fun tearDown(remoteRobot: RemoteRobot) { - remoteRobot.ideaFrame().cleanDataSources() + remoteRobot.openDatabaseToolWindow().removeAllDataSources() } @Test diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt index 2222a777d..28f899450 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt @@ -142,6 +142,8 @@ private class UiTestExtension : remoteRobot.openGradleToolWindow().also { it.ensureGradleProjectsAreSynced() } + // This ideally should not be needed anymore, but we still perform this + // to wait for smart mode to kick-in before doing anything else. remoteRobot.ideaFrame().waitUntilProjectIsInSync() saveScreenshot("$testMethodName-after-gradle-sync") } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/DatabaseToolWindowFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/DatabaseToolWindowFixture.kt new file mode 100644 index 000000000..3053b6425 --- /dev/null +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/DatabaseToolWindowFixture.kt @@ -0,0 +1,92 @@ +package com.mongodb.jbplugin.fixtures.components + +import com.intellij.remoterobot.RemoteRobot +import com.intellij.remoterobot.data.RemoteComponent +import com.intellij.remoterobot.fixtures.ContainerFixture +import com.intellij.remoterobot.fixtures.DefaultXpath +import com.intellij.remoterobot.fixtures.JButtonFixture +import com.intellij.remoterobot.fixtures.JPopupMenuFixture +import com.intellij.remoterobot.fixtures.JTreeFixture +import com.intellij.remoterobot.search.locators.byXpath +import com.intellij.remoterobot.stepsProcessing.step +import com.intellij.remoterobot.utils.waitFor +import java.time.Duration + +@DefaultXpath( + by = "class", + xpath = "//div[@class='InternalDecoratorImpl' and @accessiblename='Database Tool Window']" +) +class DatabaseToolWindowFixture( + remoteRobot: RemoteRobot, + remoteComponent: RemoteComponent, +) : ContainerFixture(remoteRobot, remoteComponent) { + private val databaseTree by lazy { + find(byXpath("//div[@class='DatabaseViewTreeComponent']")) + } + + fun removeDataSourceAtIndex(index: Int) { + val oldSize = databaseTree.collectRows().size + val dataSourceAtIndex = databaseTree.collectRows()[index] + step("Removing DataSource $dataSourceAtIndex at index $index") { + waitFor( + duration = Duration.ofMinutes(1), + description = "Data source to be removed", + errorMessage = "Data source was not removed" + ) { + databaseTree.rightClickRow(index) + val popupMenu = remoteRobot.find( + byXpath("//div[@class='MyMenu']") + ) + popupMenu.select("Remove Data Source… ") + + val confirmationDialog = remoteRobot.find( + byXpath("//div[@class='MyDialog']") + ) + + confirmationDialog.find( + byXpath("//div[@text='OK']") + ).click() + + databaseTree.collectRows().size == oldSize - 1 + } + } + } + + fun removeDataSourceByName(name: String) { + step("Removing DataSource $name") { + val indexToRemove = databaseTree.collectRows().indexOfFirst { it.contains(name) } + removeDataSourceAtIndex(indexToRemove) + } + } + + fun removeAllDataSources() { + step("Removing all data sources") { + while (databaseTree.collectRows().isNotEmpty()) { + removeDataSourceAtIndex(0) + } + } + } +} + +fun RemoteRobot.databaseToolWindow(): DatabaseToolWindowFixture = find() + +fun RemoteRobot.maybeDatabaseToolWindow(): DatabaseToolWindowFixture? = runCatching { + databaseToolWindow() +}.getOrNull() + +fun RemoteRobot.openDatabaseToolWindow(): DatabaseToolWindowFixture { + return step("Open database tool window") { + waitFor( + duration = Duration.ofMinutes(1), + description = "Database tool window to open", + errorMessage = "Database tool window did not open" + ) { + maybeDatabaseToolWindow()?.isShowing ?: run { + rightToolbar().databaseButton.click() + maybeDatabaseToolWindow()?.isShowing == true + } + } + + return@step databaseToolWindow() + } +} diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt index 978bfbb46..9841eb5b1 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/GradleToolWindowFixture.kt @@ -57,7 +57,6 @@ class GradleToolWindowFixture( step("Manually reload gradle projects") { reloadGradleButton.click() - // remoteRobot.invokeAction("ExternalSystem.RefreshAllProjects") waitFor( duration = Duration.ofMinutes(2), description = "Gradle projects to show up after manual reload", diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt index 1fd43cb06..ea294300a 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/RightToolbarFixture.kt @@ -22,6 +22,10 @@ class RightToolbarFixture( find(byXpath("//div[@tooltiptext='AI Assistant' or @text='AI Assistant']")) } + val databaseButton by lazy { + find(byXpath("//div[@tooltiptext='Database' or @text='Database']")) + } + val gradleButton by lazy { find(byXpath("//div[@tooltiptext='Gradle' or @text='Gradle']")) } From 9fe8b08e73e9b1c222a28af5aaf37c2327c349d1 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 12:32:46 +0200 Subject: [PATCH 34/41] chore: address PR feedback and remove debug steps --- .../com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt | 4 ++-- .../com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt | 4 ++-- .../kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt | 2 -- packages/jetbrains-plugin/src/test/resources/video.properties | 1 - 4 files changed, 4 insertions(+), 7 deletions(-) delete mode 100644 packages/jetbrains-plugin/src/test/resources/video.properties diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt index f7889abac..b6dad3017 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt @@ -1,6 +1,7 @@ package com.mongodb.jbplugin.editor.inputs import com.intellij.database.dataSource.LocalDataSource +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.asSequence @@ -21,7 +22,6 @@ import java.awt.event.ItemListener import javax.swing.DefaultComboBoxModel import javax.swing.JComponent import javax.swing.SwingConstants -import javax.swing.SwingUtilities import javax.swing.event.PopupMenuEvent import javax.swing.event.PopupMenuListener @@ -100,7 +100,7 @@ class DataSourceComboBox( var isFirstInit = true coroutineScope.launch { project.getToolbarModel().toolbarState.collect { state -> - SwingUtilities.invokeLater { + ApplicationManager.getApplication().invokeLater { updateComboBoxState(state, isFirstInit) isFirstInit = false } diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt index 5e53a4950..9751fa0bb 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt @@ -1,5 +1,6 @@ package com.mongodb.jbplugin.editor.inputs +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.asSequence @@ -18,7 +19,6 @@ import java.awt.event.ItemListener import javax.swing.DefaultComboBoxModel import javax.swing.JComponent import javax.swing.SwingConstants -import javax.swing.SwingUtilities import javax.swing.event.PopupMenuEvent import javax.swing.event.PopupMenuListener @@ -80,7 +80,7 @@ class DatabaseComboBox( var isFirstInit = true coroutineScope.launch { project.getToolbarModel().toolbarState.collect { state -> - SwingUtilities.invokeLater { + ApplicationManager.getApplication().invokeLater { updateComboBoxState(state, isFirstInit) isFirstInit = false } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt index 28f899450..6d2af53e9 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/UiTestExtensions.kt @@ -145,12 +145,10 @@ private class UiTestExtension : // This ideally should not be needed anymore, but we still perform this // to wait for smart mode to kick-in before doing anything else. remoteRobot.ideaFrame().waitUntilProjectIsInSync() - saveScreenshot("$testMethodName-after-gradle-sync") } // Close any right tool window remoteRobot.closeRightToolWindow() - saveScreenshot("$testMethodName-after-closing-right-tool-window") } } diff --git a/packages/jetbrains-plugin/src/test/resources/video.properties b/packages/jetbrains-plugin/src/test/resources/video.properties deleted file mode 100644 index f03fd1541..000000000 --- a/packages/jetbrains-plugin/src/test/resources/video.properties +++ /dev/null @@ -1 +0,0 @@ -video.save.mode=ALL From 29a7f9c1ed34067347ca340114cae75ed4444e29 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 13:13:13 +0200 Subject: [PATCH 35/41] chore: use invokeLater with correct modality state --- .../com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt | 5 +++-- .../com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt index b6dad3017..8b32e394f 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DataSourceComboBox.kt @@ -2,6 +2,7 @@ package com.mongodb.jbplugin.editor.inputs import com.intellij.database.dataSource.LocalDataSource import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState import com.intellij.openapi.project.Project import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.asSequence @@ -100,10 +101,10 @@ class DataSourceComboBox( var isFirstInit = true coroutineScope.launch { project.getToolbarModel().toolbarState.collect { state -> - ApplicationManager.getApplication().invokeLater { + ApplicationManager.getApplication().invokeLater({ updateComboBoxState(state, isFirstInit) isFirstInit = false - } + }, ModalityState.stateForComponent(comboBoxComponent)) } } } diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt index 9751fa0bb..11183d87f 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/editor/inputs/DatabaseComboBox.kt @@ -1,6 +1,7 @@ package com.mongodb.jbplugin.editor.inputs import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState import com.intellij.openapi.project.Project import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.asSequence @@ -80,10 +81,10 @@ class DatabaseComboBox( var isFirstInit = true coroutineScope.launch { project.getToolbarModel().toolbarState.collect { state -> - ApplicationManager.getApplication().invokeLater { + ApplicationManager.getApplication().invokeLater({ updateComboBoxState(state, isFirstInit) isFirstInit = false - } + }, ModalityState.stateForComponent(comboBoxComponent)) } } } From 9f3c7b6e3e0c44a7dfc671497dad66f427de4e85 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 13:49:00 +0200 Subject: [PATCH 36/41] chore: address PR feedback and add safety net for left over data sources --- .../impl/MongoDbRunQueryActionUiTest.kt | 3 + .../JavaDriverToolbarVisibilityUiTest.kt | 3 + .../jbplugin/fixtures/AssertionExtensions.kt | 63 +++++++++++++++---- .../components/DatabaseToolWindowFixture.kt | 8 ++- .../components/MdbJavaEditorToolbarFixture.kt | 31 ++++----- .../MdbJavaEditorToolbarPopupFixture.kt | 31 ++++----- .../fixtures/components/idea/IdeaFrame.kt | 19 ++++-- 7 files changed, 100 insertions(+), 58 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt index 06e19ced5..fdddd93f7 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt @@ -21,6 +21,9 @@ class MongoDbRunQueryActionUiTest { remoteRobot: RemoteRobot, url: MongoDbServerUrl, ) { + // This is our safety net to ensure we start with a clean slate + remoteRobot.openDatabaseToolWindow().removeAllDataSources() + remoteRobot.closeRightToolWindow() remoteRobot.ideaFrame().addDataSourceWithUrl(javaClass.simpleName, url) } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index 837cb2cdc..ad7f1fed0 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -21,6 +21,9 @@ class JavaDriverToolbarVisibilityUiTest { remoteRobot: RemoteRobot, url: MongoDbServerUrl, ) { + // This is our safety net to ensure we start with a clean slate + remoteRobot.openDatabaseToolWindow().removeAllDataSources() + remoteRobot.closeRightToolWindow() remoteRobot.ideaFrame().addDataSourceWithUrl(javaClass.simpleName, url) } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/AssertionExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/AssertionExtensions.kt index f94c22547..c5a58f31d 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/AssertionExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/AssertionExtensions.kt @@ -5,6 +5,7 @@ package com.mongodb.jbplugin.fixtures import com.intellij.remoterobot.RemoteRobot +import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.keyboard import com.intellij.remoterobot.utils.waitFor import java.time.Duration @@ -21,6 +22,38 @@ fun RemoteRobot.closeAllOpenModals() { } } +/** + * Waits until the block function finishes successfully up to 1 second (or the provided timeout). + * + * Example usages: + * + * ```kt + * eventually("Doing something") { + * verify(mock).myFunction() + * } + * // with custom timeout + * eventually(description = "Doing something", timeout = Duration.ofSeconds(5)) { + * verify(mock).myFunction() + * } + * ``` + * + * @param timeout + * @param fn + * @param recovery + */ +fun eventually( + description: String, + timeout: Duration = Duration.ofSeconds(1), + recovery: () -> Unit = {}, + fn: (Int) -> Unit +) { + eventually(timeout, recovery) { attempt -> + step("$description, attempt=$attempt") { + fn(attempt) + } + } +} + /** * Waits until the block function finishes successfully up to 1 second (or the provided timeout). * @@ -43,11 +76,12 @@ fun RemoteRobot.closeAllOpenModals() { fun eventually( timeout: Duration = Duration.ofSeconds(1), recovery: () -> Unit = {}, - fn: () -> Unit + fn: (Int) -> Unit ) { + var attempt = 1 waitFor(timeout, Duration.ofMillis(50)) { val result = runCatching { - fn() + fn(attempt++) true }.getOrDefault(false) @@ -80,16 +114,19 @@ fun eventually( */ fun eventually( timeout: Duration = Duration.ofSeconds(1), - fn: () -> T -): T? = waitFor( - timeout, - Duration.ofMillis( - 50 - ) -) { - val result = runCatching { - fn() - } + fn: (Int) -> T +): T? { + var attempt = 1 + return waitFor( + timeout, + Duration.ofMillis( + 50 + ) + ) { + val result = runCatching { + fn(attempt++) + } - result.isSuccess to result.getOrNull() + result.isSuccess to result.getOrNull() + } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/DatabaseToolWindowFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/DatabaseToolWindowFixture.kt index 3053b6425..0c6e56869 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/DatabaseToolWindowFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/DatabaseToolWindowFixture.kt @@ -8,8 +8,10 @@ import com.intellij.remoterobot.fixtures.JButtonFixture import com.intellij.remoterobot.fixtures.JPopupMenuFixture import com.intellij.remoterobot.fixtures.JTreeFixture import com.intellij.remoterobot.search.locators.byXpath +import com.intellij.remoterobot.steps.CommonSteps import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor +import com.intellij.remoterobot.utils.waitForIgnoringError import java.time.Duration @DefaultXpath( @@ -28,21 +30,23 @@ class DatabaseToolWindowFixture( val oldSize = databaseTree.collectRows().size val dataSourceAtIndex = databaseTree.collectRows()[index] step("Removing DataSource $dataSourceAtIndex at index $index") { - waitFor( + waitForIgnoringError( duration = Duration.ofMinutes(1), description = "Data source to be removed", errorMessage = "Data source was not removed" ) { databaseTree.rightClickRow(index) + + CommonSteps(remoteRobot).wait(1) val popupMenu = remoteRobot.find( byXpath("//div[@class='MyMenu']") ) popupMenu.select("Remove Data Source… ") + CommonSteps(remoteRobot).wait(1) val confirmationDialog = remoteRobot.find( byXpath("//div[@class='MyDialog']") ) - confirmationDialog.find( byXpath("//div[@text='OK']") ).click() diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt index df2e7b747..79bb67792 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarFixture.kt @@ -7,7 +7,6 @@ import com.intellij.remoterobot.fixtures.ContainerFixture import com.intellij.remoterobot.fixtures.DefaultXpath import com.intellij.remoterobot.fixtures.FixtureName import com.intellij.remoterobot.search.locators.byXpath -import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible @@ -47,34 +46,28 @@ class MdbJavaEditorToolbarFixture( }.isSuccess fun selectDataSource(title: String) { - eventually(1.minutes.toJavaDuration()) { - step("Selecting DataSource $title in toolbar") { - dataSources.selectItemContains(title) - if (!dataSources.selectedText().contains(title)) { - throw Exception("Could not select data source - $title") - } + eventually("Selecting DataSource $title in toolbar", 1.minutes.toJavaDuration()) { + dataSources.selectItemContains(title) + if (!dataSources.selectedText().contains(title)) { + throw Exception("Could not select data source - $title") } } } fun selectDetachDataSource() { - eventually(1.minutes.toJavaDuration()) { - step("Detaching DataSource from toolbar") { - dataSources.selectItem("Detach data source") - if (dataSources.selectedText() != "") { - throw Exception("Could not detach data source") - } + eventually("Detaching DataSource from toolbar", 1.minutes.toJavaDuration()) { + dataSources.selectItem("Detach data source") + if (dataSources.selectedText() != "") { + throw Exception("Could not detach data source") } } } fun selectDatabase(title: String) { - eventually(1.minutes.toJavaDuration()) { - step("Selecting Database $title in toolbar") { - databases.selectItemContains(title) - if (!databases.selectedText().contains(title)) { - throw Exception("Could not select database - $title") - } + eventually("Selecting Database $title in toolbar", 1.minutes.toJavaDuration()) { + databases.selectItemContains(title) + if (!databases.selectedText().contains(title)) { + throw Exception("Could not select database - $title") } } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt index 70b29c0ec..e96440199 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/MdbJavaEditorToolbarPopupFixture.kt @@ -4,7 +4,6 @@ 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.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible @@ -57,34 +56,28 @@ class MdbJavaEditorToolbarPopupFixture( fun cancel() = find(byXpath("//div[@text='Cancel']")).click() fun selectDataSource(title: String) { - eventually(1.minutes.toJavaDuration()) { - step("Selecting DataSource $title in popup") { - dataSources.selectItemContains(title) - if (!dataSources.selectedText().contains(title)) { - throw Exception("Could not select data source - $title") - } + eventually("Selecting DataSource $title in popup", 1.minutes.toJavaDuration()) { + dataSources.selectItemContains(title) + if (!dataSources.selectedText().contains(title)) { + throw Exception("Could not select data source - $title") } } } fun selectDetachDataSource() { - eventually(1.minutes.toJavaDuration()) { - step("Detaching DataSource from popup") { - dataSources.selectItem("Detach data source") - if (dataSources.selectedText() != "") { - throw Exception("Could not detach data source") - } + eventually("Detaching DataSource from popup", 1.minutes.toJavaDuration()) { + dataSources.selectItem("Detach data source") + if (dataSources.selectedText() != "") { + throw Exception("Could not detach data source") } } } fun selectDatabase(title: String) { - eventually(1.minutes.toJavaDuration()) { - step("Selecting Database $title in popup") { - databases.selectItemContains(title) - if (!databases.selectedText().contains(title)) { - throw Exception("Could not select database - $title") - } + eventually("Selecting Database $title in popup", 1.minutes.toJavaDuration()) { + databases.selectItemContains(title) + if (!databases.selectedText().contains(title)) { + throw Exception("Could not select database - $title") } } } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index 599bf5363..9cdf7247c 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -86,8 +86,9 @@ class IdeaFrame( url: MongoDbServerUrl, ) { step("Adding DataSource with name=$name, url=$url") { - runJs( - """ + val failed = runCatching { + runJs( + """ const LocalDataSourceManager = global.get('loadDataGripPluginClass')( 'com.intellij.database.dataSource.LocalDataSourceManager' ) @@ -133,9 +134,17 @@ class IdeaFrame( .invoke(null, dataSource, null) .run(new EmptyProgressIndicator()) } - """.trimIndent(), - runInEdt = true, - ) + """.trimIndent(), + runInEdt = true, + ) + }.isFailure + + if (failed) { + step("Warning: Adding DataSource with name=$name, url=$url was errored") { + // The runJs errors with Modality error but the DataSource is still added + // which is why we ignore the error silently but log it for debug information + } + } } CommonSteps(remoteRobot).wait(1) } From df5c222c89acf803715c839f82b7f1b13cfa0b70 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 14:17:43 +0200 Subject: [PATCH 37/41] chore: remove dead code --- .../fixtures/components/idea/IdeaFrame.kt | 71 ------------------- 1 file changed, 71 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index 9cdf7247c..1c81731a7 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -9,7 +9,6 @@ package com.mongodb.jbplugin.fixtures.components.idea 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.steps.CommonSteps import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor @@ -258,76 +257,6 @@ class IdeaFrame( } } - fun hideIntellijAiAd() { - step("Hide IntelliJ AI Ad (uses a lot of space in a small window)") { - tryHidingAiAdOnOldUI() - tryHidingAiAdOnNewUI() - } - } - - private fun tryHidingAiAdOnNewUI() { - step("Attempting to hide AI ad on new UI") { - runCatching { - val aiMenu = remoteRobot.find( - byXpath("//div[@accessiblename='AI Assistant']") - ) - aiMenu.rightClick() - remoteRobot.find( - byXpath("//div[@text='Hide']") - ).click() - } - } - } - - private fun tryHidingAiAdOnOldUI() { - step("Attempting to hide AI ad on old UI") { - runCatching { - val aiMenu = remoteRobot.find( - byXpath("//div[@tooltiptext='Install AI Assistant']") - ) - aiMenu.rightClick() - remoteRobot.find( - byXpath("//div[@text='Remove from Sidebar']") - ).click() - } - } - } - - fun cleanDataSources() { - step("Cleaning DataSources") { - // From time to time this fails with write safe context errors - // but given that the removal happens anyways, we are silently ignoring - // the error here - runCatching { - runJs( - """ - const LocalDataSourceManager = global.get('loadDataGripPluginClass')( - 'com.intellij.database.dataSource.LocalDataSourceManager' - ) - - importClass(java.lang.System) - importClass(com.intellij.openapi.project.Project) - importClass(com.intellij.openapi.util.Key) - importPackage(com.intellij.openapi.progress) - importPackage(com.intellij.openapi.wm.impl) - importPackage(com.intellij.database.view.ui) - importClass(com.intellij.openapi.application.ApplicationManager) - - const frameHelper = ProjectFrameHelper.getFrameHelper(component) - const project = frameHelper.getProject() - const dataSourceManager = LocalDataSourceManager.getMethod("getInstance", Project).invoke(null, project) - const dataSources = dataSourceManager.getDataSources(); - for (let i = 0; i < dataSources.size(); i++) { - dataSourceManager.removeDataSource(dataSources.get(i)); - } - """.trimIndent(), - runInEdt = true, - ) - } - } - CommonSteps(remoteRobot).wait(1) - } - fun closeAllFiles() { step("Closing all files") { runJs( From faec2d5b57fcd76970ba13cdb6f078511f9ce6e0 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 15:23:56 +0200 Subject: [PATCH 38/41] chore: specify the current modality state --- .../fixtures/components/idea/IdeaFrame.kt | 58 ++++--------------- 1 file changed, 11 insertions(+), 47 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index 1c81731a7..219851ce6 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -13,9 +13,7 @@ import com.intellij.remoterobot.steps.CommonSteps import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.MongoDbServerUrl -import com.mongodb.jbplugin.fixtures.eventually import com.mongodb.jbplugin.fixtures.findVisible -import org.junit.jupiter.api.Assertions.assertTrue import org.owasp.encoder.Encode import java.time.Duration import kotlin.time.Duration.Companion.milliseconds @@ -49,6 +47,7 @@ class IdeaFrame( importPackage(com.intellij.openapi.wm.impl) importClass(com.intellij.openapi.application.ApplicationManager) importClass(com.intellij.openapi.fileEditor.FileEditorManager) + importClass(com.intellij.openapi.application.ModalityState) const path = '$escapedPath' const frameHelper = ProjectFrameHelper.getFrameHelper(component) @@ -66,7 +65,7 @@ class IdeaFrame( fileEditorManager.openTextEditor(fileDescriptor, true) } }) - ApplicationManager.getApplication().invokeAndWait(openFileFunction) + ApplicationManager.getApplication().invokeAndWait(openFileFunction, ModalityState.current()) } """, true, @@ -148,53 +147,13 @@ class IdeaFrame( CommonSteps(remoteRobot).wait(1) } - fun waitUntilConnectedToMongoDb(name: String, timeout: Duration = Duration.ofMinutes(1)) { - eventually(timeout) { - step("Waiting for DataSource $name to connect, timeout=$timeout") { - assertTrue( - callJs( - """ - importClass(java.lang.System) - - const DatabaseConnectionManager = global.get('loadDataGripPluginClass')( - 'com.intellij.database.dataSource.DatabaseConnectionManager' - ) - - const connectionManager = DatabaseConnectionManager.getMethod("getInstance").invoke(null) - const activeConnections = connectionManager.getActiveConnections() - var connected = false; - - for (connection of activeConnections) { - if(connection.getConnectionPoint().getDataSource().name.equals("$name")) { - try { - connected = !connection.getRemoteConnection().isClosed() && - connection.getRemoteConnection().isValid(10) - } catch (e) { - System.err.println(e.toString()) - } - - if (connected) { - break - } - } - } - - connected - """.trimIndent(), - runInEdt = true - ) - ) - } - } - CommonSteps(remoteRobot).wait(1) - } - fun disablePowerSaveMode() { step("Disable Power Save Mode") { runJs( """ importClass(com.intellij.ide.PowerSaveMode) importClass(com.intellij.openapi.application.ApplicationManager) + importClass(com.intellij.openapi.application.ModalityState) const disableIt = new Runnable({ run: function() { @@ -202,8 +161,9 @@ class IdeaFrame( } }) - ApplicationManager.getApplication().invokeLater(disableIt) - """.trimIndent() + ApplicationManager.getApplication().invokeLater(disableIt, ModalityState.current()) + """.trimIndent(), + runInEdt = true, ) } CommonSteps(remoteRobot).wait(1) @@ -265,6 +225,7 @@ class IdeaFrame( importPackage(com.intellij.openapi.vfs) importPackage(com.intellij.openapi.wm.impl) importClass(com.intellij.openapi.application.ApplicationManager) + importClass(com.intellij.openapi.application.ModalityState) const frameHelper = ProjectFrameHelper.getFrameHelper(component) if (frameHelper) { @@ -277,7 +238,10 @@ class IdeaFrame( } }) - ApplicationManager.getApplication().invokeLater(closeEditorsFunction) + ApplicationManager.getApplication().invokeLater( + closeEditorsFunction, + ModalityState.current() + ) } """, true, From 46bcc56062c720ff7a508fc31dc2bb71b6d867ec Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 16:15:00 +0200 Subject: [PATCH 39/41] chore: catch Write unsafe errors and ignore --- .../fixtures/components/idea/IdeaFrame.kt | 177 ++++++++++-------- 1 file changed, 104 insertions(+), 73 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index 219851ce6..4a74d5dd2 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -40,36 +40,46 @@ class IdeaFrame( val escapedPath = Encode.forJavaScript(path) - runJs( - """ - importPackage(com.intellij.openapi.fileEditor) - importPackage(com.intellij.openapi.vfs) - importPackage(com.intellij.openapi.wm.impl) - importClass(com.intellij.openapi.application.ApplicationManager) - importClass(com.intellij.openapi.fileEditor.FileEditorManager) - importClass(com.intellij.openapi.application.ModalityState) - - const path = '$escapedPath' - const frameHelper = ProjectFrameHelper.getFrameHelper(component) - if (frameHelper) { - const project = frameHelper.getProject() - const projectPath = project.getBasePath() - const file = LocalFileSystem.getInstance().findFileByPath(projectPath + '/' + path) - const openFileFunction = new Runnable({ - run: function() { - const fileEditorManager = FileEditorManager.getInstance(project); - const fileDescriptor = new OpenFileDescriptor( - project, - file - ); - fileEditorManager.openTextEditor(fileDescriptor, true) + val runResult = runCatching { + runJs( + """ + importPackage(com.intellij.openapi.fileEditor) + importPackage(com.intellij.openapi.vfs) + importPackage(com.intellij.openapi.wm.impl) + importClass(com.intellij.openapi.application.ApplicationManager) + importClass(com.intellij.openapi.fileEditor.FileEditorManager) + importClass(com.intellij.openapi.application.ModalityState) + + const path = '$escapedPath' + const frameHelper = ProjectFrameHelper.getFrameHelper(component) + if (frameHelper) { + const project = frameHelper.getProject() + const projectPath = project.getBasePath() + const file = LocalFileSystem.getInstance().findFileByPath(projectPath + '/' + path) + const openFileFunction = new Runnable({ + run: function() { + const fileEditorManager = FileEditorManager.getInstance(project); + const fileDescriptor = new OpenFileDescriptor( + project, + file + ); + fileEditorManager.openTextEditor(fileDescriptor, true) + } + }) + ApplicationManager.getApplication().invokeAndWait(openFileFunction, ModalityState.current()) } - }) - ApplicationManager.getApplication().invokeAndWait(openFileFunction, ModalityState.current()) + """, + true, + ) + } + + if (runResult.isFailure) { + if (runResult.exceptionOrNull()?.message?.contains("Write-unsafe context") != + true + ) { + throw runResult.exceptionOrNull()!! + } } - """, - true, - ) } CommonSteps(remoteRobot).wait(1) } @@ -84,7 +94,7 @@ class IdeaFrame( url: MongoDbServerUrl, ) { step("Adding DataSource with name=$name, url=$url") { - val failed = runCatching { + val runResult = runCatching { runJs( """ const LocalDataSourceManager = global.get('loadDataGripPluginClass')( @@ -135,12 +145,13 @@ class IdeaFrame( """.trimIndent(), runInEdt = true, ) - }.isFailure + } - if (failed) { - step("Warning: Adding DataSource with name=$name, url=$url was errored") { - // The runJs errors with Modality error but the DataSource is still added - // which is why we ignore the error silently but log it for debug information + if (runResult.isFailure) { + if (runResult.exceptionOrNull()?.message?.contains("Write-unsafe context") != + true + ) { + throw runResult.exceptionOrNull()!! } } } @@ -149,22 +160,32 @@ class IdeaFrame( fun disablePowerSaveMode() { step("Disable Power Save Mode") { - runJs( - """ - importClass(com.intellij.ide.PowerSaveMode) - importClass(com.intellij.openapi.application.ApplicationManager) - importClass(com.intellij.openapi.application.ModalityState) + val runResult = runCatching { + runJs( + """ + importClass(com.intellij.ide.PowerSaveMode) + importClass(com.intellij.openapi.application.ApplicationManager) + importClass(com.intellij.openapi.application.ModalityState) + + const disableIt = new Runnable({ + run: function() { + PowerSaveMode.setEnabled(false) + } + }) - const disableIt = new Runnable({ - run: function() { - PowerSaveMode.setEnabled(false) - } - }) - - ApplicationManager.getApplication().invokeLater(disableIt, ModalityState.current()) - """.trimIndent(), - runInEdt = true, - ) + ApplicationManager.getApplication().invokeLater(disableIt, ModalityState.current()) + """.trimIndent(), + runInEdt = true, + ) + } + + if (runResult.isFailure) { + if (runResult.exceptionOrNull()?.message?.contains("Write-unsafe context") != + true + ) { + throw runResult.exceptionOrNull()!! + } + } } CommonSteps(remoteRobot).wait(1) } @@ -219,33 +240,43 @@ class IdeaFrame( fun closeAllFiles() { step("Closing all files") { - runJs( - """ - importPackage(com.intellij.openapi.fileEditor) - importPackage(com.intellij.openapi.vfs) - importPackage(com.intellij.openapi.wm.impl) - importClass(com.intellij.openapi.application.ApplicationManager) - importClass(com.intellij.openapi.application.ModalityState) - - const frameHelper = ProjectFrameHelper.getFrameHelper(component) - if (frameHelper) { - const project = frameHelper.getProject() - const closeEditorsFunction = new Runnable({ - run: function() { - const editorManager = FileEditorManager.getInstance(project) - const files = editorManager.openFiles - files.forEach((file) => { editorManager.closeFile(file) }) + val runResult = runCatching { + runJs( + """ + importPackage(com.intellij.openapi.fileEditor) + importPackage(com.intellij.openapi.vfs) + importPackage(com.intellij.openapi.wm.impl) + importClass(com.intellij.openapi.application.ApplicationManager) + importClass(com.intellij.openapi.application.ModalityState) + + const frameHelper = ProjectFrameHelper.getFrameHelper(component) + if (frameHelper) { + const project = frameHelper.getProject() + const closeEditorsFunction = new Runnable({ + run: function() { + const editorManager = FileEditorManager.getInstance(project) + const files = editorManager.openFiles + files.forEach((file) => { editorManager.closeFile(file) }) + } + }) + + ApplicationManager.getApplication().invokeLater( + closeEditorsFunction, + ModalityState.current() + ) } - }) - - ApplicationManager.getApplication().invokeLater( - closeEditorsFunction, - ModalityState.current() + """, + true, ) } - """, - true, - ) + + if (runResult.isFailure) { + if (runResult.exceptionOrNull()?.message?.contains("Write-unsafe context") != + true + ) { + throw runResult.exceptionOrNull()!! + } + } } CommonSteps(remoteRobot).wait(1) } From a0df2e2e0fe036c2b0fad0169c44959a04b32a2d Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 16:35:51 +0200 Subject: [PATCH 40/41] chore: bring back old clean data source with catch for write-unsafe-errors --- .../impl/MongoDbRunQueryActionUiTest.kt | 7 +--- .../JavaDriverToolbarVisibilityUiTest.kt | 7 +--- .../fixtures/components/idea/IdeaFrame.kt | 37 +++++++++++++++++++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt index fdddd93f7..76c4b8f64 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/codeActions/impl/MongoDbRunQueryActionUiTest.kt @@ -3,7 +3,6 @@ package com.mongodb.jbplugin.codeActions.impl import com.intellij.remoterobot.RemoteRobot import com.mongodb.jbplugin.fixtures.* import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame -import com.mongodb.jbplugin.fixtures.components.openDatabaseToolWindow import com.mongodb.jbplugin.fixtures.components.openRunQueryPopup import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.* @@ -21,15 +20,13 @@ class MongoDbRunQueryActionUiTest { remoteRobot: RemoteRobot, url: MongoDbServerUrl, ) { - // This is our safety net to ensure we start with a clean slate - remoteRobot.openDatabaseToolWindow().removeAllDataSources() - remoteRobot.closeRightToolWindow() + remoteRobot.ideaFrame().cleanDataSources() remoteRobot.ideaFrame().addDataSourceWithUrl(javaClass.simpleName, url) } @AfterEach fun tearDown(remoteRobot: RemoteRobot) { - remoteRobot.openDatabaseToolWindow().removeAllDataSources() + remoteRobot.ideaFrame().cleanDataSources() } @Test diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt index ad7f1fed0..a88f654e8 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/editor/javaEditor/JavaDriverToolbarVisibilityUiTest.kt @@ -5,7 +5,6 @@ import com.mongodb.jbplugin.fixtures.* import com.mongodb.jbplugin.fixtures.components.findJavaEditorToolbar import com.mongodb.jbplugin.fixtures.components.idea.ideaFrame import com.mongodb.jbplugin.fixtures.components.isJavaEditorToolbarHidden -import com.mongodb.jbplugin.fixtures.components.openDatabaseToolWindow import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach @@ -21,15 +20,13 @@ class JavaDriverToolbarVisibilityUiTest { remoteRobot: RemoteRobot, url: MongoDbServerUrl, ) { - // This is our safety net to ensure we start with a clean slate - remoteRobot.openDatabaseToolWindow().removeAllDataSources() - remoteRobot.closeRightToolWindow() + remoteRobot.ideaFrame().cleanDataSources() remoteRobot.ideaFrame().addDataSourceWithUrl(javaClass.simpleName, url) } @AfterEach fun tearDown(remoteRobot: RemoteRobot) { - remoteRobot.openDatabaseToolWindow().removeAllDataSources() + remoteRobot.ideaFrame().cleanDataSources() } @Test diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt index 4a74d5dd2..f5fa41080 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/idea/IdeaFrame.kt @@ -158,6 +158,43 @@ class IdeaFrame( CommonSteps(remoteRobot).wait(1) } + fun cleanDataSources() { + step("Removing all data sources") { + val runResult = runCatching { + runJs( + """ + const LocalDataSourceManager = global.get('loadDataGripPluginClass')( + 'com.intellij.database.dataSource.LocalDataSourceManager' + ) + importClass(java.lang.System) + importClass(com.intellij.openapi.project.Project) + importClass(com.intellij.openapi.util.Key) + importPackage(com.intellij.openapi.progress) + importPackage(com.intellij.openapi.wm.impl) + importPackage(com.intellij.database.view.ui) + importClass(com.intellij.openapi.application.ApplicationManager) + + const frameHelper = ProjectFrameHelper.getFrameHelper(component) + const project = frameHelper.getProject() + const dataSourceManager = LocalDataSourceManager.getMethod("getInstance", Project).invoke(null, project) + const dataSources = dataSourceManager.getDataSources(); + for (let i = 0; i < dataSources.size(); i++) { + dataSourceManager.removeDataSource(dataSources.get(i)); + } + """.trimIndent(), + runInEdt = true, + ) + } + if (runResult.isFailure) { + if (runResult.exceptionOrNull()?.message?.contains("Write-unsafe context") != + true + ) { + throw runResult.exceptionOrNull()!! + } + } + } + } + fun disablePowerSaveMode() { step("Disable Power Save Mode") { val runResult = runCatching { From 25220c54877872fd14d146b855cd30476ee28d13 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 23 Oct 2024 17:26:10 +0200 Subject: [PATCH 41/41] chore: bring back maybeTerminateButton call --- .../jbplugin/fixtures/FixtureExtensions.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/FixtureExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/FixtureExtensions.kt index 984a5ed2b..9d98bcc28 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/FixtureExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/FixtureExtensions.kt @@ -7,13 +7,17 @@ package com.mongodb.jbplugin.fixtures import com.intellij.remoterobot.RemoteRobot import com.intellij.remoterobot.fixtures.Fixture +import com.intellij.remoterobot.fixtures.JButtonFixture import com.intellij.remoterobot.search.locators.Locator +import com.intellij.remoterobot.search.locators.byXpath import com.intellij.remoterobot.stepsProcessing.step import com.intellij.remoterobot.utils.waitFor import com.mongodb.jbplugin.fixtures.components.idea.maybeIdeaFrame import org.owasp.encoder.Encode import java.time.Duration import java.util.concurrent.atomic.AtomicReference +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.toJavaDuration /** * Returns a fixture by the default xpath of the fixture. @@ -161,7 +165,9 @@ fun RemoteRobot.openProject(absolutePath: String) = step("Open Project at path $ """, ) + maybeTerminateButton() maybeIdeaFrame()?.closeAllFiles() + maybeTerminateButton() } /** @@ -169,4 +175,16 @@ fun RemoteRobot.openProject(absolutePath: String) = step("Open Project at path $ */ fun RemoteRobot.closeProject() = step("Closing any open project") { invokeAction("CloseProject") + maybeTerminateButton() +} + +private fun RemoteRobot.maybeTerminateButton() { + runCatching { + val terminateButton = + find( + byXpath("//div[@text='Terminate']"), + timeout = 50.milliseconds.toJavaDuration(), + ) + terminateButton.click() + }.getOrDefault(Unit) }