diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/EditorFixture.java b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/EditorFixture.java index 1f12e433c6cc..890b13d388e0 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/EditorFixture.java +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/EditorFixture.java @@ -22,6 +22,8 @@ import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.testGuiFramework.framework.GuiTestUtil; +import com.intellij.testGuiFramework.impl.ComponentFixtureUtilsKt; +import com.intellij.testGuiFramework.util.Predicate; import org.fest.swing.core.ComponentDragAndDrop; import org.fest.swing.core.GenericTypeMatcher; import org.fest.swing.core.MouseButton; @@ -126,7 +128,7 @@ public class EditorFixture { * file open. * * @param trim if true, trim whitespace around the line - * @param caret typically "^" which will insert "^" to indicate the + * @param caret typically "^" which will insert "^" to indicate the * caret position. If null, the caret position is not shown. * @param selectBegin the text string to insert at the beginning of the selection boundary * @param selectEnd the text string to insert at the end of the selection boundary @@ -228,7 +230,7 @@ public class EditorFixture { * Returns the contents of the current file, or null if there is no * file open. * - * @param caret typically "^" which will insert "^" to indicate the + * @param caret typically "^" which will insert "^" to indicate the * caret position. If null, the caret position is not shown. * @param selectBegin the text string to insert at the beginning of the selection boundary * @param selectEnd the text string to insert at the end of the selection boundary @@ -773,7 +775,9 @@ public class EditorFixture { @NotNull public EditorFixture invokeIntentionAction(@NotNull String labelPrefix) { invokeAction(EditorFixture.EditorAction.SHOW_INTENTION_ACTIONS); - JBListPopupFixture.Companion.clickPopupMenuItem(labelPrefix, true, null, robot, GuiTestUtil.INSTANCE.getSHORT_TIMEOUT()); + ComponentFixtureUtilsKt + .popupMenu(labelPrefix, robot, null, GuiTestUtil.INSTANCE.getSHORT_TIMEOUT(), Predicate.INSTANCE.getEquality()) + .clickSearchedItem(); return this; } diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.kt index 34f1e33e83f0..6c879f701ea7 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.kt @@ -1,152 +1,57 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.testGuiFramework.fixtures -import com.intellij.openapi.util.Pair -import com.intellij.openapi.util.Ref -import com.intellij.openapi.util.component1 -import com.intellij.openapi.util.component2 import com.intellij.testGuiFramework.cellReader.ExtendedJListCellReader -import com.intellij.testGuiFramework.framework.GuiTestUtil -import com.intellij.testGuiFramework.framework.GuiTestUtil.waitUntilFound +import com.intellij.testGuiFramework.util.FinderPredicate import com.intellij.ui.components.JBList -import com.intellij.ui.popup.list.ListPopupModel -import org.fest.swing.core.GenericTypeMatcher +import com.intellij.ui.popup.PopupFactoryImpl import org.fest.swing.core.Robot -import org.fest.swing.exception.ComponentLookupException -import org.fest.swing.exception.WaitTimedOutError import org.fest.swing.fixture.JListFixture -import org.fest.swing.timing.Timeout -import org.hamcrest.BaseMatcher -import org.hamcrest.Description -import org.hamcrest.Matcher -import org.junit.Assert.assertNotNull -import java.awt.Component -import java.awt.Container -class JBListPopupFixture private constructor(jbList: JBList<*>, robot: Robot) : JComponentFixture>( +class JBListPopupFixture( + jbList: JBList<*>, + private val searchedItem: String, + private val predicate: FinderPredicate, + robot: Robot) : JComponentFixture>( JBListPopupFixture::class.java, robot, jbList) { - private class PrefixMatcher(private val prefix: String) : BaseMatcher() { + private val jListFixture = JListFixture(robot, jbList) - override fun matches(item: Any): Boolean { - return item is String && item.startsWith(prefix) - } - - override fun describeTo(description: Description) { - description.appendText("with prefix '$prefix'") - } + init { + jListFixture.replaceCellReader(ExtendedJListCellReader()) } - private class EqualsMatcher(private val wanted: String) : BaseMatcher() { - - override fun matches(item: Any): Boolean { - return item is String && item == wanted - } - - override fun describeTo(description: Description) { - description.appendText("equals to '$wanted'") - } + fun clickSearchedItem(){ + jListFixture.clickItem(searchedItem) } - companion object { - - /** - * Clicks an IntelliJ/Studio popup menu item with the label prefix - * - * @param label the target menu item label prefix - * @param searchByPrefix if false equality is checked, if true prefix is checked - * @param component a component in the same window that the popup menu is associated with - * @param robot the robot to drive it with - */ - fun clickPopupMenuItem(label: String, - searchByPrefix: Boolean, - component: Component?, - robot: Robot, - timeout: Timeout) { - val matcher = if (searchByPrefix) PrefixMatcher(label) else EqualsMatcher(label) - clickPopupMenuItemMatching(matcher, component, robot, timeout) - } - - fun getJListFixtureAndItemToClick(label: String, - searchByPrefix: Boolean, - container: Component?, - robot: Robot, - timeout: Timeout): Pair { - val matcher = if (searchByPrefix) PrefixMatcher(label) else EqualsMatcher(label) - return getJListFixtureAndClickableItemByMatcher(container as Container?, matcher, robot, timeout) - } - - private fun clickPopupMenuItemMatching(labelMatcher: Matcher, - component: Component?, - robot: Robot, - timeout: Timeout) { - // IntelliJ doesn't seem to use a normal JPopupMenu, so this won't work: - // JPopupMenu menu = myRobot.findActivePopupMenu(); - // Instead, it uses a JList (technically a JBList), which is placed somewhere - // under the root pane. - var root: Container? = null - if (component != null) { - root = GuiTestUtil.getRootContainer(component) - assertNotNull(root) - } - - val fixtureAndClickableItemPair = getJListFixtureAndClickableItemByMatcher(root, labelMatcher, robot, timeout) - val (popupListFixture, clickableItem) = fixtureAndClickableItemPair - popupListFixture.replaceCellReader(ExtendedJListCellReader()) - popupListFixture.clickItem(clickableItem) - } - - - private fun getJListFixtureAndClickableItemByMatcher(root: Container?, - labelMatcher: Matcher, - robot: Robot, - timeout: Timeout): Pair { - val fixtureAndClickableItemRef = Ref>() - try { - waitUntilFound>(robot, root, object : GenericTypeMatcher>(JBList::class.java) { - override fun isMatching(list: JBList<*>): Boolean { - val model = list.model - if (model is ListPopupModel) { - val fixtureAndClickableItem = getJListFixtureAndClickableItemByList(labelMatcher, robot, list) - if (fixtureAndClickableItem != null) { - fixtureAndClickableItemRef.set(fixtureAndClickableItem) - return true - } - } - return false - } - }, timeout) - } catch (e: WaitTimedOutError){ - throw ComponentLookupException("Unable to get JListFixture because: ${e.message}") - } - return fixtureAndClickableItemRef.get() ?: throw ComponentLookupException("Unable to get JListFixture by matcher $labelMatcher") - } - - private fun getJListFixtureAndClickableItemByList(labelMatcher: Matcher, - robot: Robot, - list: JBList<*>): Pair? { - val jListFixture = JListFixture(robot, list) - jListFixture.replaceCellReader(ExtendedJListCellReader()) - val itemCount = jListFixture.target().model.size - return (0 until itemCount) - .firstOrNull { labelMatcher.matches(jListFixture.item(it).value()) } - ?.let { Pair(jListFixture, it) } - } - - + fun clickItem(item: String) { + jListFixture.clickItem(item) } -} + + fun clickItem(index: Int) { + jListFixture.clickItem(index) + } + + fun isSearchedItemEnable(): Boolean = + isItemEnable(itemIndex(searchedItem)) + + fun isItemEnable(index: Int): Boolean { + val item = jListFixture.target().model.getElementAt(index) + return (item as? PopupFactoryImpl.ActionItem)?.isEnabled + ?: throw ClassCastException("Menu item type '${item.javaClass.canonicalName}' cannot be cast to PopupFactoryImpl.ActionItem") + } + + fun isSearchedItemPresent() : Boolean = isItemPresent(searchedItem) + + fun isItemPresent(item: String): Boolean = listItems().any { predicate(it, item) } + + fun itemIndex(item: String): Int = listItems().indexOfFirst { predicate(it, item) } + + fun listItems(): List { + val itemCount = jListFixture.target().model.size + return (0 until itemCount) + .mapNotNull { jListFixture.item(it).value() } + } + +} \ No newline at end of file diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/RunConfigurationListFixture.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/RunConfigurationListFixture.kt index 710ec7170ee6..24afdf7a044d 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/RunConfigurationListFixture.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/RunConfigurationListFixture.kt @@ -3,6 +3,7 @@ package com.intellij.testGuiFramework.fixtures import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl import com.intellij.testGuiFramework.framework.GuiTestUtil +import com.intellij.testGuiFramework.impl.popupMenu import com.intellij.ui.popup.PopupFactoryImpl import org.fest.swing.core.Robot import org.fest.swing.exception.ComponentLookupException @@ -42,7 +43,7 @@ class RunConfigurationListFixture(val myRobot: Robot, val myIde: IdeFrameFixture */ fun configuration(name: String): RunActionFixture { showPopup() - JBListPopupFixture.clickPopupMenuItem(name, false, null, myRobot, GuiTestUtil.SHORT_TIMEOUT) + myIde.popupMenu(name, GuiTestUtil.SHORT_TIMEOUT).clickSearchedItem() return RunActionFixture() } @@ -62,7 +63,7 @@ class RunConfigurationListFixture(val myRobot: Robot, val myIde: IdeFrameFixture //Close popup showPopup() } - JBListPopupFixture.clickPopupMenuItem(EDIT_CONFIGURATIONS, false, null, myRobot, GuiTestUtil.THIRTY_SEC_TIMEOUT) + myIde.popupMenu(EDIT_CONFIGURATIONS, GuiTestUtil.SHORT_TIMEOUT).clickSearchedItem() } diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/ComponentFixtureUtils.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/ComponentFixtureUtils.kt index 2e1ced569308..b3a5f9ef6bc4 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/ComponentFixtureUtils.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/ComponentFixtureUtils.kt @@ -16,15 +16,19 @@ import com.intellij.testGuiFramework.util.Predicate import com.intellij.ui.CheckboxTree import com.intellij.ui.HyperlinkLabel import com.intellij.ui.components.JBLabel +import com.intellij.ui.components.JBList import com.intellij.ui.components.labels.LinkLabel import com.intellij.ui.treeStructure.treetable.TreeTable import com.intellij.util.ui.AsyncProcessIcon +import org.fest.swing.core.GenericTypeMatcher +import org.fest.swing.core.Robot import org.fest.swing.exception.ComponentLookupException import org.fest.swing.fixture.JLabelFixture import org.fest.swing.fixture.JListFixture import org.fest.swing.fixture.JSpinnerFixture import org.fest.swing.fixture.JTextComponentFixture import org.fest.swing.timing.Timeout +import org.junit.Assert import java.awt.Component import java.awt.Container import java.util.concurrent.TimeUnit @@ -315,10 +319,41 @@ fun ComponentFixture.table(cellText: String, timeout: L * @throws ComponentLookupException if component has not been found or timeout exceeded */ fun ComponentFixture.popupClick(itemName: String, timeout: Long = defaultTimeout) = + popupMenu(itemName, timeout = timeout.toFestTimeout()).clickSearchedItem() + +fun popupMenu( + item: String, + robot: Robot, + root: Container? = null, + timeout: Timeout = GuiTestUtil.defaultTimeout.toFestTimeout(), + predicate: FinderPredicate = Predicate.equality +): JBListPopupFixture{ + val jbList = GuiTestUtil.waitUntilFound( + robot, + root, + object : GenericTypeMatcher>(JBList::class.java) { + override fun isMatching(component: JBList<*>): Boolean { + return JBListPopupFixture(component, item, predicate, robot).isSearchedItemPresent() + } + }, + timeout) + return JBListPopupFixture(jbList, item, predicate, robot) + +} + +fun ComponentFixture.popupMenu( + item: String, + timeout: Timeout = GuiTestUtil.defaultTimeout.toFestTimeout(), + predicate: FinderPredicate = Predicate.equality +): JBListPopupFixture { if (target() is Container) { - JBListPopupFixture.clickPopupMenuItem(itemName, false, target() as Container, robot(), timeout.toFestTimeout()) + val root: Container? = GuiTestUtil.getRootContainer(target()) + Assert.assertNotNull(root) + return popupMenu(item, robot(), root, timeout, predicate) } - else throw unableToFindComponent("Popup") + else throw unableToFindComponent("JBList with item '${item}' not found") +} + /** * Finds a LinkLabel component in hierarchy of context component by a link name and returns fixture for it. diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/util/scenarios/RunConfigurationScenarios.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/util/scenarios/RunConfigurationScenarios.kt index 44fd2f4d9086..7e29a3ee589d 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/util/scenarios/RunConfigurationScenarios.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/util/scenarios/RunConfigurationScenarios.kt @@ -1,9 +1,9 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.testGuiFramework.util.scenarios -import com.intellij.testGuiFramework.impl.GuiTestCase -import com.intellij.testGuiFramework.impl.button -import com.intellij.testGuiFramework.impl.popupClick +import com.intellij.testGuiFramework.framework.GuiTestUtil +import com.intellij.testGuiFramework.impl.* +import com.intellij.testGuiFramework.util.Key import com.intellij.testGuiFramework.util.logTestStep import com.intellij.testGuiFramework.utils.TestUtilsClass import com.intellij.testGuiFramework.utils.TestUtilsClassCompanion @@ -27,9 +27,13 @@ fun RunConfigurationScenarios.openRunConfiguration(vararg configuration: String) logTestStep("Going to check presence of run/debug configuration `$configurationName`") navigationBar { assert(exists { button(configurationName) }) { "Button `$configurationName` not found on Navigation bar" } - button(configurationName).click() - popupClick(RunConfigurationScenarios.Constants.editConfigurationMenuItem) } + GuiTestUtilKt.waitUntil("Menu item '${RunConfigurationScenarios.Constants.editConfigurationMenuItem}' is enabled", GuiTestUtil.LONG_TIMEOUT.duration().toInt()){ + shortcut(Key.ESCAPE) + button(configurationName).click() + popupMenu(RunConfigurationScenarios.Constants.editConfigurationMenuItem, GuiTestUtil.NO_TIMEOUT).isSearchedItemEnable() + } + popupMenu(RunConfigurationScenarios.Constants.editConfigurationMenuItem).clickSearchedItem() } } }