[gui-test] fix TypeAheadTest when Edit Configurations is disabled

fix TypeAheadTest when Edit Configurations... action is disabled.
This commit is contained in:
Sergey Karashevich
2018-01-24 23:25:49 +03:00
parent 60db9a971d
commit 1d7f4e9c6a
4 changed files with 169 additions and 177 deletions
@@ -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
}
}
@@ -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;
}
@@ -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<JBListPopupFixture, JBList> {
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<String> 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<Pair<JListFixture, Integer>> 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>(JBList.class) {
@Override
protected boolean isMatching(@NotNull JBList list) {
ListModel model = list.getModel();
if (model instanceof ListPopupModel) {
Pair<JListFixture, Integer> fixtureAndClickableItem = getJListFixtureAndClickableItem(labelMatcher, robot, list);
if (fixtureAndClickableItem != null) {
fixtureAndClickableItemRef.set(fixtureAndClickableItem);
return true;
}
}
return false;
}
}, timeout);
Pair<JListFixture, Integer> fixtureAndClickableItemPair = fixtureAndClickableItemRef.get();
JListFixture popupListFixture = fixtureAndClickableItemPair.first;
popupListFixture.replaceCellReader(new ExtendedJListCellReader());
int clickableItem = fixtureAndClickableItemPair.second;
popupListFixture.clickItem(clickableItem);
}
@Nullable
private static Pair<JListFixture, Integer> getJListFixtureAndClickableItem(@NotNull Matcher<String> 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<String> {
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<String> {
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 + "'");
}
}
}
@@ -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, JBList<*>>(
JBListPopupFixture::class.java, robot, jbList) {
private class PrefixMatcher(private val prefix: String) : BaseMatcher<String>() {
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<String>() {
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<JListFixture, Int> {
val matcher = if (searchByPrefix) PrefixMatcher(label) else EqualsMatcher(label)
return getJListFixtureAndClickableItemByMatcher(container as Container?, matcher, robot, timeout)
}
private fun clickPopupMenuItemMatching(labelMatcher: Matcher<String>,
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<String>,
robot: Robot,
timeout: Timeout): Pair<JListFixture, Int> {
val fixtureAndClickableItemRef = Ref<Pair<JListFixture, Int>>()
waitUntilFound<JBList<*>>(robot, root, object : GenericTypeMatcher<JBList<*>>(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<String>,
robot: Robot,
list: JBList<*>): Pair<JListFixture, Int>? {
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) }
}
}
}