[UI Tests] Fixed bug where tests could not click menus nested in more than one level.
Change-Id: Ib983dbed2549caf7794a7ec197196ae72c165589
diff --git a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/EditorFixture.java b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/EditorFixture.java
index 1d536ea..7f00216 100644
--- a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/EditorFixture.java
+++ b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/EditorFixture.java
@@ -917,8 +917,7 @@
}
});
if (visible == null || !visible) {
- // This doesn't work; second nested menu item isn't clicked
- //myFrame.invokeMenuPath("View", "Tool Windows", "Preview");
+ myFrame.invokeMenuPath("View", "Tool Windows", "Preview");
}
pause(new Condition("Preview window is visible") {
diff --git a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/IdeFrameFixture.java b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/IdeFrameFixture.java
index 39468ee..96fd398 100644
--- a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/IdeFrameFixture.java
+++ b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/IdeFrameFixture.java
@@ -74,7 +74,6 @@
import javax.swing.*;
import java.awt.*;
import java.io.File;
-import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -438,8 +437,7 @@
* @param path the series of menu names, e.g. {@link invokeActionByMenuPath("Build", "Make Project")}
*/
public void invokeMenuPath(@NotNull String... path) {
- JMenuItem menuItem = findActionMenuItem(path);
- robot().click(menuItem);
+ getMenuFixture().invokeMenuPath(path);
}
/**
@@ -450,37 +448,12 @@
* @param path the series of menu name regular expressions, e.g. {@link invokeActionByMenuPath("Build", "Make( Project)?")}
*/
public void invokeMenuPathRegex(@NotNull String... path) {
- JMenuItem menuItem = findActionMenuItem(true, path);
- robot().click(menuItem);
+ getMenuFixture().invokeMenuPathRegex(path);
}
@NotNull
- private JMenuItem findActionMenuItem(@NotNull String... path) {
- return findActionMenuItem(false, path);
- }
-
- @NotNull
- private JMenuItem findActionMenuItem(final boolean pathIsRegex, @NotNull String... path) {
- assertThat(path).isNotEmpty();
- int segmentCount = path.length;
- Container root = target();
- for (int i = 0; i < segmentCount; i++) {
- final String segment = path[i];
- assertNotNull(root);
- JMenuItem found = robot().finder().find(root, new GenericTypeMatcher<JMenuItem>(JMenuItem.class) {
- @Override
- protected boolean isMatching(@NotNull JMenuItem menuItem) {
- return pathIsRegex ? menuItem.getText().matches(segment) : segment.equals(menuItem.getText());
- }
- });
- if (i < segmentCount - 1) {
- robot().click(found);
- root = robot().findActivePopupMenu();
- continue;
- }
- return found;
- }
- throw new AssertionError("Menu item with path " + Arrays.toString(path) + " should have been found already");
+ private MenuFixture getMenuFixture() {
+ return new MenuFixture(robot(), target());
}
@NotNull
diff --git a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/MenuFixture.java b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/MenuFixture.java
new file mode 100644
index 0000000..6114e18
--- /dev/null
+++ b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/MenuFixture.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.android.tools.idea.tests.gui.framework.fixture;
+
+import com.google.common.collect.Lists;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.wm.impl.IdeFrameImpl;
+import org.fest.swing.core.GenericTypeMatcher;
+import org.fest.swing.core.Robot;
+import org.fest.swing.timing.Condition;
+import org.fest.swing.timing.Pause;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.util.Lists.newArrayList;
+import static org.junit.Assert.assertNotNull;
+
+class MenuFixture {
+ @NotNull private final Robot myRobot;
+ @NotNull private final IdeFrameImpl myContainer;
+
+ MenuFixture(@NotNull Robot robot, @NotNull IdeFrameImpl container) {
+ myRobot = robot;
+ myContainer = container;
+ }
+
+ /**
+ * Invokes an action by menu path
+ *
+ * @param path the series of menu names, e.g. {@link invokeActionByMenuPath("Build", "Make Project ")}
+ */
+ void invokeMenuPath(@NotNull String... path) {
+ JMenuItem menuItem = findActionMenuItem(false, path);
+ myRobot.click(menuItem);
+ }
+
+ /**
+ * Invokes an action by menu path (where each segment is a regular expression). This is particularly
+ * useful when the menu items can change dynamically, such as the labels of Undo actions, Run actions,
+ * etc.
+ *
+ * @param path the series of menu name regular expressions, e.g. {@link invokeActionByMenuPath("Build", "Make( Project)?")}
+ */
+ void invokeMenuPathRegex(@NotNull String... path) {
+ JMenuItem menuItem = findActionMenuItem(true, path);
+ myRobot.click(menuItem);
+ }
+
+ @NotNull
+ private JMenuItem findActionMenuItem(final boolean pathIsRegex, @NotNull String... path) {
+ assertThat(path).isNotEmpty();
+ int segmentCount = path.length;
+
+ // We keep the list of previously found pop-up menus, so we don't look for menu items in the same pop-up more than once.
+ List<JPopupMenu> previouslyFoundPopups = Lists.newArrayList();
+
+ Container root = myContainer;
+ for (int i = 0; i < segmentCount; i++) {
+ final String segment = path[i];
+ assertNotNull(root);
+ JMenuItem found = myRobot.finder().find(root, new GenericTypeMatcher<JMenuItem>(JMenuItem.class) {
+ @Override
+ protected boolean isMatching(@NotNull JMenuItem menuItem) {
+ return pathIsRegex ? menuItem.getText().matches(segment) : segment.equals(menuItem.getText());
+ }
+ });
+ if (root instanceof JPopupMenu) {
+ previouslyFoundPopups.add((JPopupMenu)root);
+ }
+ if (i < segmentCount - 1) {
+ myRobot.click(found);
+ List<JPopupMenu> showingPopupMenus = findShowingPopupMenus(i + 1);
+ showingPopupMenus.removeAll(previouslyFoundPopups);
+ assertThat(showingPopupMenus).hasSize(1);
+ root = showingPopupMenus.get(0);
+ continue;
+ }
+ return found;
+ }
+ throw new AssertionError("Menu item with path " + Arrays.toString(path) + " should have been found already");
+ }
+
+ @NotNull
+ private List<JPopupMenu> findShowingPopupMenus(final int expectedCount) {
+ final Ref<List<JPopupMenu>> ref = new Ref<List<JPopupMenu>>();
+ Pause.pause(new Condition("waiting for " + expectedCount + " JPopupMenus to show up") {
+ @Override
+ public boolean test() {
+ List<JPopupMenu> popupMenus = newArrayList(myRobot.finder().findAll(new GenericTypeMatcher<JPopupMenu>(JPopupMenu.class) {
+ @Override
+ protected boolean isMatching(@NotNull JPopupMenu popupMenu) {
+ return popupMenu.isShowing();
+ }
+ }));
+ boolean allFound = popupMenus.size() == expectedCount;
+ if (allFound) {
+ ref.set(popupMenus);
+ }
+ return allFound;
+ }
+ });
+ List<JPopupMenu> popupMenus = ref.get();
+ assertThat(popupMenus).isNotNull().hasSize(expectedCount);
+ return popupMenus;
+ }
+}