From 1d7f4e9c6a37f158fe71d7f5495a187386b5e300 Mon Sep 17 00:00:00 2001 From: Sergey Karashevich Date: Wed, 24 Jan 2018 17:04:57 +0300 Subject: [PATCH] [gui-test] fix TypeAheadTest when Edit Configurations is disabled fix TypeAheadTest when Edit Configurations... action is disabled. --- .../tests/community/TypeAheadTest.kt | 22 ++- .../fixtures/EditorFixture.java | 2 +- .../fixtures/JBListPopupFixture.java | 175 ------------------ .../fixtures/JBListPopupFixture.kt | 147 +++++++++++++++ 4 files changed, 169 insertions(+), 177 deletions(-) delete mode 100644 platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.java create mode 100644 platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.kt diff --git a/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/TypeAheadTest.kt b/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/TypeAheadTest.kt index 25a85a560736..8e3b00217970 100644 --- a/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/TypeAheadTest.kt +++ b/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/TypeAheadTest.kt @@ -1,14 +1,20 @@ // 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.tests.community +import com.intellij.openapi.util.component1 +import com.intellij.openapi.util.component2 import com.intellij.testGuiFramework.fixtures.IdeFrameFixture +import com.intellij.testGuiFramework.fixtures.JBListPopupFixture import com.intellij.testGuiFramework.fixtures.JDialogFixture import com.intellij.testGuiFramework.framework.RunWithIde import com.intellij.testGuiFramework.impl.GuiTestCase import com.intellij.testGuiFramework.impl.GuiTestUtilKt import com.intellij.testGuiFramework.launcher.ide.CommunityIde +import com.intellij.ui.popup.PopupFactoryImpl import org.fest.swing.timing.Pause +import org.fest.swing.timing.Timeout import org.junit.Test +import java.util.concurrent.TimeUnit @RunWithIde(CommunityIde::class) class TypeAheadTest : GuiTestCase() { @@ -61,12 +67,26 @@ class TypeAheadTest : GuiTestCase() { } private fun IdeFrameFixture.openRunDebugConfiguration() { + val attempts = 5 + val timeoutInterval = 2L navigationBar { if (!isShowing()) show() actionButton("Run").waitUntilEnabledAndShowing() - button("Main").click() + for (i in 0..attempts) { + button("Main").click() + if (ensureEditConfigurationsIsEnabled()) break; + else if (i == attempts - 1) throw Exception("Action 'Edit Configurations' is still disabled") + Pause.pause(timeoutInterval, TimeUnit.SECONDS) + } popupClick("Edit Configurations...") } } + private fun IdeFrameFixture.ensureEditConfigurationsIsEnabled(): Boolean { + val (jListFixture, index) = JBListPopupFixture.getJListFixtureAndItemToClick("Edit Configurations...", false, null, this.robot(), + Timeout.timeout(1000)) + val actionItem = jListFixture.target().model.getElementAt(index) as PopupFactoryImpl.ActionItem + return actionItem.action.templatePresentation.isEnabled + } + } \ No newline at end of file diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/EditorFixture.java b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/EditorFixture.java index b9c6d7b76c22..69525af891a0 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/EditorFixture.java +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/EditorFixture.java @@ -818,7 +818,7 @@ public class EditorFixture { @NotNull public EditorFixture invokeIntentionAction(@NotNull String labelPrefix) { invokeAction(EditorFixture.EditorAction.SHOW_INTENTION_ACTIONS); - JBListPopupFixture.clickPopupMenuItem(labelPrefix, true, null, robot, SHORT_TIMEOUT); + JBListPopupFixture.Companion.clickPopupMenuItem(labelPrefix, true, null, robot, SHORT_TIMEOUT); return this; } diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.java b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.java deleted file mode 100644 index ecc90e84d84d..000000000000 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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. - */ -package com.intellij.testGuiFramework.fixtures; - -import com.intellij.execution.configurations.ConfigurationTypeBase; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Ref; -import com.intellij.testGuiFramework.cellReader.ExtendedJListCellReader; -import com.intellij.testGuiFramework.framework.GuiTestUtil; -import com.intellij.ui.components.JBList; -import com.intellij.ui.popup.PopupFactoryImpl; -import com.intellij.ui.popup.list.ListPopupModel; -import org.fest.swing.core.GenericTypeMatcher; -import org.fest.swing.core.Robot; -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.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; - -import static com.intellij.testGuiFramework.framework.GuiTestUtil.waitUntilFound; -import static org.junit.Assert.assertNotNull; - -public class JBListPopupFixture extends JComponentFixture { - - private JBListPopupFixture(JBList jbList, Robot robot) { - super(JBListPopupFixture.class, robot, jbList); - } - - /** - * 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 - */ - public static void clickPopupMenuItem(@NotNull String label, - boolean searchByPrefix, - @Nullable Component component, - @NotNull Robot robot, - @NotNull Timeout timeout) { - if (searchByPrefix) { - clickPopupMenuItemMatching(new PrefixMatcher(label), component, robot, timeout); - } - else { - clickPopupMenuItemMatching(new EqualsMatcher(label), component, robot, timeout); - } - } - - private static void clickPopupMenuItemMatching(@NotNull Matcher labelMatcher, - @Nullable Component component, - @NotNull Robot robot, - @NotNull 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. - Container root = null; - if (component != null) { - root = GuiTestUtil.getRootContainer(component); - assertNotNull(root); - } - - Ref> fixtureAndClickableItemRef = new Ref<>(); - // First find the JBList which holds the popup. There could be other JBLists in the hierarchy, - // so limit it to one that is actually used as a popup, as identified by its model being a ListPopupModel: - waitUntilFound(robot, root, new GenericTypeMatcher(JBList.class) { - @Override - protected boolean isMatching(@NotNull JBList list) { - ListModel model = list.getModel(); - if (model instanceof ListPopupModel) { - Pair fixtureAndClickableItem = getJListFixtureAndClickableItem(labelMatcher, robot, list); - if (fixtureAndClickableItem != null) { - fixtureAndClickableItemRef.set(fixtureAndClickableItem); - return true; - } - } - return false; - } - }, timeout); - - Pair fixtureAndClickableItemPair = fixtureAndClickableItemRef.get(); - JListFixture popupListFixture = fixtureAndClickableItemPair.first; - popupListFixture.replaceCellReader(new ExtendedJListCellReader()); - int clickableItem = fixtureAndClickableItemPair.second; - popupListFixture.clickItem(clickableItem); - } - - @Nullable - private static Pair getJListFixtureAndClickableItem(@NotNull Matcher labelMatcher, - @NotNull Robot robot, - JBList list) { - JListFixture jListFixture = new JListFixture(robot, list); - jListFixture.replaceCellReader(new ExtendedJListCellReader()); - int itemCount = jListFixture.target().getModel().getSize(); - for (int i = 0; i < itemCount; i++) { - if (labelMatcher.matches(jListFixture.item(i).value())) { - return new Pair<>(jListFixture, i); - } - } - return null; - } - - @NotNull - private static String readPopupItem(ListPopupModel model, int itemNumber) { - assert itemNumber < model.getSize(); - Object elementAt = model.getElementAt(itemNumber); - if (elementAt instanceof PopupFactoryImpl.ActionItem) { - return ((PopupFactoryImpl.ActionItem)elementAt).getText(); - } - else if (elementAt instanceof ConfigurationTypeBase) { - return ((ConfigurationTypeBase)elementAt).getDisplayName(); - } - else { // For example package private class IntentionActionWithTextCaching used in quickfix popups - return elementAt.toString(); - } - } - - private static class PrefixMatcher extends BaseMatcher { - - private final String prefix; - - public PrefixMatcher(String prefix) { - this.prefix = prefix; - } - - @Override - public boolean matches(Object item) { - return item instanceof String && ((String)item).startsWith(prefix); - } - - @Override - public void describeTo(Description description) { - description.appendText("with prefix '" + prefix + "'"); - } - } - - private static class EqualsMatcher extends BaseMatcher { - - private final String wanted; - - public EqualsMatcher(String wanted) { - this.wanted = wanted; - } - - @Override - public boolean matches(Object item) { - return item instanceof String && item.equals(wanted); - } - - @Override - public void describeTo(Description description) { - description.appendText("equals to '" + wanted + "'"); - } - } -} diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.kt new file mode 100644 index 000000000000..1e07711417f6 --- /dev/null +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/JBListPopupFixture.kt @@ -0,0 +1,147 @@ +/* + * 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. + */ +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.ui.components.JBList +import com.intellij.ui.popup.list.ListPopupModel +import org.fest.swing.core.GenericTypeMatcher +import org.fest.swing.core.Robot +import org.fest.swing.exception.ComponentLookupException +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>( + JBListPopupFixture::class.java, robot, jbList) { + + private class PrefixMatcher(private val prefix: String) : BaseMatcher() { + + override fun matches(item: Any): Boolean { + return item is String && item.startsWith(prefix) + } + + override fun describeTo(description: Description) { + description.appendText("with prefix '$prefix'") + } + } + + 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'") + } + } + + 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>() + 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) + 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) } + } + + + } +}